pcbjam/site/src/components/Icon.astro
Viktor Vaczi 7f9dbdd068 feat(site): 🛬 PCBJam landing page — waitlist, sections, Tailwind
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>
2026-06-07 14:59:13 +02:00

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>