92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
import { For } from 'solid-js';
|
|
|
|
const chipNodes = [
|
|
{ kind: 'code', left: '2%', top: '14%', size: 44, cls: 'lp-chip-slow' },
|
|
{ kind: 'camera', left: '94%', top: '22%', size: 46, cls: 'lp-chip-mid' },
|
|
{ kind: 'briefcase', left: '3%', top: '76%', size: 46, cls: 'lp-chip-fast' },
|
|
{ kind: 'bell', left: '93%', top: '80%', size: 42, cls: 'lp-chip-slow' },
|
|
{ kind: 'sparkles', left: '50%', top: '6%', size: 40, cls: 'lp-chip-mid' },
|
|
] as const;
|
|
|
|
function ChipIcon(props: { kind: (typeof chipNodes)[number]['kind'] }) {
|
|
const common = { fill: 'none', stroke: 'currentColor', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' } as const;
|
|
if (props.kind === 'camera') {
|
|
return (
|
|
<svg viewBox="0 0 24 24" aria-hidden="true" {...common}>
|
|
<path d="M14 4a2 2 0 0 1 1.76 1.05l.49.9A2 2 0 0 0 18 7h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h2a2 2 0 0 0 1.76-1.05l.49-.9A2 2 0 0 1 10 4z" />
|
|
<circle cx="12" cy="13" r="3" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (props.kind === 'briefcase') {
|
|
return (
|
|
<svg viewBox="0 0 24 24" aria-hidden="true" {...common}>
|
|
<path d="M16 6V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2" />
|
|
<path d="M22 13a18 18 0 0 1-20 0" />
|
|
<rect x="2" y="6" width="20" height="14" rx="2" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (props.kind === 'bell') {
|
|
return (
|
|
<svg viewBox="0 0 24 24" aria-hidden="true" {...common}>
|
|
<path d="M10.3 21a2 2 0 0 0 3.4 0" />
|
|
<path d="M3.3 15.3A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.67C19.4 14 18 12.5 18 8A6 6 0 0 0 6 8c0 4.5-1.4 6-2.7 7.3" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (props.kind === 'sparkles') {
|
|
return (
|
|
<svg viewBox="0 0 24 24" aria-hidden="true" {...common}>
|
|
<path d="M11 2.8a1 1 0 0 1 2 0l1 5.6a2 2 0 0 0 1.6 1.6l5.6 1a1 1 0 0 1 0 2l-5.6 1a2 2 0 0 0-1.6 1.6l-1 5.6a1 1 0 0 1-2 0l-1-5.6A2 2 0 0 0 8.4 14l-5.6-1a1 1 0 0 1 0-2l5.6-1A2 2 0 0 0 10 8.4z" />
|
|
<path d="M20 2v4M22 4h-4" />
|
|
</svg>
|
|
);
|
|
}
|
|
return (
|
|
<svg viewBox="0 0 24 24" aria-hidden="true" {...common}>
|
|
<path d="m18 16 4-4-4-4" />
|
|
<path d="m6 8-4 4 4 4" />
|
|
<path d="m14.5 4-5 16" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
type PublicBackgroundProps = {
|
|
scrollY?: number;
|
|
reduceMotion?: boolean;
|
|
meshFactor?: number;
|
|
ribbonFactor?: number;
|
|
chipsFactor?: number;
|
|
meshCap?: number;
|
|
ribbonCap?: number;
|
|
chipsCap?: number;
|
|
};
|
|
|
|
export default function PublicBackground(props: PublicBackgroundProps) {
|
|
const y = () => (props.reduceMotion ? 0 : props.scrollY || 0);
|
|
const meshFactor = () => props.meshFactor ?? 0.1;
|
|
const ribbonFactor = () => props.ribbonFactor ?? 0.18;
|
|
const chipsFactor = () => props.chipsFactor ?? 0.24;
|
|
const meshCap = () => props.meshCap ?? 36;
|
|
const ribbonCap = () => props.ribbonCap ?? 58;
|
|
const chipsCap = () => props.chipsCap ?? 80;
|
|
|
|
return (
|
|
<div class="lp-bg" aria-hidden="true">
|
|
<div class="lp-dark-base" />
|
|
<div class="lp-mesh" style={{ transform: `translate3d(0, ${Math.min(meshCap(), y() * meshFactor())}px, 0)` }} />
|
|
<div class="lp-ribbon" style={{ transform: `translate3d(0, ${Math.min(ribbonCap(), y() * ribbonFactor())}px, 0)` }} />
|
|
<div class="lp-noise" />
|
|
<div class="lp-chips" style={{ transform: `translate3d(0, ${Math.min(chipsCap(), y() * chipsFactor())}px, 0)` }}>
|
|
<For each={chipNodes}>
|
|
{(chip) => (
|
|
<span class={`lp-chip ${chip.cls}`} style={{ left: chip.left, top: chip.top, width: `${chip.size}px`, height: `${chip.size}px` }}>
|
|
<ChipIcon kind={chip.kind} />
|
|
</span>
|
|
)}
|
|
</For>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|