Files
brk/app/src/app/components/background.tsx
2024-08-05 00:44:46 +02:00

200 lines
4.6 KiB
TypeScript

import { phone, touchScreen } from "/src/env";
import { createRWS } from "/src/solid/rws";
const texts = [
"satonomics",
"satonomics",
"satonomics",
"satonomics",
"satonomics",
"stay humble, stack sats",
"21 million",
"cold storage",
"utxo",
"satoshi nakamoto",
"hodl",
`don't trust, verify`,
"zap",
"₿itcoin",
"lightning",
"nostr",
"freedom tech",
"2008/10/31",
"2009/01/03",
"2010/05/22",
"hodl!",
"Hal Finney",
"Vote for better money",
"gradually then suddenly",
"timechain",
"self custody",
"be your own bank",
"resistance money",
"foss",
"permissionless",
"great reset",
"orange pill",
"borderless",
"anonymous",
"nyknyc",
"low time preference",
"absolute scarcity",
"time is scarce",
"ride or die",
"cypherpunk",
"we like the coin",
];
export function Background({
mode,
opacity,
focused,
}: {
mode: SL<"Scroll" | "Static">;
opacity: SL<{ text: string; value: number }>;
focused: Accessor<boolean>;
}) {
return (
<>
<div
class="absolute h-full w-full overflow-hidden will-change-auto"
style={{
opacity: opacity.selected().value,
}}
>
<div class="-m-[2rem] -space-y-1 overflow-hidden md:-m-[1rem]">
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
<Line mode={mode} focused={focused} />
</div>
</div>
<div class="absolute h-full w-full opacity-10 mix-blend-multiply">
<Noise />
</div>
<div class="absolute h-full w-full opacity-10 mix-blend-hard-light">
<Noise />
</div>
</>
);
}
function Line({
mode,
focused,
}: {
mode: SL<"Scroll" | "Static">;
focused: Accessor<boolean>;
}) {
const shuffled = shuffle(texts).slice(0, 10);
const joined = shuffled.join(". ");
return (
<div class="select-none whitespace-nowrap">
<TextWrapper mode={mode} focused={focused} joined={joined} />
</div>
);
}
function TextWrapper({
joined,
mode,
focused,
}: {
mode: SL<"Scroll" | "Static">;
focused: Accessor<boolean>;
joined: string;
}) {
const p = createRWS(undefined as HTMLParagraphElement | undefined);
const seconds = createRWS(joined.length * 2);
const wasOnceOn = createRWS(false);
createEffect(() => {
if (!wasOnceOn() && mode.selected() === "Scroll") {
wasOnceOn.set(true);
}
});
// Bug in Safari iOS, not sure where else, works perfectly on Mac OS though
if (!touchScreen) {
onMount(() => {
seconds.set(Math.round(p()!.clientWidth / 20));
});
}
return (
<p
ref={p.set}
class="inline-block px-2 text-[5dvh] font-black uppercase leading-none"
style={{
...(wasOnceOn()
? {
animation: `marquee ${seconds()}s linear infinite`,
"animation-play-state":
focused() && mode.selected() === "Scroll"
? "running"
: "paused",
}
: {}),
}}
>
{joined} {wasOnceOn() ? joined : undefined}
</p>
);
}
function shuffle<T>([...arr]: T[]): T[] {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr;
}
function Noise() {
return (
<svg
class="size-full"
viewBox="0 0 200 200"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
>
<filter id="noiseFilter">
<feTurbulence
type="fractalNoise"
baseFrequency="3"
numOctaves="3"
stitchTiles="stitch"
/>
</filter>
<rect width="100%" height="100%" filter="url(#noiseFilter)" />
</svg>
);
}