Build public home, contact, and content pages
This commit is contained in:
284
src/app/page.tsx
284
src/app/page.tsx
@@ -1,38 +1,23 @@
|
||||
import Link from 'next/link';
|
||||
import { Section } from '@/components/Section';
|
||||
import { site } from '@/lib/site';
|
||||
import {
|
||||
featuredProperties,
|
||||
locationHighlights,
|
||||
site,
|
||||
testimonials,
|
||||
} from '@/lib/site';
|
||||
|
||||
const phaseCards = [
|
||||
{
|
||||
title: 'Project scaffold',
|
||||
items: ['Next.js app shell', 'Bootstrap + Sass', 'Shared layout and navigation'],
|
||||
},
|
||||
{
|
||||
title: 'Foundation data model',
|
||||
items: ['Prisma schema', 'Booking and payment entities', 'Content and property records'],
|
||||
},
|
||||
{
|
||||
title: 'Runtime readiness',
|
||||
items: ['Health endpoint', 'Environment variables', 'Docker entrypoint'],
|
||||
},
|
||||
const ctaPoints = [
|
||||
'Featured stays and clear summaries',
|
||||
'Location-led content for quick orientation',
|
||||
'A direct contact route for questions before booking',
|
||||
];
|
||||
|
||||
const stackCards = [
|
||||
{
|
||||
title: 'Frontend',
|
||||
items: ['Next.js App Router', 'React 19', 'Bootstrap 5', 'Sass theme layer'],
|
||||
},
|
||||
{
|
||||
title: 'Backend',
|
||||
items: ['Next.js route handlers', 'Prisma client', 'PostgreSQL'],
|
||||
},
|
||||
{
|
||||
title: 'Platform',
|
||||
items: ['Docker-based environments', 'Stripe Checkout later', 'Transactional email later'],
|
||||
},
|
||||
{
|
||||
title: 'Scope control',
|
||||
items: ['Docs-first planning', 'Phase gates', 'Separate booking and payment state'],
|
||||
},
|
||||
const bookingFields = [
|
||||
{ label: 'Arrival', value: 'Choose a date' },
|
||||
{ label: 'Departure', value: 'Choose a date' },
|
||||
{ label: 'Guests', value: '2 adults' },
|
||||
{ label: 'Area', value: 'Coastal or rural' },
|
||||
];
|
||||
|
||||
export default function HomePage() {
|
||||
@@ -40,55 +25,83 @@ export default function HomePage() {
|
||||
<>
|
||||
<section className="hero" id="top">
|
||||
<div className="hero-copy">
|
||||
<p className="brand-kicker">Phase 1 foundation</p>
|
||||
<p className="brand-kicker">Public website slice</p>
|
||||
<h2>{site.tagline}</h2>
|
||||
<p>{site.description}</p>
|
||||
|
||||
<div className="hero-actions">
|
||||
<a className="btn btn-primary" href="#foundation">
|
||||
Review foundation
|
||||
</a>
|
||||
<a className="btn btn-outline-dark" href="/api/health">
|
||||
Check health
|
||||
</a>
|
||||
<Link className="btn btn-primary" href="#browse">
|
||||
Explore featured stays
|
||||
</Link>
|
||||
<Link className="btn btn-outline-dark" href="/contact">
|
||||
Contact the team
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<ul className="hero-points">
|
||||
{ctaPoints.map((point) => (
|
||||
<li key={point}>{point}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<aside className="hero-panel" aria-label="Build snapshot">
|
||||
<aside className="hero-panel" aria-label="Quick search preview">
|
||||
<div className="info-card">
|
||||
<p className="footer-label">Current state</p>
|
||||
<strong>Scaffold created</strong>
|
||||
<p className="footer-label">Search preview</p>
|
||||
<strong>Plan the right stay</strong>
|
||||
<p className="mb-0 text-body-secondary">
|
||||
The project now has a repo boundary, app shell, and database foundation to build on.
|
||||
The booking flow will later use live availability and pricing. This slice keeps the public browsing entry point clear.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="metric-grid">
|
||||
<div className="metric">
|
||||
<strong>5</strong>
|
||||
<span>Foundation steps queued</span>
|
||||
</div>
|
||||
<div className="metric">
|
||||
<strong>1</strong>
|
||||
<span>Health endpoint</span>
|
||||
</div>
|
||||
</div>
|
||||
<form className="search-panel" aria-label="Availability search preview">
|
||||
{bookingFields.map((field) => (
|
||||
<label key={field.label} className="search-field">
|
||||
<span>{field.label}</span>
|
||||
<input aria-label={field.label} defaultValue={field.value} />
|
||||
</label>
|
||||
))}
|
||||
<button className="btn btn-dark" type="button">
|
||||
Check availability
|
||||
</button>
|
||||
</form>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<Section
|
||||
id="foundation"
|
||||
eyebrow="What is in place"
|
||||
title="Foundation work starts here"
|
||||
description="The approved planning docs are already complete, so the first build slice is the shared platform foundation rather than a feature page."
|
||||
id="browse"
|
||||
eyebrow="Featured stays"
|
||||
title="A few properties guests can imagine themselves in"
|
||||
description="The homepage gives the browsing experience enough shape to be useful before the dedicated listing and detail pages arrive."
|
||||
>
|
||||
<div className="phase-grid">
|
||||
{phaseCards.map((card) => (
|
||||
<article key={card.title} className="phase-card">
|
||||
<h3>{card.title}</h3>
|
||||
<ul>
|
||||
{card.items.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
<div className="property-grid">
|
||||
{featuredProperties.map((property) => (
|
||||
<article key={property.slug} className="property-card">
|
||||
<div className="property-card-top">
|
||||
<div>
|
||||
<p className="footer-label">{property.area}</p>
|
||||
<h3>{property.name}</h3>
|
||||
</div>
|
||||
<span className="property-price">{property.priceFrom}</span>
|
||||
</div>
|
||||
<p>{property.summary}</p>
|
||||
<dl className="property-metrics">
|
||||
<div>
|
||||
<dt>Sleeps</dt>
|
||||
<dd>{property.sleeps}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Bedrooms</dt>
|
||||
<dd>{property.bedrooms}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Bathrooms</dt>
|
||||
<dd>{property.bathrooms}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<ul className="tag-list">
|
||||
{property.tags.map((tag) => (
|
||||
<li key={tag}>{tag}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
@@ -97,57 +110,130 @@ export default function HomePage() {
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
id="stack"
|
||||
eyebrow="Technical direction"
|
||||
title="The implementation stack is locked"
|
||||
description="The app is set up to match the approved planning docs: Next.js, TypeScript, Bootstrap 5, Sass, PostgreSQL, Prisma, and Docker-based environments."
|
||||
id="story"
|
||||
eyebrow="About the business"
|
||||
title="Editorial content keeps the journey understandable"
|
||||
description="The homepage introduces the business, then lets the page hierarchy handle deeper detail. That keeps the first visit focused and low friction."
|
||||
>
|
||||
<div className="data-grid">
|
||||
{stackCards.map((card) => (
|
||||
<article key={card.title} className="data-card">
|
||||
<h3>{card.title}</h3>
|
||||
<ul>
|
||||
{card.items.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="content-grid">
|
||||
<article className="content-card">
|
||||
<h3>What the site should do</h3>
|
||||
<p>
|
||||
Guests should understand the style of stay, the practical details, and the next step without having to hunt through the UI.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Present the booking business clearly</li>
|
||||
<li>Reduce uncertainty before the enquiry step</li>
|
||||
<li>Keep public content editable as the site grows</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article className="content-card">
|
||||
<h3>How this slice is framed</h3>
|
||||
<p>
|
||||
The public website now has a real homepage, contact page, and editable content-page route so the next tickets can add richer booking behavior.
|
||||
</p>
|
||||
<Link className="inline-link" href="/about">
|
||||
Read the About page
|
||||
</Link>
|
||||
</article>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
id="places"
|
||||
eyebrow="Location highlights"
|
||||
title="The site can now speak about place, not just property"
|
||||
description="Guests often choose by location first, so the homepage includes content that makes the area feel legible before search and pricing are wired up."
|
||||
>
|
||||
<div className="card-stack">
|
||||
{locationHighlights.map((item) => (
|
||||
<article key={item.title} className="content-card">
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.body}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
id="data"
|
||||
eyebrow="Data model"
|
||||
title="The first schema pass is ready"
|
||||
description="The initial Prisma schema covers the core content, property, booking, payment, and site settings entities so later screens can use real records instead of placeholders."
|
||||
id="stories"
|
||||
eyebrow="Guest feedback"
|
||||
title="Testimonials and trust signals belong on the public page"
|
||||
description="The marketing layer needs a few trust cues so the journey feels deliberate instead of empty scaffold."
|
||||
>
|
||||
<div className="data-card">
|
||||
<h3>Seeded core entities</h3>
|
||||
<ul>
|
||||
{site.highlights.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="testimonial-grid">
|
||||
{testimonials.map((testimonial) => (
|
||||
<blockquote key={testimonial.author} className="testimonial-card">
|
||||
<p>{testimonial.quote}</p>
|
||||
<footer>
|
||||
<strong>{testimonial.author}</strong>
|
||||
<span>{testimonial.location}</span>
|
||||
</footer>
|
||||
</blockquote>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
id="launch"
|
||||
eyebrow="Next move"
|
||||
title="Ready for the first implementation slice"
|
||||
description="From here, the next work is to connect the app to real data and start the public browsing flow. The scaffold avoids guessing at booking behavior until the later docs are turned into screens."
|
||||
id="content"
|
||||
eyebrow="Editable pages"
|
||||
title="About, FAQs, local area, and policy pages are now routable"
|
||||
description="The content-page route can render the editorial and policy pages the public site needs without building each one as a special case."
|
||||
>
|
||||
<div className="data-card">
|
||||
<h3>Immediate follow-up</h3>
|
||||
<ul>
|
||||
<li>Connect Prisma to a real Postgres instance.</li>
|
||||
<li>Seed the first property and content records.</li>
|
||||
<li>Start the public homepage and listing screens.</li>
|
||||
</ul>
|
||||
<div className="content-grid content-grid-tight">
|
||||
<article className="content-card">
|
||||
<h3>Available pages</h3>
|
||||
<ul className="link-list">
|
||||
<li>
|
||||
<Link href="/about">About</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/local-area">Local area guide</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/faqs">FAQs</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/terms-and-conditions">Terms and conditions</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/privacy-policy">Privacy policy</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article className="content-card">
|
||||
<h3>What comes next</h3>
|
||||
<p>
|
||||
The next tickets can now focus on the property listing and property detail pages while the public content layer stays reusable.
|
||||
</p>
|
||||
<Link className="inline-link" href="/contact">
|
||||
Enquire through the contact page
|
||||
</Link>
|
||||
</article>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
id="contact"
|
||||
eyebrow="Next step"
|
||||
title="A clear contact route is already live"
|
||||
description="If a guest is not ready to book, the site now gives them a proper contact path rather than forcing a dead end."
|
||||
>
|
||||
<div className="cta-band">
|
||||
<div>
|
||||
<p className="footer-label">Contact details</p>
|
||||
<h3>{site.contact.email}</h3>
|
||||
<p className="mb-0">
|
||||
{site.contact.phone} • {site.contact.area}
|
||||
</p>
|
||||
</div>
|
||||
<Link className="btn btn-dark" href="/contact">
|
||||
Open contact page
|
||||
</Link>
|
||||
</div>
|
||||
</Section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user