feat(02-01): scaffold marketing site nav, hero, listings, footer
- Add scroll-behavior: smooth and scroll-margin-top to globals.css - Create SiteNav with sticky navy bar, desktop links, mobile hamburger - Create HeroSection with split-panel layout and next/image - Create ListingsPlaceholder with brand navy background and gold CTA - Create SiteFooter with license number and TODO verify comment - Update page.tsx to compose all section components - Install lucide-react for icons [Rule 1 - Bug] Fixed event handlers in server components — used CSS hover classes instead
This commit is contained in:
111
teressa-copeland-homes/src/app/_components/HeroSection.tsx
Normal file
111
teressa-copeland-homes/src/app/_components/HeroSection.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function HeroSection() {
|
||||
return (
|
||||
<section id="hero" className="hero-section">
|
||||
{/* Left half — photo */}
|
||||
<div className="hero-photo">
|
||||
<Image
|
||||
src="/red.jpg"
|
||||
alt="Teressa Copeland"
|
||||
fill
|
||||
style={{ objectFit: 'cover', objectPosition: 'center top' }}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right half — copy */}
|
||||
<div className="hero-copy">
|
||||
{/* PLACEHOLDER HEADLINE — replace before launch */}
|
||||
<h1 className="hero-headline">
|
||||
Your Trusted Utah Real Estate Partner
|
||||
</h1>
|
||||
|
||||
{/* PLACEHOLDER SUBHEADING — replace before launch */}
|
||||
<p className="hero-subheading">
|
||||
Helping Utah families find the home they deserve
|
||||
</p>
|
||||
|
||||
{/* PLACEHOLDER BIO — replace before launch */}
|
||||
<p className="hero-bio">
|
||||
With years of experience navigating the Utah real estate market,
|
||||
Teressa Copeland brings deep local knowledge and a genuine commitment
|
||||
to every client she serves. Whether you're buying your first home
|
||||
in the Salt Lake Valley or selling a property along the Wasatch Front,
|
||||
Teressa guides you through every step with patience, transparency, and
|
||||
skill. Her clients don't just find houses — they find the right
|
||||
home.
|
||||
</p>
|
||||
|
||||
<a href="#contact" className="hero-cta">
|
||||
Get in Touch
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.hero-section {
|
||||
display: flex;
|
||||
min-height: 600px;
|
||||
background-color: #FAF9F7;
|
||||
}
|
||||
.hero-photo {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
min-height: 500px;
|
||||
}
|
||||
.hero-copy {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 4rem 3rem;
|
||||
background-color: #FAF9F7;
|
||||
}
|
||||
.hero-headline {
|
||||
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
||||
font-weight: 700;
|
||||
color: #1B2B4B;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.hero-subheading {
|
||||
font-size: 1.125rem;
|
||||
color: #1B2B4B;
|
||||
opacity: 0.75;
|
||||
margin-bottom: 1.5rem;
|
||||
font-style: italic;
|
||||
}
|
||||
.hero-bio {
|
||||
font-size: 1rem;
|
||||
color: #1B2B4B;
|
||||
line-height: 1.75;
|
||||
margin-bottom: 2rem;
|
||||
max-width: 480px;
|
||||
}
|
||||
.hero-cta {
|
||||
display: inline-block;
|
||||
background-color: #C9A84C;
|
||||
color: #1B2B4B;
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 2rem;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
align-self: flex-start;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.hero-cta:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.hero-section {
|
||||
flex-direction: column;
|
||||
}
|
||||
.hero-photo {
|
||||
min-height: 300px;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Home } from 'lucide-react';
|
||||
|
||||
export default function ListingsPlaceholder() {
|
||||
return (
|
||||
<section id="listings" className="listings-section">
|
||||
<div className="listings-inner">
|
||||
<Home size={48} color="#C9A84C" />
|
||||
|
||||
<h2 className="listings-heading">Listings Coming Soon</h2>
|
||||
|
||||
<p className="listings-desc">
|
||||
Teressa is actively curating listings in your area. Check back soon or
|
||||
reach out directly.
|
||||
</p>
|
||||
|
||||
<a href="#contact" className="listings-cta">
|
||||
Contact Teressa
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.listings-section {
|
||||
background-color: #1B2B4B;
|
||||
color: #FAF9F7;
|
||||
padding: 5rem 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.listings-inner {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
.listings-heading {
|
||||
font-size: clamp(1.5rem, 3vw, 2rem);
|
||||
font-weight: 700;
|
||||
color: #FAF9F7;
|
||||
margin: 0;
|
||||
}
|
||||
.listings-desc {
|
||||
font-size: 1rem;
|
||||
color: #FAF9F7;
|
||||
opacity: 0.8;
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
}
|
||||
.listings-cta {
|
||||
display: inline-block;
|
||||
border: 2px solid #C9A84C;
|
||||
color: #C9A84C;
|
||||
font-weight: 600;
|
||||
padding: 0.6rem 1.75rem;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-size: 0.95rem;
|
||||
margin-top: 0.5rem;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
}
|
||||
.listings-cta:hover {
|
||||
background-color: #C9A84C;
|
||||
color: #1B2B4B;
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
74
teressa-copeland-homes/src/app/_components/SiteFooter.tsx
Normal file
74
teressa-copeland-homes/src/app/_components/SiteFooter.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
const navLinks = [
|
||||
{ label: 'Home', href: '#hero' },
|
||||
{ label: 'About', href: '#about' },
|
||||
{ label: 'Listings', href: '#listings' },
|
||||
{ label: 'Contact', href: '#contact' },
|
||||
];
|
||||
|
||||
export default function SiteFooter() {
|
||||
return (
|
||||
<footer
|
||||
style={{
|
||||
backgroundColor: '#1B2B4B',
|
||||
color: '#FAF9F7',
|
||||
padding: '2rem 1.5rem',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: '1200px',
|
||||
margin: '0 auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '0.75rem',
|
||||
alignItems: 'center',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{/* Row 1: Name / Wordmark */}
|
||||
<p style={{ fontWeight: 'bold', fontSize: '1rem', margin: 0 }}>
|
||||
Teressa Copeland Homes
|
||||
</p>
|
||||
|
||||
{/* Row 2: License number */}
|
||||
<p style={{ fontSize: '0.875rem', opacity: 0.75, margin: 0 }}>
|
||||
{/* TODO: Verify license number before launch — last two chars may be "00" (zeros) or "OO" (letters O) */}
|
||||
Utah Real Estate License: 14196185-SA00
|
||||
</p>
|
||||
|
||||
{/* Row 3: Copyright */}
|
||||
<p style={{ fontSize: '0.8rem', opacity: 0.6, margin: 0 }}>
|
||||
© {new Date().getFullYear()} Teressa Copeland Homes. All rights
|
||||
reserved.
|
||||
</p>
|
||||
|
||||
{/* Row 4: Nav links */}
|
||||
<nav
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '1.5rem',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
marginTop: '0.5rem',
|
||||
}}
|
||||
>
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
style={{
|
||||
color: '#FAF9F7',
|
||||
textDecoration: 'none',
|
||||
fontSize: '0.875rem',
|
||||
opacity: 0.75,
|
||||
transition: 'opacity 0.2s',
|
||||
}}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
153
teressa-copeland-homes/src/app/_components/SiteNav.tsx
Normal file
153
teressa-copeland-homes/src/app/_components/SiteNav.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
|
||||
const navLinks = [
|
||||
{ label: 'Home', href: '#hero' },
|
||||
{ label: 'About', href: '#about' },
|
||||
{ label: 'Listings', href: '#listings' },
|
||||
{ label: 'Contact', href: '#contact' },
|
||||
];
|
||||
|
||||
export default function SiteNav() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
function handleMobileLinkClick() {
|
||||
setIsOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav
|
||||
style={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: 50,
|
||||
backgroundColor: '#1B2B4B',
|
||||
color: '#FAF9F7',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: '1200px',
|
||||
margin: '0 auto',
|
||||
padding: '0 1.5rem',
|
||||
height: '72px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{/* Wordmark */}
|
||||
<a
|
||||
href="#hero"
|
||||
style={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.125rem',
|
||||
color: '#FAF9F7',
|
||||
textDecoration: 'none',
|
||||
letterSpacing: '0.01em',
|
||||
}}
|
||||
>
|
||||
Teressa Copeland
|
||||
</a>
|
||||
|
||||
{/* Desktop nav links — hidden on mobile */}
|
||||
<ul
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '2rem',
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
}}
|
||||
className="hidden-mobile-nav"
|
||||
>
|
||||
{navLinks.map((link) => (
|
||||
<li key={link.href}>
|
||||
<a
|
||||
href={link.href}
|
||||
style={{
|
||||
color: '#FAF9F7',
|
||||
textDecoration: 'none',
|
||||
fontSize: '0.95rem',
|
||||
opacity: 0.9,
|
||||
transition: 'opacity 0.2s',
|
||||
}}
|
||||
onMouseEnter={(e) =>
|
||||
((e.currentTarget as HTMLAnchorElement).style.opacity = '1')
|
||||
}
|
||||
onMouseLeave={(e) =>
|
||||
((e.currentTarget as HTMLAnchorElement).style.opacity = '0.9')
|
||||
}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{/* Mobile hamburger button */}
|
||||
<button
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
aria-label={isOpen ? 'Close menu' : 'Open menu'}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: '#FAF9F7',
|
||||
cursor: 'pointer',
|
||||
padding: '0.25rem',
|
||||
display: 'none',
|
||||
}}
|
||||
className="mobile-menu-btn"
|
||||
>
|
||||
{isOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile dropdown drawer */}
|
||||
{isOpen && (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: '#1B2B4B',
|
||||
borderTop: '1px solid rgba(250,249,247,0.15)',
|
||||
padding: '1rem 1.5rem',
|
||||
}}
|
||||
className="mobile-nav-drawer"
|
||||
>
|
||||
<ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
|
||||
{navLinks.map((link) => (
|
||||
<li key={link.href} style={{ marginBottom: '0.75rem' }}>
|
||||
<a
|
||||
href={link.href}
|
||||
onClick={handleMobileLinkClick}
|
||||
style={{
|
||||
color: '#FAF9F7',
|
||||
textDecoration: 'none',
|
||||
fontSize: '1rem',
|
||||
display: 'block',
|
||||
padding: '0.25rem 0',
|
||||
}}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<style>{`
|
||||
@media (min-width: 768px) {
|
||||
.hidden-mobile-nav { display: flex !important; }
|
||||
.mobile-menu-btn { display: none !important; }
|
||||
.mobile-nav-drawer { display: none !important; }
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.hidden-mobile-nav { display: none !important; }
|
||||
.mobile-menu-btn { display: block !important; }
|
||||
}
|
||||
`}</style>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
@@ -24,3 +24,11 @@ body {
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
section[id] {
|
||||
scroll-margin-top: 72px;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import SiteNav from './_components/SiteNav';
|
||||
import HeroSection from './_components/HeroSection';
|
||||
import ListingsPlaceholder from './_components/ListingsPlaceholder';
|
||||
import { ContactSection } from './_components/ContactSection';
|
||||
import SiteFooter from './_components/SiteFooter';
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="min-h-screen flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold text-gray-900">Teressa Copeland Homes</h1>
|
||||
<p className="mt-4 text-gray-600">Real estate expertise for Utah home buyers and sellers.</p>
|
||||
<p className="mt-2 text-sm text-gray-400">Marketing site coming in Phase 2.</p>
|
||||
</div>
|
||||
</main>
|
||||
<>
|
||||
<SiteNav />
|
||||
<main>
|
||||
<HeroSection />
|
||||
{/* TestimonialsSection — added in Task 2 */}
|
||||
<ListingsPlaceholder />
|
||||
<ContactSection />
|
||||
</main>
|
||||
<SiteFooter />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user