|
1 | 1 | import React, { useState } from "react"; |
2 | 2 | import { motion } from "framer-motion"; |
3 | 3 | import emailjs from "@emailjs/browser"; |
| 4 | +import { FaEnvelope, FaGithub, FaLinkedinIn, FaMapMarkerAlt } from "react-icons/fa"; |
| 5 | +import { profile } from "../data/profile"; |
| 6 | +import PageHeader from "./ui/PageHeader"; |
| 7 | +import SectionPanel from "./ui/SectionPanel"; |
| 8 | +import Badge from "./ui/Badge"; |
4 | 9 | import "../styles/ContactSection.css"; |
5 | 10 |
|
6 | 11 | const ContactSection = () => { |
@@ -72,67 +77,134 @@ const ContactSection = () => { |
72 | 77 | }; |
73 | 78 |
|
74 | 79 | return ( |
75 | | - <section className="contact" id="contact"> |
76 | | - <div className="contact-header"> |
77 | | - <h2 className="contact-title">Let's Work Together</h2> |
78 | | - <p className="contact-subtitle"> |
79 | | - Have a project or idea? I'd love to hear from you. |
80 | | - </p> |
81 | | - </div> |
82 | | - |
83 | | - <form onSubmit={handleSubmit} className="contact-form"> |
84 | | - {["name", "email", "message"].map((field, i) => ( |
85 | | - <motion.div |
86 | | - key={field} |
87 | | - custom={i} |
88 | | - initial="hidden" |
89 | | - animate="visible" |
90 | | - variants={inputVariants} |
91 | | - > |
92 | | - {field !== "message" ? ( |
93 | | - <input |
94 | | - type={field === "email" ? "email" : "text"} |
95 | | - name={field} |
96 | | - placeholder={`Your ${ |
97 | | - field.charAt(0).toUpperCase() + field.slice(1) |
98 | | - }`} |
99 | | - value={formData[field]} |
100 | | - onChange={handleChange} |
101 | | - required |
102 | | - /> |
103 | | - ) : ( |
104 | | - <textarea |
105 | | - name="message" |
106 | | - placeholder="Your Message" |
107 | | - value={formData.message} |
108 | | - onChange={handleChange} |
109 | | - rows="5" |
110 | | - required |
111 | | - ></textarea> |
112 | | - )} |
113 | | - </motion.div> |
114 | | - ))} |
115 | | - |
116 | | - <motion.button |
117 | | - type="submit" |
118 | | - disabled={isSending} |
119 | | - whileHover={{ scale: isSending ? 1 : 1.05 }} |
120 | | - whileTap={{ scale: 0.95 }} |
121 | | - > |
122 | | - {isSending ? "Sending..." : "Send Message"} |
123 | | - </motion.button> |
124 | | - |
125 | | - {status.message && ( |
126 | | - <motion.p |
127 | | - className={`form-status ${status.type}`} |
128 | | - initial={{ opacity: 0 }} |
129 | | - animate={{ opacity: 1 }} |
130 | | - > |
131 | | - {status.message} |
132 | | - </motion.p> |
133 | | - )} |
134 | | - </form> |
135 | | - </section> |
| 80 | + <main className="page-shell"> |
| 81 | + <PageHeader |
| 82 | + eyebrow="Contact" |
| 83 | + title="Let’s build something useful and well-crafted" |
| 84 | + description="For frontend polish, dashboard architecture, portfolio systems, and production-ready React work, this page is designed to make the next step easy." |
| 85 | + align="left" |
| 86 | + /> |
| 87 | + |
| 88 | + <SectionPanel |
| 89 | + eyebrow="Collaboration" |
| 90 | + title="Start a conversation" |
| 91 | + description="Reach out with a feature idea, UI cleanup request, portfolio upgrade, or product concept. I’m most helpful when the work needs both technical structure and visual refinement." |
| 92 | + > |
| 93 | + <div className="contact-layout"> |
| 94 | + <div className="contact-column contact-summary"> |
| 95 | + <div className="card-row"> |
| 96 | + <Badge tone="accent">Frontend Systems</Badge> |
| 97 | + <Badge>React + Vite</Badge> |
| 98 | + <Badge tone="success">Available</Badge> |
| 99 | + </div> |
| 100 | + |
| 101 | + <div className="contact-intro"> |
| 102 | + <h3>Best fit engagements</h3> |
| 103 | + <p>Developer portfolios, engineering dashboards, routing cleanup, mobile-first UI refinement, and production-ready frontend/full-stack features.</p> |
| 104 | + </div> |
| 105 | + |
| 106 | + <div className="contact-methods"> |
| 107 | + <a href={`mailto:${profile.email}`} className="contact-method"> |
| 108 | + <FaEnvelope /> |
| 109 | + <div> |
| 110 | + <strong>Email</strong> |
| 111 | + <span>{profile.email}</span> |
| 112 | + </div> |
| 113 | + </a> |
| 114 | + <a href={profile.github} target="_blank" rel="noreferrer" className="contact-method"> |
| 115 | + <FaGithub /> |
| 116 | + <div> |
| 117 | + <strong>GitHub</strong> |
| 118 | + <span>See active builds and coding-journal sync</span> |
| 119 | + </div> |
| 120 | + </a> |
| 121 | + <a href={profile.linkedin} target="_blank" rel="noreferrer" className="contact-method"> |
| 122 | + <FaLinkedinIn /> |
| 123 | + <div> |
| 124 | + <strong>LinkedIn</strong> |
| 125 | + <span>Professional profile and collaboration context</span> |
| 126 | + </div> |
| 127 | + </a> |
| 128 | + <div className="contact-method static"> |
| 129 | + <FaMapMarkerAlt /> |
| 130 | + <div> |
| 131 | + <strong>Location</strong> |
| 132 | + <span>{profile.location}</span> |
| 133 | + </div> |
| 134 | + </div> |
| 135 | + </div> |
| 136 | + |
| 137 | + <div className="contact-trust-grid"> |
| 138 | + <article className="glass-card"> |
| 139 | + <h3>UI/UX Cleanup</h3> |
| 140 | + <p>Turning cluttered flows into clearer, more premium product surfaces.</p> |
| 141 | + </article> |
| 142 | + <article className="glass-card"> |
| 143 | + <h3>Developer Platforms</h3> |
| 144 | + <p>Problems, codebase, analytics, and synced engineering views built around live data.</p> |
| 145 | + </article> |
| 146 | + <article className="glass-card"> |
| 147 | + <h3>Production Mindset</h3> |
| 148 | + <p>Routing, responsive layouts, build safety, and implementation detail all treated seriously.</p> |
| 149 | + </article> |
| 150 | + </div> |
| 151 | + </div> |
| 152 | + |
| 153 | + <div className="contact-column"> |
| 154 | + <form onSubmit={handleSubmit} className="contact-form"> |
| 155 | + {["name", "email", "message"].map((field, i) => ( |
| 156 | + <motion.div |
| 157 | + key={field} |
| 158 | + custom={i} |
| 159 | + initial="hidden" |
| 160 | + animate="visible" |
| 161 | + variants={inputVariants} |
| 162 | + > |
| 163 | + {field !== "message" ? ( |
| 164 | + <input |
| 165 | + type={field === "email" ? "email" : "text"} |
| 166 | + name={field} |
| 167 | + placeholder={`Your ${field.charAt(0).toUpperCase() + field.slice(1)}`} |
| 168 | + value={formData[field]} |
| 169 | + onChange={handleChange} |
| 170 | + required |
| 171 | + /> |
| 172 | + ) : ( |
| 173 | + <textarea |
| 174 | + name="message" |
| 175 | + placeholder="Tell me what you’re building, where it feels stuck, and what kind of help you need." |
| 176 | + value={formData.message} |
| 177 | + onChange={handleChange} |
| 178 | + rows="7" |
| 179 | + required |
| 180 | + ></textarea> |
| 181 | + )} |
| 182 | + </motion.div> |
| 183 | + ))} |
| 184 | + |
| 185 | + <motion.button |
| 186 | + type="submit" |
| 187 | + disabled={isSending} |
| 188 | + whileHover={{ scale: isSending ? 1 : 1.01 }} |
| 189 | + whileTap={{ scale: 0.99 }} |
| 190 | + > |
| 191 | + {isSending ? "Sending..." : "Send Message"} |
| 192 | + </motion.button> |
| 193 | + |
| 194 | + {status.message && ( |
| 195 | + <motion.p |
| 196 | + className={`form-status ${status.type}`} |
| 197 | + initial={{ opacity: 0 }} |
| 198 | + animate={{ opacity: 1 }} |
| 199 | + > |
| 200 | + {status.message} |
| 201 | + </motion.p> |
| 202 | + )} |
| 203 | + </form> |
| 204 | + </div> |
| 205 | + </div> |
| 206 | + </SectionPanel> |
| 207 | + </main> |
136 | 208 | ); |
137 | 209 | }; |
138 | 210 |
|
|
0 commit comments