## Summary Implements Spec 216 for the public website homepage in `apps/website`. This reworks the homepage into the required narrative flow: - hero with one dominant CTA, one secondary CTA, product-near visual, and bounded trust subclaims - outcome framing section - grouped capability model section - explicit trust block before the final CTA - dated progress teaser backed by changelog entries - final CTA transition to contact It also adds the full spec-kit artifact set for `specs/216-homepage-structure` and updates the smoke suite to prove section order, CTA hierarchy, onward route reachability, and mobile readability. ## Validation - `corepack pnpm build:website` - `cd apps/website && corepack pnpm exec playwright test` ## Notes - Branch: `216-homepage-structure` - Commit: `097f8e70` - Remote branch has been pushed and is ready for review. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #254
107 lines
4.8 KiB
Plaintext
107 lines
4.8 KiB
Plaintext
---
|
|
import Badge from '@/components/primitives/Badge.astro';
|
|
import Card from '@/components/primitives/Card.astro';
|
|
import Cluster from '@/components/primitives/Cluster.astro';
|
|
import Container from '@/components/primitives/Container.astro';
|
|
import Headline from '@/components/content/Headline.astro';
|
|
import Lead from '@/components/content/Lead.astro';
|
|
import Metric from '@/components/content/Metric.astro';
|
|
import PrimaryCTA from '@/components/content/PrimaryCTA.astro';
|
|
import SecondaryCTA from '@/components/content/SecondaryCTA.astro';
|
|
import type { HeroContent, MetricItem } from '@/types/site';
|
|
|
|
interface Props {
|
|
calloutDescription?: string;
|
|
calloutTitle?: string;
|
|
hero: HeroContent;
|
|
metrics?: MetricItem[];
|
|
}
|
|
|
|
const { calloutDescription, calloutTitle, hero, metrics = [] } = Astro.props;
|
|
---
|
|
|
|
<section class="pt-8 sm:pt-10 lg:pt-14">
|
|
<Container width="wide">
|
|
<div class="grid gap-6 lg:grid-cols-[1.35fr,0.85fr]" data-disclosure-layer="1">
|
|
<Card class="motion-rise overflow-hidden">
|
|
<div class="space-y-6">
|
|
<Badge>{hero.eyebrow}</Badge>
|
|
<div class="space-y-4">
|
|
<Headline as="h1" size="display" class="max-w-4xl">
|
|
{hero.title}
|
|
</Headline>
|
|
<Lead class="max-w-3xl" size="lead">
|
|
{hero.description}
|
|
</Lead>
|
|
</div>
|
|
{(hero.primaryCta || hero.secondaryCta) && (
|
|
<Cluster data-cta-cluster gap="md">
|
|
<PrimaryCTA cta={hero.primaryCta} />
|
|
{hero.secondaryCta && (
|
|
<SecondaryCTA cta={hero.secondaryCta} />
|
|
)}
|
|
</Cluster>
|
|
)}
|
|
{hero.trustSubclaims && hero.trustSubclaims.length > 0 && (
|
|
<ul class="grid gap-3 p-0 sm:grid-cols-3">
|
|
{
|
|
hero.trustSubclaims.map((claim) => (
|
|
<li class="list-none rounded-[1.1rem] border border-[color:var(--color-line)] bg-white/70 px-4 py-3 text-sm font-medium text-[var(--color-ink-800)]">
|
|
{claim}
|
|
</li>
|
|
))
|
|
}
|
|
</ul>
|
|
)}
|
|
{hero.highlights && hero.highlights.length > 0 && !hero.trustSubclaims?.length && (
|
|
<ul class="grid gap-3 p-0 sm:grid-cols-3">
|
|
{
|
|
hero.highlights.map((highlight) => (
|
|
<li class="list-none rounded-[1.1rem] border border-[color:var(--color-line)] bg-white/70 px-4 py-3 text-sm font-medium text-[var(--color-ink-800)]">
|
|
{highlight}
|
|
</li>
|
|
))
|
|
}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
</Card>
|
|
|
|
<div class="grid gap-5">
|
|
{hero.productVisual && (
|
|
<Card variant="accent" class="motion-rise overflow-hidden" data-hero-visual>
|
|
<img
|
|
src={hero.productVisual.src}
|
|
alt={hero.productVisual.alt}
|
|
class="w-full rounded-[var(--radius-lg)] object-cover"
|
|
loading="eager"
|
|
/>
|
|
</Card>
|
|
)}
|
|
|
|
{!hero.productVisual && (calloutTitle || calloutDescription) && (
|
|
<Card variant="accent" class="motion-rise">
|
|
<p class="m-0 text-sm font-semibold uppercase tracking-[0.15em] text-[var(--color-brand)]">
|
|
Trust-first launch surface
|
|
</p>
|
|
{calloutTitle && (
|
|
<h2 class="mt-4 font-[var(--font-display)] text-3xl leading-tight text-[var(--color-ink-900)]">
|
|
{calloutTitle}
|
|
</h2>
|
|
)}
|
|
{calloutDescription && (
|
|
<p class="mt-3 text-base leading-7 text-[var(--color-copy)]">{calloutDescription}</p>
|
|
)}
|
|
</Card>
|
|
)}
|
|
|
|
{metrics.length > 0 && (
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-1">
|
|
{metrics.map((metric) => <Metric item={metric} />)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Container>
|
|
</section>
|