import { Attributes, ComponentChild, ComponentChildren, JSX, VNode, toChildArray, } from "preact"; import { render } from "preact-render-to-string"; import { writeText } from "copy-paste"; // i know it's out of date; i just want something simple import { randomInt } from "https://deno.land/std@0.146.0/node/internal/crypto/random.ts"; export function Main({ children, ...attributes }: { children?: ComponentChildren; style?: JSX.CSSProperties; attributes?: JSX.HTMLAttributes; }) { return ( <div {...attributes} id="main"> {...toChildArray(children)} </div> ); } export const HCenter = ({ children, ...attrs }: { children: ComponentChildren; attrs?: Attributes; }) => ( <div {...attrs} class="hcenter" style="display: flex; justify-content: center;" > {...toChildArray(children)} </div> ); export const eggbug_emotions = (attrs: JSX.HTMLAttributes<HTMLImageElement>) => ({ smiling: ( <img class="eggbug" src="https://staging.cohostcdn.org/attachment/f33b4285-0455-4128-96b8-117054af40c3/eggbugSquare.png" alt="eggbug, smiling" {...attrs} /> ), frowning: ( <img class="eggbug" src="https://static.pyrope.net/eggbug-sad.png" alt="eggbug, frowning" {...attrs} /> ), revengeance: ( <img class="eggbug" src="https://static.pyrope.net/eggbug-revengeance.png" alt="ULTRA EGGBUG REVENGEANCE, MEGA. THERE IS FIRE. THERE IS TRISCAR. EGGBUG REVENGEANCE. YOU ARE. DIE!" {...attrs} /> ), jpeg_annihilation: ( <img class="eggbug" src="https://static.pyrope.net/eggbug-jpeg-annihilation.gif" alt="eggbug dissolving as the image gets more and more jpeg" {...attrs} /> ), golfball: ( <img class="eggbug" src="https://static.pyrope.net/eggbug-golfball.png" alt="eggbug as a golfball. no legs" {...attrs} /> ), } as const); export type EggbugEmotion = keyof ReturnType<typeof eggbug_emotions>; type bla = ({ type: EggbugEmotion; } & JSX.HTMLAttributes<HTMLImageElement>)["type"]; export const EggbugImg = ({ type, ...attrs }: { type: EggbugEmotion } & Omit< JSX.HTMLAttributes<HTMLImageElement>, "type" >) => eggbug_emotions(attrs)[type]; export const render_and_copy = (elem: VNode, pretty = false) => { const rendered = render(elem, null, { pretty }); writeText(rendered); console.log(rendered); }; export const mk_class_wrapper = (klass: string) => ({ children }: { children?: ComponentChildren }) => <div class={klass}>{...toChildArray(children)}</div>; export const slidify = ( Slide: (_: { slide: JSX.Element; next?: JSX.Element; n: number; max: number; }) => JSX.Element, slides: JSX.Element[], n = 1, max = slides.length ): JSX.Element => slides[0] ? ( <Slide slide={slides[0]} next={slidify(Slide, slides.slice(1), n + 1, max)} n={n} max={max} /> ) : ( <></> ); // https://cohost.org/lexyeevee/post/2107474-css-for-css-baby-3 (wayyy down at the bottom) export const DisappearOnClick = ({ children, className, }: { className?: string; children: ComponentChildren; }) => ( <details open class={`disappearing ${className}`} style="position: relative; cursor: pointer;" > <summary style="list-style: none; position: absolute; inset: 0;"></summary> {children} </details> ); /// make sure the margins are all legit export const ToggleOnClick = ({ children: [a, b], }: { children: [ComponentChild, ComponentChild]; }) => ( <details style="position: relative; margin: 0 auto; cursor: pointer;"> <summary style="list-style: none;">{a}</summary> <div style="display: block; position: absolute; top: 0; pointer-events: none;"> {b} </div> </details> ); // TODO: probably doesn't work export const ReduceOnClick = ({ children }: { children: VNode<{}>[] }) => { if (children.length == 0) return <></>; if (children.length == 1) return children[1]; return ( <details style="position: relative; margin: 0 auto; cursor: pointer;"> <summary style="list-style: none;">{children[0]}</summary> <ReduceOnClick>{...children.slice(1)}</ReduceOnClick> </details> ); }; export function shuffle<T>(array: T[]): T[] { let currentIndex = array.length, randomIndex; // While there remain elements to shuffle. while (currentIndex != 0) { // Pick a remaining element. randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; // And swap it with the current element. [array[currentIndex], array[randomIndex]] = [ array[randomIndex], array[currentIndex], ]; } return array; } // type NOf<N extends number, T, R extends any[] = []> = R["length"] extends N // ? R // : NOf<N, T, [T, ...R]>; // export function n_of<N extends number, T, R extends any[]>( // n: N, // x: T // ): NOf<N, T, R> { // return []; // } export function n_of<T>(n: number, x: T): T[] { return new Array(n).fill(x); } export const static_url = (res: string) => `https://static.pyrope.net/${res}`; export const randirect = (...urls: string[]) => `https://pyrope.net/randirect#${urls.join("::")}`; export const serverside_randirect = (...urls: string[]) => `https://pyrope.net/serverside-randirect?${urls.join("::")}`; // could do some [T, ...T[]] shenanigans for totality but meh // kinda bad name // unhappy with the randomness so i'm going way overkill lol export const pick_random = <T,>(xs: readonly T[]): T => xs[randomInt(xs.length)]; export const jitter = (n: number) => n * (Math.random() - 0.5); export const svg_url = (svg: string) => `data:image/svg+xml,${encodeURI(svg)}`; // something higher-level might be worthwhile... // could namespace; e.g. css.font.sans_serif // could put various beziers export const css = { url(href: string) { return `url('${href}')`; }, px(n: number) { return `${n}px`; }, em(n: number) { return `${n}em`; }, rem(n: number) { return `${n}rem`; }, deg(n: number) { return `${n}deg`; }, rad(n: number) { return `${n}rad`; }, turn(n: number) { return `${n}turn`; }, // now i feel like this could be generalizable // but js metaprogramming SUCKS transform(...ts: string[]) { return ts.join(" "); }, rotate(by: string) { return `rotate(${by})`; }, translateX(by: string) { return `translateX(${by})`; }, translateY(by: string) { return `translateY(${by})`; }, translate(x: string, y: string) { return `translate(${x}, ${y})`; }, fontstack(...fonts: string[]) { return fonts.join(", "); }, // # ruby i wont you .. inline_block: "inline-block", block: "block", grid: "grid", flex: "flex", fit_content: "fit-content", min_content: "min-content", max_content: "max-content", } as const; export const Filler = ({ height }: { height: string }) => ( <div style={`height:${height}`}></div> ); /// nonfunctional, deno's toplevel await (:D) is generally the best workaround export function make_sync_no_matter_the_cost<T>(promise: Promise<T>): T { let done = false; let out; promise.then(t => { out = t; done = true; }); return out as T; } // INFINITE CREDIT TO @BLACKLE https://cohost.org/blackle/post/72096-h3-style-text-alig export const Cycle = ({ width_px, height_px, children, style, }: { width_px: number; height_px: number; children: [ComponentChild, ...ComponentChild[]]; style?: Record<string, string>; }) => ( <div style={{ width: `${width_px}px`, height: `${height_px}px`, overflow: "hidden", filter: "url(https://mehbark.github.io/#INFINITE%20CREDIT%20TO%20@BLACKLE)", ...style, }} > <div style={{ display: "inline-flex", height: `${height_px}px`, paddingRight: `${width_px}px`, position: "relative", cursor: "pointer", }} > {...children.map((c, i) => ( <details> <summary style={{ position: "absolute", top: "0px", left: `calc(-${width_px * 100}% + ${ width_px * width_px + width_px * i }px)`, // width: `${width_px}px`, width: `calc(${ width_px * (children.length - 1) * 2 + width_px - width_px * i * 2 }px)`, height: `${height_px}px`, listStyle: "none", overflow: "hidden", }} > {c} </summary> <div style={{ width: `${ i == children.length - 1 ? children.length - 1 : 1 }px`, }} ></div> </details> ))} </div> </div> );