aboutsummaryrefslogtreecommitdiff
path: root/lume/src/_components
diff options
context:
space:
mode:
authorXe Iaso <me@christine.website>2023-09-30 10:36:37 -0400
committerGitHub <noreply@github.com>2023-09-30 10:36:37 -0400
commitac6a3df0d18cc73524c0096d954a57d24cad5669 (patch)
tree81474177d730440657f490ae29892d62392251ea /lume/src/_components
parentcbdea8ba3fca9a663778af71f8df5965aeb6c090 (diff)
downloadxesite-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.tsx83
-rw-r--r--lume/src/_components/SignalboostCard.tsx43
-rw-r--r--lume/src/_components/XeblogConv.tsx36
-rw-r--r--lume/src/_components/XeblogHero.tsx40
-rw-r--r--lume/src/_components/XeblogPicture.tsx27
-rw-r--r--lume/src/_components/XeblogSlide.tsx28
-rw-r--r--lume/src/_components/XeblogSticker.tsx29
-rw-r--r--lume/src/_components/XeblogToot.tsx63
-rw-r--r--lume/src/_components/XeblogVideo.tsx42
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}
+ </>;
+}