diff --git a/functions/contact.js b/functions/contact.js new file mode 100644 index 0000000..6061a19 --- /dev/null +++ b/functions/contact.js @@ -0,0 +1,49 @@ +export async function onRequestPost(context) { + try { + const { name, email, subject, message } = await context.request.json(); + + // Validate inputs + if (!name || !email || !subject || !message) { + return new Response( + JSON.stringify({ error: 'All fields are required' }), + { status: 400, headers: { 'Content-Type': 'application/json' } } + ); + } + + // Send email using Resend + const response = await fetch('https://api.resend.com/emails', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${context.env.RESEND_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + from: 'contact@argobox.com', + to: 'daniel.laforce@gmail.com', + subject: `Contact Form: ${subject}`, + html: ` +
Name: ${name}
+Email: ${email}
+Subject: ${subject}
+${message}
+ ` + }) + }); + + if (!response.ok) { + throw new Error('Failed to send email'); + } + + return new Response( + JSON.stringify({ message: 'Message sent successfully!' }), + { status: 200, headers: { 'Content-Type': 'application/json' } } + ); + } catch (error) { + return new Response( + JSON.stringify({ error: 'Failed to send message' }), + { status: 500, headers: { 'Content-Type': 'application/json' } } + ); + } +} \ No newline at end of file diff --git a/index.html b/index.html index c63481a..da582da 100644 --- a/index.html +++ b/index.html @@ -69,27 +69,27 @@A GIS mapping platform used by mining claim prospectors to automate boundary plotting and compliance verification, reducing manual research by 85%.
+Designed and implemented a full-access Wi-Fi testing facility for remote firmware testing of router models, supporting Wave2 and WiFi6 capabilities.
+Custom application for streamlining Kaseya VSA RMM agent installation, reducing deployment time by 80% across dental practice environments.
+Bash script for automating DNS updates with Cloudflare, featuring user input validation, API integration, and cron scheduling.
+Name: ${name}
+Email: ${email}
+Subject: ${subject}
+${message}
+ ` + }; + + // Send email + await transporter.sendMail(mailOptions); + + res.status(200).json({ message: 'Message sent successfully!' }); + } catch (error) { + console.error('Error sending email:', error); + res.status(500).json({ message: 'Failed to send message. Please try again.' }); + } +}); + +app.listen(port, () => { + console.log(`Server running on port ${port}`); +}); \ No newline at end of file diff --git a/styles.css b/styles.css index a374e79..5c2e046 100644 --- a/styles.css +++ b/styles.css @@ -297,45 +297,69 @@ ul { .hero-visual { flex: 1; + min-width: 300px; + max-width: 600px; +} + +.tech-dashboard { + background-color: var(--secondary); + border-radius: 1rem; + overflow: hidden; + border: 1px solid var(--border); + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3); + transform: perspective(1000px) rotateY(-5deg) rotateX(5deg); + transition: all 0.3s ease; +} + +.tech-dashboard:hover { + transform: perspective(1000px) rotateY(0deg) rotateX(0deg); } /* Data Stream Animation */ .data-stream { height: 200px; - background-color: var(--secondary); - border-radius: 0.5rem; + background-color: rgba(15, 23, 42, 0.95); + border-radius: 0.5rem 0.5rem 0 0; position: relative; overflow: hidden; - margin-bottom: 0.5rem; + background-image: + linear-gradient(rgba(59, 130, 246, 0.05) 1px, transparent 1px), + linear-gradient(90deg, rgba(59, 130, 246, 0.05) 1px, transparent 1px); + background-size: 20px 20px; } .data-line { position: absolute; - height: 1px; - background-color: var(--accent); + height: 2px; + background: linear-gradient(90deg, var(--accent), transparent); opacity: 0.5; - animation-name: datastream; - animation-timing-function: linear; - animation-iteration-count: infinite; + transform: translateY(-100%); + will-change: transform; + animation: datastream 3s linear infinite; } @keyframes datastream { - 0% { transform: translateY(-100%); } - 100% { transform: translateY(500%); } + from { transform: translateY(-100%); } + to { transform: translateY(1000%); } } .terminal { - background-color: var(--primary); - border-radius: 0.5rem; + background-color: rgba(15, 23, 42, 0.98); + border-radius: 0 0 0.5rem 0.5rem; padding: 1rem; - font-family: monospace; + font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; } .terminal-line { margin-bottom: 0.5rem; + color: var(--text-muted); } +.terminal-line.success { color: var(--success); } +.terminal-line.warning { color: var(--warning); } +.terminal-line.info { color: var(--info); } + .success { color: var(--success); }