Add contact form and thank-you redirect flow
This commit is contained in:
+170
-1
@@ -491,6 +491,143 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ── Contact ── */
|
||||
.section-contact {
|
||||
background: #090909;
|
||||
border-top: 1px solid rgba(200, 134, 10, 0.18);
|
||||
border-bottom: 1px solid rgba(200, 134, 10, 0.18);
|
||||
padding: 5rem 0;
|
||||
}
|
||||
|
||||
.contact-inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.contact-copy .section-heading {
|
||||
text-align: left;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.contact-copy p {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.7;
|
||||
color: #a89060;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
background: #121212;
|
||||
border: 1px solid rgba(200, 134, 10, 0.22);
|
||||
border-radius: 14px;
|
||||
padding: 1.4rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.95rem;
|
||||
}
|
||||
|
||||
.contact-form label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 0.82rem;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: #c8860a;
|
||||
}
|
||||
|
||||
.contact-form input,
|
||||
.contact-form textarea {
|
||||
background: #0c0c0c;
|
||||
border: 1px solid rgba(200, 134, 10, 0.25);
|
||||
border-radius: 8px;
|
||||
color: #f0e6d0;
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
padding: 0.7rem 0.85rem;
|
||||
outline: none;
|
||||
transition: border-color 200ms;
|
||||
}
|
||||
|
||||
.contact-form input:focus,
|
||||
.contact-form textarea:focus {
|
||||
border-color: rgba(200, 134, 10, 0.7);
|
||||
}
|
||||
|
||||
.contact-form textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.contact-form .btn-primary {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.contact-honeypot {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── Thank You Page ── */
|
||||
.thanks-page {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(ellipse at top, rgba(200, 134, 10, 0.12) 0%, transparent 55%),
|
||||
#0a0a0a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.thanks-card {
|
||||
width: min(720px, 100%);
|
||||
background: #121212;
|
||||
border: 1px solid rgba(200, 134, 10, 0.24);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5);
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.thanks-card h1 {
|
||||
font-family: 'Playfair Display', Georgia, serif;
|
||||
font-size: clamp(2rem, 5vw, 3rem);
|
||||
color: #f0e6d0;
|
||||
margin: 0.3rem 0 1rem;
|
||||
}
|
||||
|
||||
.thanks-card p {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
line-height: 1.7;
|
||||
color: #a89060;
|
||||
margin: 0 0 1rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.thanks-countdown {
|
||||
color: #d4b87a !important;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: 1.3rem !important;
|
||||
}
|
||||
|
||||
.thanks-card .btn-primary {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ── Footer ── */
|
||||
.site-footer {
|
||||
background: #050505;
|
||||
@@ -529,6 +666,28 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.footer-contact {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.08em;
|
||||
color: #d4b87a;
|
||||
margin: 0 0 1.2rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.footer-contact a {
|
||||
color: #f0e6d0;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid rgba(240, 230, 208, 0.4);
|
||||
transition: color 200ms, border-color 200ms;
|
||||
}
|
||||
|
||||
.footer-contact a:hover {
|
||||
color: #c8860a;
|
||||
border-color: rgba(200, 134, 10, 0.8);
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
@@ -1041,6 +1200,15 @@
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.contact-inner {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contact-copy .section-heading {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-ornament {
|
||||
display: none;
|
||||
}
|
||||
@@ -1055,7 +1223,8 @@
|
||||
.section-about,
|
||||
.section-series,
|
||||
.section-guide,
|
||||
.section-qr {
|
||||
.section-qr,
|
||||
.section-contact {
|
||||
padding: 3.5rem 0;
|
||||
}
|
||||
|
||||
|
||||
+78
-1
@@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Routes, Route } from 'react-router-dom'
|
||||
import { Routes, Route, useNavigate } from 'react-router-dom'
|
||||
import AdminPage from './AdminPage'
|
||||
import './App.css'
|
||||
|
||||
@@ -13,6 +13,8 @@ const YOUTUBE_URL = 'https://www.youtube.com/@blackzebraem5558'
|
||||
const AMAZON_MUSIC_URL =
|
||||
'https://music.amazon.com/podcasts/202322bf-db86-4e7d-9a6b-4db7cbccbccf/verse-by-verse-with-nate'
|
||||
const FACEBOOK_URL = 'https://facebook.com/versebyversewithnate'
|
||||
const CONTACT_FORM_ACTION = 'https://formsubmit.co/vbvwithnate@outlook.com'
|
||||
const CONTACT_FORM_NEXT = '/thanks'
|
||||
|
||||
function FacebookIcon() {
|
||||
return (
|
||||
@@ -113,6 +115,7 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
<a href="#listen">Listen</a>
|
||||
<a href="#about">About</a>
|
||||
<a href="#series">Series</a>
|
||||
<a href="#contact">Contact</a>
|
||||
<a
|
||||
href={SPOTIFY_SHOW_URL}
|
||||
target="_blank"
|
||||
@@ -321,6 +324,39 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CONTACT ── */}
|
||||
<section className="section-contact" id="contact" aria-label="Contact form">
|
||||
<div className="section-inner contact-inner">
|
||||
<div className="contact-copy">
|
||||
<p className="eyebrow">Get in Touch</p>
|
||||
<h2 className="section-heading">
|
||||
<span className="ornament">✦</span> Contact Nate <span className="ornament">✦</span>
|
||||
</h2>
|
||||
<p>
|
||||
Have a question, testimony, or topic request? Send a message and we will get back to you.
|
||||
</p>
|
||||
</div>
|
||||
<form className="contact-form" action={CONTACT_FORM_ACTION} method="POST">
|
||||
<input type="hidden" name="_subject" value="New message from Verse by Verse website" />
|
||||
<input type="hidden" name="_next" value={CONTACT_FORM_NEXT} />
|
||||
<input type="text" name="_honey" className="contact-honeypot" tabIndex={-1} autoComplete="off" />
|
||||
<label>
|
||||
Name
|
||||
<input type="text" name="name" required autoComplete="name" />
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input type="email" name="email" required autoComplete="email" />
|
||||
</label>
|
||||
<label>
|
||||
Message
|
||||
<textarea name="message" rows={6} required />
|
||||
</label>
|
||||
<button type="submit" className="btn-primary">Send Message</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CUSTOM RESOURCES ── */}
|
||||
{(content.customLinks ?? []).filter(l => l.placement === 'resources').length > 0 && (
|
||||
<section className="section-resources" aria-label="More resources">
|
||||
@@ -355,6 +391,10 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
<p className="footer-ornament">✦ ✦ ✦</p>
|
||||
<p className="footer-title">Verse by Verse with Nate</p>
|
||||
<p className="footer-sub">A Journey Through Scripture</p>
|
||||
<p className="footer-contact">
|
||||
Contact:{' '}
|
||||
<a href="mailto:vbvwithnate@outlook.com">vbvwithnate@outlook.com</a>
|
||||
</p>
|
||||
<nav className="footer-links" aria-label="Footer links">
|
||||
<a href={SPOTIFY_SHOW_URL} target="_blank" rel="noreferrer">Spotify</a>
|
||||
<span aria-hidden="true">·</span>
|
||||
@@ -378,6 +418,42 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
)
|
||||
}
|
||||
|
||||
function ThankYouPage() {
|
||||
const navigate = useNavigate()
|
||||
const [secondsLeft, setSecondsLeft] = useState(15)
|
||||
|
||||
useEffect(() => {
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
navigate('/')
|
||||
}, 15000)
|
||||
|
||||
const intervalId = window.setInterval(() => {
|
||||
setSecondsLeft(s => (s > 0 ? s - 1 : 0))
|
||||
}, 1000)
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(timeoutId)
|
||||
window.clearInterval(intervalId)
|
||||
}
|
||||
}, [navigate])
|
||||
|
||||
return (
|
||||
<main className="thanks-page" aria-label="Thank you">
|
||||
<div className="thanks-card">
|
||||
<p className="eyebrow">Message Received</p>
|
||||
<h1>Thank You</h1>
|
||||
<p>
|
||||
Your message was sent successfully. We appreciate you reaching out and will get back to you soon.
|
||||
</p>
|
||||
<p className="thanks-countdown">Returning to the main site in {secondsLeft} seconds...</p>
|
||||
<button type="button" className="btn-primary" onClick={() => navigate('/')}>
|
||||
Go Back Now
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [content, setContent] = useState<SiteContent>(DEFAULTS)
|
||||
|
||||
@@ -395,6 +471,7 @@ export default function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage content={content} />} />
|
||||
<Route path="/thanks" element={<ThankYouPage />} />
|
||||
<Route path="/admin" element={<AdminPage content={content} onSave={setContent} />} />
|
||||
</Routes>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user