Replace the placeholder homepage with the PCBJam waitlist conversion page (13 sections from the copy spec), shared chrome, and a real email-capture backend, keeping the site zero-runtime-JS / zero-web-font. - Tailwind v4 via @tailwindcss/postcss (the Vite plugin breaks on Astro 6 rolldown-vite); Preflight skipped; brand tokens in :root + @theme inline. - Waitlist: /api/waitlist serverless route (prerender=false) + Resend, with dual JSON/303 responses; WaitlistForm progressive enhancement bound on astro:page-load (survives ClientRouter swaps); honeypot + validation. - New components (Icon, Placeholder, DemoVideo, SectionBand, Chip, EECredit, StatBar, Pillar, Step, CheckItem, WaitlistForm) + 13 section components. - Redesigned Header (sticky, mobile menu, CTA) + 4-col Footer (KiCad attribution); BaseLayout gains full-bleed mode + OG/canonical meta. - Assets scaffolded with marked placeholders; EE/generic/client SVGs copied. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
1.6 KiB
Text
63 lines
1.6 KiB
Text
---
|
|
/**
|
|
* Placeholder — a clearly-marked, dashed-box slot for an asset that doesn't
|
|
* exist yet (PCBJam logo, demo video, product screenshots…). Real assets drop
|
|
* into the same spot later by swapping this component for an <img>/<DemoVideo>.
|
|
*
|
|
* The `label` should name what to produce + the spec ref, e.g.
|
|
* "PRODUCE: multiplayer demo loop (§4b.2)"
|
|
*/
|
|
interface Props {
|
|
label: string;
|
|
ratio?: string; // e.g. "16 / 9", "1 / 1"; default 16/9
|
|
kind?: 'image' | 'video' | 'logo';
|
|
class?: string;
|
|
}
|
|
|
|
const { label, ratio = '16 / 9', kind = 'image', class: cls = '' } = Astro.props;
|
|
const glyph = kind === 'video' ? '▶' : kind === 'logo' ? '◆' : '▦';
|
|
---
|
|
|
|
<div
|
|
class={`placeholder ${cls}`}
|
|
data-placeholder={kind}
|
|
style={`aspect-ratio:${ratio};`}
|
|
role="img"
|
|
aria-label={label}
|
|
>
|
|
<span class="ph-glyph" aria-hidden="true">{glyph}</span>
|
|
<span class="ph-label">{label}</span>
|
|
</div>
|
|
|
|
<style>
|
|
.placeholder {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
width: 100%;
|
|
padding: 1.5rem;
|
|
text-align: center;
|
|
border: 2px dashed var(--border);
|
|
border-radius: var(--radius);
|
|
background:
|
|
repeating-linear-gradient(
|
|
45deg,
|
|
color-mix(in srgb, var(--bg-soft) 88%, transparent),
|
|
color-mix(in srgb, var(--bg-soft) 88%, transparent) 12px,
|
|
var(--bg-soft) 12px,
|
|
var(--bg-soft) 24px
|
|
);
|
|
color: var(--fg-muted);
|
|
}
|
|
.ph-glyph {
|
|
font-size: 1.75rem;
|
|
opacity: 0.6;
|
|
}
|
|
.ph-label {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
letter-spacing: 0.01em;
|
|
}
|
|
</style>
|