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>
57 lines
1.5 KiB
Text
57 lines
1.5 KiB
Text
---
|
|
/**
|
|
* Icon — renders an SVG from /public.
|
|
*
|
|
* mode="mask" (default): paints the SVG silhouette with `currentColor` via a CSS
|
|
* mask, so monochrome glyphs (github, arrows, play, mail…) tint to the brand
|
|
* regardless of the file's own hardcoded fills.
|
|
* mode="img": a plain <img>, preserving the file's original colors — use for
|
|
* multicolor illustrations, brand wordmarks, and client/partner logos.
|
|
*
|
|
* `name` is a path under /public, e.g. "icons/github.svg" or "clients/skiff.svg".
|
|
*/
|
|
interface Props {
|
|
name: string;
|
|
alt?: string;
|
|
size?: string; // any CSS length; defaults to 1.25rem
|
|
mode?: 'mask' | 'img';
|
|
class?: string;
|
|
}
|
|
|
|
const { name, alt = '', size = '1.25rem', mode = 'mask', class: cls = '' } = Astro.props;
|
|
const src = `/${name.replace(/^\/+/, '')}`;
|
|
const decorative = alt === '';
|
|
---
|
|
|
|
{
|
|
mode === 'mask' ? (
|
|
<span
|
|
class={`icon-mask ${cls}`}
|
|
role={decorative ? undefined : 'img'}
|
|
aria-label={decorative ? undefined : alt}
|
|
aria-hidden={decorative ? 'true' : undefined}
|
|
style={`--icon-url:url('${src}');--icon-size:${size};`}
|
|
/>
|
|
) : (
|
|
<img
|
|
src={src}
|
|
alt={alt}
|
|
loading="lazy"
|
|
decoding="async"
|
|
class={cls}
|
|
style={`height:${size};width:auto;`}
|
|
/>
|
|
)
|
|
}
|
|
|
|
<style>
|
|
.icon-mask {
|
|
display: inline-block;
|
|
width: var(--icon-size);
|
|
height: var(--icon-size);
|
|
flex: none;
|
|
background-color: currentColor;
|
|
-webkit-mask: var(--icon-url) no-repeat center / contain;
|
|
mask: var(--icon-url) no-repeat center / contain;
|
|
}
|
|
</style>
|