diff options
| author | Xe Iaso <me@christine.website> | 2023-09-30 10:36:37 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-30 10:36:37 -0400 |
| commit | ac6a3df0d18cc73524c0096d954a57d24cad5669 (patch) | |
| tree | 81474177d730440657f490ae29892d62392251ea /lume/src/_components | |
| parent | cbdea8ba3fca9a663778af71f8df5965aeb6c090 (diff) | |
| download | xesite-ac6a3df0d18cc73524c0096d954a57d24cad5669.tar.xz xesite-ac6a3df0d18cc73524c0096d954a57d24cad5669.zip | |
Xesite V4 (#723)
* scripts/ditherify: fix quoting
Signed-off-by: Xe Iaso <me@xeiaso.net>
* clean up some old files
Signed-off-by: Xe Iaso <me@xeiaso.net>
* import site into lume
Signed-off-by: Xe Iaso <me@xeiaso.net>
* initial go code
Signed-off-by: Xe Iaso <me@xeiaso.net>
* move vods index to top level
Signed-off-by: Xe Iaso <me@xeiaso.net>
* remove the ads
Signed-off-by: Xe Iaso <me@xeiaso.net>
* internal/lume: metrics
Signed-off-by: Xe Iaso <me@xeiaso.net>
* delete old code
Signed-off-by: Xe Iaso <me@xeiaso.net>
* load config into memory
Signed-off-by: Xe Iaso <me@xeiaso.net>
* autogenerate data from dhall config
Signed-off-by: Xe Iaso <me@xeiaso.net>
* various cleanups, import clackset logic
Signed-off-by: Xe Iaso <me@xeiaso.net>
* Update signalboost.dhall (#722)
Added myself, and also fixed someone’s typo
* Add Connor Edwards to signal boost (#721)
* add cache headers
Signed-off-by: Xe Iaso <me@xeiaso.net>
* move command to xesite folder
Signed-off-by: Xe Iaso <me@xeiaso.net>
* xesite: listen for GitHub webhook push events
Signed-off-by: Xe Iaso <me@xeiaso.net>
* xesite: 5 minute timeout for rebuilding the site
Signed-off-by: Xe Iaso <me@xeiaso.net>
* xesite: add rebuild metrics
Signed-off-by: Xe Iaso <me@xeiaso.net>
* xesite: update default variables
Signed-off-by: Xe Iaso <me@xeiaso.net>
* don't commit binaries oops lol
Signed-off-by: Xe Iaso <me@xeiaso.net>
* lume: make search have a light background
Signed-off-by: Xe Iaso <me@xeiaso.net>
* add a notfound page
Signed-off-by: Xe Iaso <me@xeiaso.net>
* fetch info from patreon API
Signed-off-by: Xe Iaso <me@xeiaso.net>
* create contact page
Signed-off-by: Xe Iaso <me@xeiaso.net>
* Toot embedding
Signed-off-by: Xe Iaso <me@xeiaso.net>
* attempt a docker image
Signed-off-by: Xe Iaso <me@xeiaso.net>
* lume: fix deno lock
Signed-off-by: Xe Iaso <me@xeiaso.net>
* add gokrazy post
Signed-off-by: Xe Iaso <me@xeiaso.net>
* cmd/xesite: go up before trying to connect to the saas proxy
Signed-off-by: Xe Iaso <me@xeiaso.net>
* blog: add Sine post/demo
Signed-off-by: Xe Iaso <me@xeiaso.net>
---------
Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: bri <284789+b-@users.noreply.github.com>
Co-authored-by: Connor Edwards <38229097+cedws@users.noreply.github.com>
Diffstat (limited to 'lume/src/_components')
| -rw-r--r-- | lume/src/_components/MastodonShare.tsx | 83 | ||||
| -rw-r--r-- | lume/src/_components/SignalboostCard.tsx | 43 | ||||
| -rw-r--r-- | lume/src/_components/XeblogConv.tsx | 36 | ||||
| -rw-r--r-- | lume/src/_components/XeblogHero.tsx | 40 | ||||
| -rw-r--r-- | lume/src/_components/XeblogPicture.tsx | 27 | ||||
| -rw-r--r-- | lume/src/_components/XeblogSlide.tsx | 28 | ||||
| -rw-r--r-- | lume/src/_components/XeblogSticker.tsx | 29 | ||||
| -rw-r--r-- | lume/src/_components/XeblogToot.tsx | 63 | ||||
| -rw-r--r-- | lume/src/_components/XeblogVideo.tsx | 42 |
9 files changed, 391 insertions, 0 deletions
diff --git a/lume/src/_components/MastodonShare.tsx b/lume/src/_components/MastodonShare.tsx new file mode 100644 index 0000000..be91a78 --- /dev/null +++ b/lume/src/_components/MastodonShare.tsx @@ -0,0 +1,83 @@ +import { useState } from "npm:preact/hooks"; + +const u = (url = "", params = {}) => { + let result = new URL(url, window.location.href); + Object.entries(params).forEach((kv) => { + let [k, v] = kv; + result.searchParams.set(k, v as string); + }); + return result.toString(); + }; + +export interface MastodonShareButtonProps { + title: string; + url: string; + series?: string; + tags: string; +} + +export default function MastodonShareButton( + { title, url, series, tags }: MastodonShareButtonProps, +) { + let defaultURL = localStorage["mastodon_instance"]; + + if (defaultURL == undefined) { + defaultURL = ""; + } + + const tootTemplate = `${title} + +${url} + +${series ? "#" + series + " " : ""}${ + tags ? tags.map((x) => "#" + x).join(" ") : "" + } @cadey@pony.social`; + + const [getURL, setURL] = useState(defaultURL); + const [getToot, setToot] = useState(tootTemplate); + + return ( + <div> + <details> + <summary>Share on Mastodon</summary> + <span>{"Instance URL (https://mastodon.example)"}</span> + <br /> + <input + type="text" + placeholder="https://pony.social" + value={defaultURL} + oninput={(e) => setURL(e.target.value)} + /> + <br /> + <textarea + rows={6} + cols={40} + oninput={(e) => setToot(e.target.value)} + > + {getToot()} + </textarea> + <br /> + <button + onclick={() => { + let instanceURL = getURL; + + if (!instanceURL.startsWith("https://")) { + instanceURL = `https://${instanceURL}`; + } + + localStorage["mastodon_instance"] = instanceURL; + const text = getToot; + const mastodonURL = u(instanceURL + "/share", { + text, + visibility: "public", + }); + console.log({ text, mastodonURL }); + window.open(mastodonURL, "_blank"); + }} + > + Share + </button> + </details> + </div> + ); +} diff --git a/lume/src/_components/SignalboostCard.tsx b/lume/src/_components/SignalboostCard.tsx new file mode 100644 index 0000000..c5ec6f2 --- /dev/null +++ b/lume/src/_components/SignalboostCard.tsx @@ -0,0 +1,43 @@ +export type Link = { + url: string; + title: string; + description?: string; +}; + +export interface SignalBoostCardProps { + name: string; + tags: string[]; + links: Link[]; +} + +export default function Card( + { + name, + tags, + links, + }: SignalBoostCardProps, +) { + return ( + <div id={name} class="bg-bg-1 dark:bg-bgDark-1 rounded-xl m-2 shadow-md max-w-[29rem]"> + <div class="items-center text-xl pl-4 pt-4 font-bold"> + {name} + </div> + <div class="flex flex-row items-center px-4 py-2"> + <div class="flex flex-wrap items-start justify-center p-5"> + {tags.map((tag) => ( + <div class="px-2 py-1 m-1 bg-bg-2 dark:bg-bgDark-2 rounded-lg"> + {tag} + </div> + ))} + {links.map((link) => ( + <div class="px-2 py-1 m-1 bg-bg-2 dark:bg-bgDark-2 rounded-lg"> + <a class="flex flex-row items-center" href={link.url}> + {link.title} + </a> + </div> + ))} + </div> + </div> + </div> + ); +} diff --git a/lume/src/_components/XeblogConv.tsx b/lume/src/_components/XeblogConv.tsx new file mode 100644 index 0000000..f876cd0 --- /dev/null +++ b/lume/src/_components/XeblogConv.tsx @@ -0,0 +1,36 @@ +export interface XeblogConvProps { + name: string; + mood: string; + children: HTMLElement[]; + standalone?: boolean; +} + +const ConvSnippet = ({ name, mood, children, standalone }: XeblogConvProps) => { + const nameLower = name.toLowerCase(); + name = name.replace(" ", "_"); + const size = standalone ? 128 : 64; + + return ( + <> + <div className="my-4 flex space-x-4 rounded-md border border-solid border-fg-4 bg-bg-2 p-3 dark:border-fgDark-4 dark:bg-bgDark-2 max-w-full"> + <div className="flex max-h-16 max-w-16 shrink-0 items-center justify-center self-center overflow-hidden rounded-lg bg-gray-200 dark:bg-gray-700"> + <img + style="max-height:4.5rem" + alt={`${name} is ${mood}`} + loading="lazy" + src={`https://cdn.xeiaso.net/sticker/${nameLower}/${mood}/${size}`} + /> + </div> + <div className="convsnippet min-w-0 self-center"> + {"<"} + <a href={`/characters#${nameLower}`}> + <b>{name}</b> + </a> + {">"} {children} + </div> + </div> + </> + ); +}; + +export default ConvSnippet; diff --git a/lume/src/_components/XeblogHero.tsx b/lume/src/_components/XeblogHero.tsx new file mode 100644 index 0000000..6c1cefa --- /dev/null +++ b/lume/src/_components/XeblogHero.tsx @@ -0,0 +1,40 @@ +export interface XeblogHeroProps { + ai: string; + file: string; + prompt: string; +} + +export default function XeblogHero({ ai, file, prompt }: XeblogHeroProps) { + return ( + <> + <figure className="hero not-prose w-full"> + <picture> + <source + type="image/avif" + srcset={`https://cdn.xeiaso.net/file/christine-static/hero/${file}.avif`} + /> + <source + type="image/webp" + srcset={`https://cdn.xeiaso.net/file/christine-static/hero/${file}.webp`} + /> + <img + alt={`An image of ${prompt}`} + loading="lazy" + src={`https://cdn.xeiaso.net/file/christine-static/hero/${file}.jpg`} + /> + </picture> + {ai !== undefined + ? ( + <figcaption className="mx-2 my-1 text-center text-gray-600 dark:text-gray-400"> + Image generated by {ai}, prompt: {prompt} + </figcaption> + ) + : ( + <figcaption className="mx-2 my-1 text-center text-gray-600 dark:text-gray-400"> + {prompt} + </figcaption> + )} + </figure> + </> + ); +} diff --git a/lume/src/_components/XeblogPicture.tsx b/lume/src/_components/XeblogPicture.tsx new file mode 100644 index 0000000..9f20e6c --- /dev/null +++ b/lume/src/_components/XeblogPicture.tsx @@ -0,0 +1,27 @@ +export interface XeblogPicture { + path: string; + desc?: string; +} + +export default function XeblogPicture({ path, desc }: XeblogPicture) { + return ( + <figure> + <picture> + <source + type="image/avif" + srcset={`https://cdn.xeiaso.net/file/christine-static/${path}.avif`} + /> + <source + type="image/webp" + srcset={`https://cdn.xeiaso.net/file/christine-static/${path}.webp`} + /> + <img + alt={`An image of ${prompt}`} + loading="lazy" + src={`https://cdn.xeiaso.net/file/christine-static/${path}.jpg`} + /> + </picture> + {desc && <figcaption>{desc}</figcaption>} + </figure> + ); +} diff --git a/lume/src/_components/XeblogSlide.tsx b/lume/src/_components/XeblogSlide.tsx new file mode 100644 index 0000000..fe5c34e --- /dev/null +++ b/lume/src/_components/XeblogSlide.tsx @@ -0,0 +1,28 @@ +export interface XeblogSlideProps { + name: string; + essential?: boolean; + desc?: string; +} + +export default function XeblogSlide({ name, essential, desc }: XeblogSlideProps) { + return ( + <figure class={essential ? "xeblog-sides-essential" : "xeblog-slides-fluff"}> + <picture> + <source + type="image/avif" + srcset={`https://cdn.xeiaso.net/file/christine-static/${name}.avif`} + /> + <source + type="image/webp" + srcset={`https://cdn.xeiaso.net/file/christine-static/${name}.webp`} + /> + <img + alt={desc || `Slide ${name}`} + loading="lazy" + src={`https://cdn.xeiaso.net/file/christine-static/${name}.jpg`} + /> + </picture> + {desc && <figcaption>{desc}</figcaption>} + </figure> + ); +} diff --git a/lume/src/_components/XeblogSticker.tsx b/lume/src/_components/XeblogSticker.tsx new file mode 100644 index 0000000..713cad2 --- /dev/null +++ b/lume/src/_components/XeblogSticker.tsx @@ -0,0 +1,29 @@ +export interface XeblogStickerProps { + name: string; + mood: string; +} + +export default function XeblogSticker({ name, mood }: XeblogStickerProps) { + const nameLower = name.toLowerCase(); + name = name.replace(" ", "_"); + + return ( + <> + <picture> + <source + type="image/avif" + srcset={`https://cdn.xeiaso.net/file/christine-static/stickers/${nameLower}/${mood}.avif`} + /> + <source + type="image/webp" + srcset={`https://cdn.xeiaso.net/file/christine-static/stickers/${nameLower}/${mood}.webp`} + /> + <img + alt={`${name} is ${mood}`} + loading="lazy" + src={`https://cdn.xeiaso.net/file/christine-static/stickers/${nameLower}/${mood}.png`} + /> + </picture> + </> + ); +} diff --git a/lume/src/_components/XeblogToot.tsx b/lume/src/_components/XeblogToot.tsx new file mode 100644 index 0000000..3fd1f46 --- /dev/null +++ b/lume/src/_components/XeblogToot.tsx @@ -0,0 +1,63 @@ +import { sha256 } from "https://denopkg.com/chiefbiiko/sha256@v1.0.0/mod.ts"; + +export interface XeblogTootProps { + url: string; +} + +export default function XeblogToot({ url }: XeblogTootProps) { + const tootHash = sha256(url + ".json", "utf8", "hex"); + const tootJSON = (new TextDecoder("utf-8")).decode( + Deno.readFileSync(`./src/_data/toots/${tootHash}.json`), + ); + const toot = JSON.parse(tootJSON); + + const userHash = sha256(toot.attributedTo + ".json", "utf8", "hex"); + const userJSON = (new TextDecoder("utf-8")).decode( + Deno.readFileSync(`./src/_data/users/${userHash}.json`), + ); + const user = JSON.parse(userJSON); + + return ( + <> + <div class="bg-bg-soft dark:bg-bgDark-soft rounded-xl m-2 shadow-md max-w-lg"> + <div class="items-center flex flex-row text-xl px-4 font-bold max-h-[4rem]"> + <img class="rounded-full w-8 h-8" src={user.icon.url} /> + <span class="pl-2">{user.name}</span> + </div> + <div class="flex flex-row items-center px-4 py-2"> + <div class="flex flex-wrap px-5"> + <div class="px-2 py-1 m-1 bg-bg-2 dark:bg-bgDark-2 rounded-lg"> + {toot.published} + <div + dangerouslySetInnerHTML={{ __html: toot.content }} + > + </div> + </div> + </div> + </div> + <div class={`grid grid-cols-${toot.attachment.length > 1 ? 2 : 1} px-4`}> + {toot.attachment.map((attachment) => { + if (attachment.mediaType.startsWith("image/")) { + return ( + <div class="flex flex-row items-center justify-center m-1 max-w-xs"> + <a href={attachment.url} target="_blank"> + <img src={attachment.url} /> + </a> + </div> + ); + } else { + return ( + <div class="flex flex-row items-center justify-center m-1 max-w-xs"> + <a href={attachment.url}> + {attachment.name} + </a> + </div> + ); + } + })} + </div> + <a href={toot.url} className="pb-4 px-4" target="_blank">Link</a> + </div> + </> + ); +} diff --git a/lume/src/_components/XeblogVideo.tsx b/lume/src/_components/XeblogVideo.tsx new file mode 100644 index 0000000..01d271c --- /dev/null +++ b/lume/src/_components/XeblogVideo.tsx @@ -0,0 +1,42 @@ +// @jsxImportSource xeact +// @jsxRuntime automatic + +import Hls from "npm:hls.js"; + +function uuidv4() { + return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + ); +} + +export interface VideoProps { + path: string; +} + +export default function Video({ path }: VideoProps) { + const streamURL = + `https://cdn.xeiaso.net/file/christine-static/${path}/index.m3u8`; + const id = uuidv4(); + const video = ( + <video id={id} className="not-prose" style="width:100%" controls> + <source src={streamURL} type="application/vnd.apple.mpegurl" /> + <source + src="https://cdn.xeiaso.net/file/christine-static/blog/HLSBROKE.mp4" + type="video/mp4" + /> + </video> + ); + + const script = ( + <script type="module"> + {`import execFor from ${`'`}/js/hls.js${`'`}; + + execFor(${`'`}${id}${`'`}, ${`'`}${streamURL}${`'`});`} + </script> + ) + + return <> + {video} + {script} + </>; +} |
