Upgrade to Svelte 5, some regressions :(

This commit is contained in:
Jade Ellis
2024-11-24 02:54:18 +00:00
parent c36e68e73c
commit d5db048ec6
31 changed files with 1894 additions and 1903 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
podman build . -f packages/website/Dockerfile -t jade-website-frontend:latest; podman build . -f packages/website/Dockerfile -t jade-website-frontend:latest;
podman save --format oci-archive jade-website-frontend:latest | gzip | ssh core@176.126.240.240 -T "zcat > /opt/images/jade-website-frontend" podman save --format oci-archive jade-website-frontend:latest | gzip | ssh fedora@213.32.25.24 -T "zcat > /opt/images/jade-website-frontend"
+18 -18
View File
@@ -5,28 +5,28 @@ import { SENTRY_REPORT_URL } from './src/lib/config.js';
* @type {import("@sveltejs/kit").CspDirectives} * @type {import("@sveltejs/kit").CspDirectives}
*/ */
const cspDirectives = { const cspDirectives = {
'base-uri': ["'self'"], 'base-uri': ["self"],
'child-src': ["'self'", "blob:"], 'child-src': ["self", "blob:"],
'connect-src': ["'self'", "https://*.google-analytics.com", "https://" + SENTRY_HOST], 'connect-src': ["self", "https://*.google-analytics.com", "https://" + SENTRY_HOST],
// 'connect-src': ["'self'", 'ws://localhost:*', 'https://hcaptcha.com', 'https://*.hcaptcha.com'], // 'connect-src': ["self", 'ws://localhost:*', 'https://hcaptcha.com', 'https://*.hcaptcha.com'],
'img-src': ["'self'", 'data:', 'img-src': ["self", 'data:',
'https://*.googletagmanager.com'], 'https://*.googletagmanager.com'],
'font-src': ["'self'", 'data:'], 'font-src': ["self", 'data:'],
'form-action': ["'self'"], 'form-action': ["self"],
'frame-ancestors': ["'self'"], 'frame-ancestors': ["self"],
'frame-src': [ 'frame-src': [
"'self'", "self",
// "https://*.stripe.com", // "https://*.stripe.com",
// "https://*.facebook.com", // "https://*.facebook.com",
// "https://*.facebook.net", // "https://*.facebook.net",
// 'https://hcaptcha.com', // 'https://hcaptcha.com',
// 'https://*.hcaptcha.com', // 'https://*.hcaptcha.com',
], ],
'manifest-src': ["'self'"], 'manifest-src': ["self"],
'media-src': ["'self'", 'data:'], 'media-src': ["self", 'data:'],
'object-src': ["'none'"], 'object-src': ["none"],
'style-src': ["'self'", "'unsafe-inline'"], 'style-src': ["self", "unsafe-inline"],
// 'style-src': ["'self'", "'unsafe-inline'", 'https://hcaptcha.com', 'https://*.hcaptcha.com'], // 'style-src': ["self", "'unsafe-inline'", 'https://hcaptcha.com', 'https://*.hcaptcha.com'],
'default-src': [ 'default-src': [
'self', 'self',
...(rootDomain ? [rootDomain, `ws://${rootDomain}`] : []), ...(rootDomain ? [rootDomain, `ws://${rootDomain}`] : []),
@@ -42,8 +42,8 @@ const cspDirectives = {
// 'https://*.sentry.io', // 'https://*.sentry.io',
], ],
'script-src': [ 'script-src': [
'self', "self",
'unsafe-inline', // chrome suggestion "unsafe-inline", // chrome suggestion
'https://*.googletagmanager.com' 'https://*.googletagmanager.com'
// 'https://*.stripe.com', // 'https://*.stripe.com',
// 'https://*.facebook.com', // 'https://*.facebook.com',
@@ -53,9 +53,9 @@ const cspDirectives = {
// 'https://*.sentry.io', // 'https://*.sentry.io',
// 'https://polyfill.io', // 'https://polyfill.io',
], ],
'worker-src': ["'self'", "blob:"], 'worker-src': ["self", "blob:"],
// remove report-to & report-uri if you do not want to use Sentry reporting // remove report-to & report-uri if you do not want to use Sentry reporting
'report-to': ["'csp-endpoint'"], 'report-to': ["csp-endpoint"],
'report-uri': [ 'report-uri': [
SENTRY_REPORT_URL, SENTRY_REPORT_URL,
], ],
+31 -32
View File
@@ -10,25 +10,25 @@
"fix": "biome lint --write . && biome format --write . && biome check . --write" "fix": "biome lint --write . && biome format --write . && biome check . --write"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.0", "@biomejs/biome": "1.9.4",
"@bitmachina/highlighter": "1.0.0-alpha.6", "@bitmachina/highlighter": "1.0.0-alpha.6",
"@fontsource/fira-mono": "^5.0.14", "@fontsource/fira-mono": "^5.1.0",
"@json-feed-types/1_1": "^1.0.2", "@json-feed-types/1_1": "^1.0.2",
"@rollup/pluginutils": "^5.1.0", "@rollup/pluginutils": "^5.1.3",
"@sentry/esbuild-plugin": "^2.22.2", "@sentry/esbuild-plugin": "^2.22.6",
"@sveltejs/adapter-auto": "^3.2.4", "@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-node": "^5.2.2", "@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/kit": "^2.5.24", "@sveltejs/kit": "^2.8.2",
"@sveltejs/vite-plugin-svelte": "^3.1.2", "@sveltejs/vite-plugin-svelte": "^4.0.1",
"@types/fnv-plus": "^1.3.2", "@types/fnv-plus": "^1.3.2",
"@types/node": "^20.16.1", "@types/node": "^20.17.7",
"@types/polka": "^0.5.7", "@types/polka": "^0.5.7",
"@types/sharedworker": "^0.0.115", "@types/sharedworker": "^0.0.115",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"esbuild": "^0.23.1", "esbuild": "^0.23.1",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"glob": "^10.4.5", "glob": "^10.4.5",
"hast-util-to-string": "^3.0.0", "hast-util-to-string": "^3.0.1",
"just-camel-case": "^6.2.0", "just-camel-case": "^6.2.0",
"mdast-util-to-string": "^4.0.0", "mdast-util-to-string": "^4.0.0",
"mdsvex": "^0.11.2", "mdsvex": "^0.11.2",
@@ -43,56 +43,55 @@
"remark-math": "^3.0.1", "remark-math": "^3.0.1",
"remark-reading-time": "^2.0.1", "remark-reading-time": "^2.0.1",
"remark-wiki-link": "^0.0.4", "remark-wiki-link": "^0.0.4",
"rollup": "^4.21.0", "rollup": "^4.27.4",
"rollup-plugin-type-as-json-schema": "^0.2.6", "rollup-plugin-type-as-json-schema": "^0.2.6",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"schema-dts": "^1.1.2", "schema-dts": "^1.1.2",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"svelte": "^4.2.19", "svelte": "^5.2.7",
"svelte-check": "^3.8.6", "svelte-check": "^4.1.0",
"svelte-seo": "^1.6.1", "svelte-seo": "^1.6.1",
"sveltekit-html-minifier": "^1.0.3", "sveltekit-html-minifier": "^1.0.4",
"svgo": "^3.3.2", "svgo": "^3.3.2",
"tm-grammars": "^1.17.4", "tm-grammars": "^1.19.5",
"tslib": "^2.7.0", "tslib": "^2.8.1",
"typescript": "^5.5.4", "typescript": "^5.7.2",
"unified": "^11.0.5", "unified": "^11.0.5",
"unist-util-visit": "^5.0.0", "unist-util-visit": "^5.0.0",
"vite": "^5.4.2", "vite": "^5.4.2",
"vite-plugin-dynamic-import": "^1.5.0",
"vite-plugin-image-optimizer": "^1.1.8", "vite-plugin-image-optimizer": "^1.1.8",
"vite-plugin-thumbhash": "^0.1.6", "vite-plugin-thumbhash": "^0.1.6",
"vite-plugin-thumbhash-svg": "workspace:^" "vite-plugin-thumbhash-svg": "workspace:^"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@babel/preset-typescript": "^7.24.7", "@babel/preset-typescript": "^7.26.0",
"@codemirror/commands": "^6.6.0", "@codemirror/commands": "^6.7.1",
"@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-javascript": "^6.2.2",
"@codemirror/language": "^6.10.2", "@codemirror/language": "^6.10.3",
"@codemirror/lint": "^6.8.1", "@codemirror/lint": "^6.8.3",
"@codemirror/state": "^6.4.1", "@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.33.0", "@codemirror/view": "^6.35.0",
"@isaacs/ttlcache": "^1.4.1", "@isaacs/ttlcache": "^1.4.1",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.1",
"@octokit/types": "^13.5.0", "@octokit/types": "^13.6.1",
"@resvg/resvg-js": "^2.6.2", "@resvg/resvg-js": "^2.6.2",
"@sentry/sveltekit": "^8.26.0", "@sentry/sveltekit": "^8.40.0",
"@steeze-ui/svelte-icon": "^1.5.0", "@steeze-ui/svelte-icon": "^1.6.2",
"@tabler/icons-svelte": "^3.12.0", "@tabler/icons-svelte": "^3.22.0",
"@tusbar/cache-control": "^1.0.2", "@tusbar/cache-control": "^1.0.2",
"@uiw/codemirror-theme-github": "^4.23.0", "@uiw/codemirror-theme-github": "^4.23.6",
"Notes": "file:Notes-1.0.0.tgz", "Notes": "file:Notes-1.0.0.tgz",
"acorn": "^8.12.1", "acorn": "^8.14.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"fnv-plus": "^1.3.1", "fnv-plus": "^1.3.1",
"magic-string": "^0.30.11", "magic-string": "^0.30.13",
"octokit": "^3.2.1", "octokit": "^3.2.1",
"satori": "^0.10.14", "satori": "^0.10.14",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"super-sitemap": "^0.14.20", "super-sitemap": "^0.14.20",
"svelte-codemirror-editor": "^1.4.0", "svelte-codemirror-editor": "^1.4.1",
"terser": "^5.31.6", "terser": "^5.36.0",
"xmlbuilder2": "^3.1.1" "xmlbuilder2": "^3.1.1"
}, },
"targets": { "targets": {
+19 -9
View File
@@ -1,27 +1,37 @@
<script lang="ts"> <script lang="ts">
export let calloutType: string;
import { IconExclamationCircle } from "@tabler/icons-svelte"; import { IconExclamationCircle } from "@tabler/icons-svelte";
interface Props {
calloutType: string;
icon?: import('svelte').Snippet;
title?: import('svelte').Snippet;
body?: import('svelte').Snippet;
}
let {
calloutType,
icon,
title,
body
}: Props = $props();
</script> </script>
<div class="callout" data-callout={calloutType}> <div class="callout" data-callout={calloutType}>
<div class="callout-title"> <div class="callout-title">
{#if $$slots.icon} {#if icon}
<div class="callout-icon"><slot name="icon" /></div> <div class="callout-icon">{@render icon?.()}</div>
{:else} {:else}
<div class="callout-icon"><IconExclamationCircle /></div> <div class="callout-icon"><IconExclamationCircle /></div>
{/if} {/if}
<div class="callout-title-inner"> <div class="callout-title-inner">
<slot name="title" {#if title}{@render title()}{:else}{calloutType.replace(/\w\S*/g, function (txt) {
>{calloutType.replace(/\w\S*/g, function (txt) {
return ( return (
txt.charAt(0).toUpperCase() + txt.charAt(0).toUpperCase() +
txt.substring(1).toLowerCase() txt.substring(1).toLowerCase()
); );
})}</slot })}{/if}
>
</div> </div>
</div> </div>
{#if $$slots.body} {#if body}
<div class="callout-body"><slot name="body" /></div> <div class="callout-body">{@render body?.()}</div>
{/if} {/if}
</div> </div>
+55 -33
View File
@@ -1,4 +1,4 @@
<script lang="ts" context="module"> <script lang="ts" module>
type Attrs = { type Attrs = {
[name: string]: string; [name: string]: string;
}; };
@@ -6,6 +6,8 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
// look at https://github.com/sveltejs/learn.svelte.dev/blob/main/src/routes/tutorial/%5Bslug%5D/Editor.svelte // look at https://github.com/sveltejs/learn.svelte.dev/blob/main/src/routes/tutorial/%5Bslug%5D/Editor.svelte
// import { javascript } from "@codemirror/lang-javascript"; // import { javascript } from "@codemirror/lang-javascript";
import { onDestroy, onMount, createEventDispatcher } from "svelte"; import { onDestroy, onMount, createEventDispatcher } from "svelte";
@@ -21,27 +23,40 @@
import { type LanguageSupport } from "@codemirror/language"; import { type LanguageSupport } from "@codemirror/language";
import { get_base_extensions } from "./editorExtensions"; import { get_base_extensions } from "./editorExtensions";
export let value = "";
export let contentAttributes: AttrSource | null = null;
export let lang: LanguageSupport | null = null;
export let useTab = true;
export let tabSize = 2;
export let lineWrapping = false; interface Props {
export let editable = true; value?: string;
export let readonly = false; contentAttributes?: AttrSource | null;
export let placeholder: string | HTMLElement | null | undefined = undefined; lang?: LanguageSupport | null;
useTab?: boolean;
tabSize?: number;
lineWrapping?: boolean;
editable?: boolean;
readonly?: boolean;
placeholder?: string | HTMLElement | null | undefined;
header?: import('svelte').Snippet;
}
let {
value = $bindable(""),
contentAttributes = null,
lang = null,
useTab = true,
tabSize = 2,
lineWrapping = false,
editable = true,
readonly = false,
placeholder = undefined,
header
}: Props = $props();
const is_browser = typeof window !== "undefined"; const is_browser = typeof window !== "undefined";
let element: HTMLDivElement; let element: HTMLDivElement = $state();
let view: EditorView; let view: EditorView = $state();
$: view && update(value);
$: view && state_extensions && reconfigure();
$: on_change = handle_change;
let update_from_prop = false; let update_from_prop = false;
let update_from_state = false; let update_from_state = false;
@@ -52,19 +67,6 @@
let extensions: Extension[] = []; let extensions: Extension[] = [];
$: state_extensions = [
...get_base_extensions(
useTab,
tabSize,
lineWrapping,
placeholder,
editable,
readonly,
lang,
),
$theme == "dark" ? githubDark : githubLight,
...extensions,
];
if (langPlugin !== null) extensions.push(langPlugin); if (langPlugin !== null) extensions.push(langPlugin);
if (contentAttributes !== null) if (contentAttributes !== null)
@@ -165,20 +167,40 @@
// lintGutter(), // lintGutter(),
// linter(esLint(new eslint.Linter(), config)), // linter(esLint(new eslint.Linter(), config)),
run(() => {
view && update(value);
});
let state_extensions = $derived([
...get_base_extensions(
useTab,
tabSize,
lineWrapping,
placeholder,
editable,
readonly,
lang,
),
$theme == "dark" ? githubDark : githubLight,
...extensions,
]);
run(() => {
view && state_extensions && reconfigure();
});
let on_change = $derived(handle_change);
</script> </script>
<div class="editor-wrapper card" class:no-header={!$$slots.header}> <div class="editor-wrapper card" class:no-header={!header}>
{#if $$slots.header} {#if header}
<div class="header"> <div class="header">
<slot name="header" /> {@render header?.()}
</div> </div>
{/if} {/if}
{#if is_browser} {#if is_browser}
<div class="codemirror-wrapper editor" bind:this={element} /> <div class="codemirror-wrapper editor" bind:this={element}></div>
{:else} {:else}
<div class="scm-waiting editor"> <div class="scm-waiting editor">
<div class="scm-waiting__loading scm-loading"> <div class="scm-waiting__loading scm-loading">
<div class="scm-loading__spinner" /> <div class="scm-loading__spinner"></div>
<p class="scm-loading__text">Loading editor...</p> <p class="scm-loading__text">Loading editor...</p>
</div> </div>
<div class="cm-editor"><pre class="scm-pre">{value}</pre></div> <div class="cm-editor"><pre class="scm-pre">{value}</pre></div>
+1 -1
View File
@@ -51,7 +51,7 @@
<span class="site-name">Jade Ellis</span> <span class="site-name">Jade Ellis</span>
</a> </a>
<button on:click={sendFeedback} class="feedback-button">Report a bug</button> <button onclick={sendFeedback} class="feedback-button">Report a bug</button>
</div> </div>
{#each Object.entries(links) as [title, inner_links]} {#each Object.entries(links) as [title, inner_links]}
@@ -1,8 +1,12 @@
<script lang="ts"> <script lang="ts">
import type { Endpoints } from "@octokit/types"; import type { Endpoints } from "@octokit/types";
export let releaseData: Endpoints["GET /repos/{owner}/{repo}/releases/latest"]["response"]["data"];
import { browser } from "$app/environment"; import { browser } from "$app/environment";
interface Props {
releaseData: Endpoints["GET /repos/{owner}/{repo}/releases/latest"]["response"]["data"];
}
let { releaseData }: Props = $props();
// console.log(releaseData); // console.log(releaseData);
</script> </script>
+5 -3
View File
@@ -1,7 +1,9 @@
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import url from "./logo.svg?url"; import url from "./logo.svg?url";
import { SITE_URL } from "$lib/metadata"; import { SITE_URL } from "$lib/metadata";
let logo: HTMLDivElement; let logo: HTMLDivElement = $state();
let wiggleCount = 0; let wiggleCount = 0;
function wiggle() { function wiggle() {
wiggleCount++; wiggleCount++;
@@ -18,8 +20,8 @@
<div class="hero card edge h-card"> <div class="hero card edge h-card">
<div <div
class="logo" class="logo"
on:click|preventDefault={wiggle} onclick={preventDefault(wiggle)}
on:animationiteration={wiggleIteration} onanimationiteration={wiggleIteration}
bind:this={logo} bind:this={logo}
> >
<a href={SITE_URL} class="u-url u-uid" rel="me" <a href={SITE_URL} class="u-url u-uid" rel="me"
+8 -5
View File
@@ -1,15 +1,18 @@
<script lang="ts"> <script lang="ts">
import TocItem from "./TocItem.svelte"; import TocItem from "./TocItem.svelte";
const className = "toc";
type FlatHeading = { level: number; title: string }; type FlatHeading = { level: number; title: string };
export let headings: nestedListNode[]; interface Props {
headings: nestedListNode[];
class?: string;
}
let { headings }: Props = $props();
// creates a `class` property, even // creates a `class` property, even
// though it is a reserved word // though it is a reserved word
export { className as class };
export const listType = "ul"; export const listType = "ul";
let open = false; let open = $state(false);
/** @type {import('./$types').Snapshot<string>} */ /** @type {import('./$types').Snapshot<string>} */
export const snapshot = { export const snapshot = {
capture: () => open, capture: () => open,
@@ -20,7 +23,7 @@
</script> </script>
{#if headings?.length > 0} {#if headings?.length > 0}
<aside class={className}> <aside class="toc">
<details bind:open> <details bind:open>
<summary accesskey="c" title="(Alt + C)">Table of Contents</summary> <summary accesskey="c" title="(Alt + C)">Table of Contents</summary>
<div class="inner"> <div class="inner">
+7 -2
View File
@@ -1,6 +1,11 @@
<script lang="ts"> <script lang="ts">
import TocItem from './TocItem.svelte';
export let node: nestedListNode; interface Props {
node: nestedListNode;
}
let { node }: Props = $props();
export const listType = "ul" export const listType = "ul"
</script> </script>
@@ -9,7 +14,7 @@
{#if node.children.length > 0} {#if node.children.length > 0}
<svelte:element this={listType} class="toc-level {"toc-level-" + node.children[0].level}"> <svelte:element this={listType} class="toc-level {"toc-level-" + node.children[0].level}">
{#each node.children as nodes} {#each node.children as nodes}
<svelte:self node={nodes} {listType} /> <TocItem node={nodes} {listType} />
{/each} {/each}
</svelte:element> </svelte:element>
{/if} {/if}
+19
View File
@@ -0,0 +1,19 @@
// import fontBoldUrl from './Inter-Bold.ttf?url';
// import fontRegularUrl from './Inter-Regular.ttf?url';
// This is a hack
// Get the URL that the server is running on
// console.log(import.meta.env)
// let base = (import.meta.env.VITE_DOMAIN || "http://localhost:5173") + import.meta.env.BASE_URL;
// if (base?.endsWith('/')) {
// base = base.slice(0, -1);
// }
// // console.log(base)
// const fontBoldData = await (await fetch(base + fontBoldUrl)).arrayBuffer();
// const fontRegularData = await (await fetch(base + fontRegularUrl)).arrayBuffer();
// import { readFileSync } from 'fs';
// const fontBoldUrl = new URL('./Inter-Bold.ttf', import.meta.url).href
// const fontBoldData = readFileSync(fontBoldUrl);
// const fontRegularUrl = new URL('./Inter-Regular.ttf', import.meta.url).href
// const fontRegularData = readFileSync(fontRegularUrl);
// console.log(fontBoldUrl)
// export { fontBoldData, fontRegularData };
@@ -1,23 +1,33 @@
<script lang="ts"> <script lang="ts">
export let src; interface Props {
export let alt; src: any;
export let title; alt: any;
export let thumb; title: any;
thumb: any;
class?: string;
}
let {
src,
alt,
title,
thumb,
class: className
}: Props = $props();
// export let align // export let align
// export let small: boolean; // export let small: boolean;
// console.log("imgcmp", thumb); // console.log("imgcmp", thumb);
const className = ""; let loaded = $state(false)
export { className as class };
let loaded = false
// console.log(thumb) // console.log(thumb)
// import _PastedImage20240716123726Png from "./Pasted%20image%2020240716123726.png?meta"; // import _PastedImage20240716123726Png from "./Pasted%20image%2020240716123726.png?meta";
</script> </script>
<!-- <figure class={className}> -->
<figure class={className}> <!-- Svelte 5 hydration bug means we can't nest image inside figure -->
<img <img
{src} {src}
{alt} {alt}
{title} {title}
class={className}
width={thumb?.originalWidth} width={thumb?.originalWidth}
height={thumb?.originalHeight} height={thumb?.originalHeight}
style:background-image={loaded ? "none" : `url('${thumb?.thumbSrc}')`} style:background-image={loaded ? "none" : `url('${thumb?.thumbSrc}')`}
@@ -25,10 +35,10 @@
decoding="async" decoding="async"
style:--aspect-ratio={thumb?.originalWidth / thumb?.originalHeight} style:--aspect-ratio={thumb?.originalWidth / thumb?.originalHeight}
/> />
{#if title} <!-- {#if title}
<figcaption>{title}</figcaption> <figcaption>{title}</figcaption>
{/if} {/if} -->
</figure> <!-- </figure> -->
<!-- {:else} <!-- {:else}
<img <img
{src} {src}
@@ -1,7 +1,12 @@
<script context="module"> <script>
/** @type {{children?: import('svelte').Snippet}} */
let { children } = $props();
</script>
<script module>
import img from "$lib/htmlComponents/img.svelte"; import img from "$lib/htmlComponents/img.svelte";
import Callout from "$lib/Callout.svelte"; import Callout from "$lib/Callout.svelte";
export { img, Callout }; export { img, Callout };
</script> </script>
<slot /> {@render children?.()}
@@ -15,20 +15,24 @@
const minify = init().minify; const minify = init().minify;
let value = ""; let value = $state("");
let output = ""; let output = $state("");
let options: Config = {}; let options: Config = $state({});
async function process(str: string) { async function process(str: string) {
options = await parseMeta(str); options = await parseMeta(str);
const res = await bookmarkify(str, options, minify); const res = await bookmarkify(str, options, minify);
if (typeof res == "string") { if (typeof res == "string") {
output = res; return res;
} }
} }
const contentAttributes = { "aria-label": "Bookmarklet editor" }; const contentAttributes = { "aria-label": "Bookmarklet editor" };
$: progress = process(value); let computation = $derived(process(value));
$effect(async () => {
output = await computation;
});
</script> </script>
<SvelteSeo <SvelteSeo
@@ -45,11 +49,13 @@
lang={javascript()} lang={javascript()}
{contentAttributes} {contentAttributes}
> >
<div slot="header" class="code-header">Input</div> {#snippet header()}
<div class="code-header">Input</div>
{/snippet}
</Editor> </Editor>
<h2>Output</h2> <h2>Output</h2>
{#await progress} {#await computation}
<p>...waiting</p> <p>...waiting</p>
{:catch error} {:catch error}
<p style="color: red">{error.message}</p> <p style="color: red">{error.message}</p>
@@ -13,16 +13,15 @@
const minify = init().minify; const minify = init().minify;
let value = ""; let value = $state("");
let output = ""; let output = $state("");
async function process(str: string) { async function process(str: string): string {
if (value === "") { if (value === "") {
output = ""; return "";
return;
} }
const result = await minify(str); const result = await minify(str);
if (typeof result.code == "string") { if (typeof result.code == "string") {
output = result.code; return result.code;
} else { } else {
console.error(result); console.error(result);
} }
@@ -30,7 +29,11 @@
const contentAttributes = { "aria-label": "Javascript editor" }; const contentAttributes = { "aria-label": "Javascript editor" };
$: progress = process(value); let computation = $derived(process(value));
$effect(async () => {
output = await computation;
});
</script> </script>
<SvelteSeo <SvelteSeo
@@ -47,11 +50,13 @@
lang={javascript()} lang={javascript()}
{contentAttributes} {contentAttributes}
> >
<div slot="header" class="code-header">Input</div> {#snippet header()}
<div class="code-header">Input</div>
{/snippet}
</Editor> </Editor>
<h2>Output</h2> <h2>Output</h2>
{#await progress} {#await computation}
<p>...waiting</p> <p>...waiting</p>
{:catch error} {:catch error}
<p style="color: red">{error.message}</p> <p style="color: red">{error.message}</p>
+4 -4
View File
@@ -7,8 +7,8 @@
const { status, error } = $page; const { status, error } = $page;
const message = error?.message || "Hmm"; const message = error?.message || "Hmm";
const title = `${status}: ${message}`; const title = `${status}: ${message}`;
let sentryElement: HTMLDivElement; let sentryElement: HTMLDivElement = $state();
let openForm = () => {}; let openForm = $state(() => {});
const online = typeof navigator !== 'undefined' ? navigator.onLine : true; const online = typeof navigator !== 'undefined' ? navigator.onLine : true;
onMount(async () => { onMount(async () => {
const feedback = Sentry.getFeedback({ const feedback = Sentry.getFeedback({
@@ -55,8 +55,8 @@
<p>Reload the page once you've found the internet.</p> <p>Reload the page once you've found the internet.</p>
{/if} {/if}
<p> <p>
<button on:click={openForm}>Send Feedback</button> <button onclick={openForm}>Send Feedback</button>
<button class="secondary" on:click={() => window.location.reload()} <button class="secondary" onclick={() => window.location.reload()}
>Reload</button >Reload</button
> >
</p> </p>
+6 -1
View File
@@ -5,6 +5,11 @@
import Nav from "$lib/Nav.svelte"; import Nav from "$lib/Nav.svelte";
import Footer from "$lib/Footer.svelte"; import Footer from "$lib/Footer.svelte";
import { SITE_TITLE } from "$lib/metadata" import { SITE_TITLE } from "$lib/metadata"
interface Props {
children?: import('svelte').Snippet;
}
let { children }: Props = $props();
</script> </script>
<svelte:head> <svelte:head>
<Favicons /> <Favicons />
@@ -12,5 +17,5 @@
<meta property="og:site_name" content={SITE_TITLE}> <meta property="og:site_name" content={SITE_TITLE}>
</svelte:head> </svelte:head>
<Nav /> <Nav />
<slot /> {@render children?.()}
<Footer /> <Footer />
+1 -1
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import Hero from "$lib/Hero.svelte"; import Hero from "$lib/Hero.svelte";
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
import Homepage from "Notes/Website Homepage.md"; import Homepage from "$notes/Website Homepage.md";
import { SITE_URL, SITE_TITLE } from "$lib/metadata"; import { SITE_URL, SITE_TITLE } from "$lib/metadata";
import { onMount } from "svelte"; import { onMount } from "svelte";
</script> </script>
@@ -4,7 +4,11 @@
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
import type { WithContext, Thing } from "schema-dts"; import type { WithContext, Thing } from "schema-dts";
export let data; interface Props {
data: any;
}
let { data }: Props = $props();
const { pages } = data; const { pages } = data;
const jsonLd = { const jsonLd = {
@@ -1,20 +1,21 @@
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
// https://github.com/mattjennings/sveltekit-blog-template/blob/main/src/routes/post/%5Bslug%5D/%2Bpage.svelte // https://github.com/mattjennings/sveltekit-blog-template/blob/main/src/routes/post/%5Bslug%5D/%2Bpage.svelte
import { browser } from "$app/environment"; import { browser } from "$app/environment";
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
export let data;
import { SITE_URL, SITE_TITLE } from "$lib/metadata"; import { SITE_URL, SITE_TITLE } from "$lib/metadata";
import Toc from "$lib/Toc.svelte"; import Toc from "$lib/Toc.svelte";
import type { WithContext, Thing } from "schema-dts"; import type { WithContext, Thing } from "schema-dts";
import pfpUrl from "$lib/logo.svg?url"; import pfpUrl from "$lib/logo.svg?url";
import { gtag } from "$lib/analytics.js"; import { gtag } from "$lib/analytics.js";
// let GhReleasesDownload: Promise<any>; interface Props {
// if (data.ghReleaseData) { data: any;
// GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default) }
// }
$: canonical = SITE_URL + "/blog/" + data.post.canonical;
let { data }: Props = $props();
// console.log(data)
function calcOgURL( function calcOgURL(
slug: string, slug: string,
date: string, date: string,
@@ -33,10 +34,6 @@
return url; return url;
} }
$: webShareAPISupported = browser && typeof navigator.share !== "undefined";
// let webShareAPISupported = true;
$: handleWebShare;
const handleWebShare = async () => { const handleWebShare = async () => {
try { try {
const url = new URL(canonical); const url = new URL(canonical);
@@ -69,7 +66,21 @@
fediverse: "@JadedBlueEyes@tech.lgbt", fediverse: "@JadedBlueEyes@tech.lgbt",
image: pfpUrl, image: pfpUrl,
}; };
$: jsonLd = { // let GhReleasesDownload: Promise<any>;
// if (data.ghReleaseData) {
// GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default)
// }
let canonical = $derived(SITE_URL + "/blog/" + data.post.canonical);
let webShareAPISupported;
run(() => {
webShareAPISupported = browser && typeof navigator.share !== "undefined";
});
// let webShareAPISupported = true;
run(() => {
handleWebShare;
});
let jsonLd = $derived({
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "WebPage", "@type": "WebPage",
breadcrumb: { breadcrumb: {
@@ -118,7 +129,7 @@
name: "Jade's Blog", name: "Jade's Blog",
}, },
}, },
} as WithContext<Thing>; } as WithContext<Thing>);
</script> </script>
<svelte:head> <svelte:head>
@@ -199,7 +210,7 @@
> >
· <span class="reading-time ib">{data.post.readingTime.text}</span> · <span class="reading-time ib">{data.post.readingTime.text}</span>
{#if webShareAPISupported} {#if webShareAPISupported}
· <button class="link" on:click={handleWebShare}>Share</button> · <button class="link" onclick={handleWebShare}>Share</button>
{/if} {/if}
</aside> </aside>
<Toc headings={data.post.headings} /> <Toc headings={data.post.headings} />
@@ -210,7 +221,7 @@
{/await} --> {/await} -->
<div class="e-content"> <div class="e-content">
<svelte:component this={data.component} /> <data.component />
</div> </div>
</article> </article>
</main> </main>
@@ -11,10 +11,9 @@ export async function load({ data, params }) {
// console.log(data) // console.log(data)
const component = const component =
// await import(data.page.filepath) // await import(data.page.filepath)
await import("Notes/Blogs/" + data.page.filepath.name + ".md") await import(`$notes/Blogs/${data.page.filepath.name}.md`)
// console.log(data.page.filepath) // console.log(data.page.filepath)
return { return {
post: data.page, post: data.page,
component: component.default component: component.default
@@ -1,6 +1,6 @@
import { pages } from '../posts' import { pages } from '../posts'
import { error, type RequestHandler } from '@sveltejs/kit' import { error, type RequestHandler } from '@sveltejs/kit'
export const prerender = false;
import satori from 'satori'; import satori from 'satori';
import { Resvg } from '@resvg/resvg-js'; import { Resvg } from '@resvg/resvg-js';
import { SITE_DOMAIN } from '$lib/metadata'; import { SITE_DOMAIN } from '$lib/metadata';
@@ -8,13 +8,18 @@ import TTLCache from "@isaacs/ttlcache";
import { format } from "@tusbar/cache-control"; import { format } from "@tusbar/cache-control";
const cache = new TTLCache({ max: 10000, ttl: 1000 * 60 * 60 }) const cache = new TTLCache({ max: 10000, ttl: 1000 * 60 * 60 })
import fnv from "fnv-plus" import fnv from "fnv-plus"
import { readFileSync } from 'fs';
// const fontFile = await fetch('https://og-playground.vercel.app/inter-latin-ext-700-normal.woff'); // const fontFile = await fetch('https://og-playground.vercel.app/inter-latin-ext-700-normal.woff');
const fontBoldUrl = new URL('./Inter-Bold.ttf', import.meta.url)
const fontBoldData = readFileSync(fontBoldUrl); // import fontBoldString from '$lib/assets/Inter-Bold.ttf?raw';
const fontRegularUrl = new URL('./Inter-Regular.ttf', import.meta.url) // import fontRegularString from '$lib/assets/Inter-Regular.ttf?raw';
const fontRegularData = readFileSync(fontRegularUrl); // const fontBoldData = Buffer.from(fontBoldString);
// const fontRegularData = Buffer.from(fontRegularString);
// import { fontBoldData, fontRegularData } from '$lib/assets/fonts';
// Hacky hack because sveltekit
const fontBoldData = await (await fetch("https://config-servers-1.ellis.link/Inter-Bold.ttf")).arrayBuffer();
const fontRegularData = await (await fetch("https://config-servers-1.ellis.link/Inter-Regular.ttf")).arrayBuffer();
const defaultWidth = 800; const defaultWidth = 800;
const defaultRatio = 0.5 const defaultRatio = 0.5
+6 -5
View File
@@ -65,18 +65,20 @@ if (browser) {
// previous: allPosts[index + 1] // previous: allPosts[index + 1]
// })) // }))
const dateRegex = /^((?<year>\d{4})-(?<month>[0][1-9]|1[0-2])-(?<day>[0][1-9]|[1-2]\d|3[01]))\s*/ const dateRegex = /^((?<year>\d{4})-(?<month>[0][1-9]|1[0-2])-(?<day>[0][1-9]|[1-2]\d|3[01]))\s*/
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Blogs/*.md', { eager: true }))
.map(([filepath, post]) => { export const pages = (await Promise.all(Object.entries(import.meta.glob('$notes/Blogs/*.md', { eager: true}))
.map(async ([filepath, post]) => {
const path = parse(filepath); const path = parse(filepath);
const title = path.name.replace(dateRegex, "") const title = path.name.replace(dateRegex, "")
// @ts-ignore // @ts-ignore
// let {year, month, day}: { year: string, month: string, day: string } = path.name.match(dateRegex)?.groups; // let {year, month, day}: { year: string, month: string, day: strisng } = path.name.match(dateRegex)?.groups;
// console.log(year, month, day) // console.log(year, month, day)
const date = path.name.match(dateRegex)[1]; const date = path.name.match(dateRegex)[1];
const datePath = date.replaceAll("-", "/") const datePath = date.replaceAll("-", "/")
const slug = slugify(title, { lower: true }) const slug = slugify(title, { lower: true })
return { return {
title, title,
date, date,
@@ -85,10 +87,9 @@ export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Blogs/
...post.metadata, ...post.metadata,
slug, slug,
// filepath: relative(import.meta.dirname, filepath)
filepath: path filepath: path
} }
}) })))
// sort by date // sort by date
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
// Get all posts and add metadata // Get all posts and add metadata
@@ -2,9 +2,13 @@
// https://github.com/mattjennings/sveltekit-blog-template/blob/main/src/routes/post/%5Bslug%5D/%2Bpage.svelte // https://github.com/mattjennings/sveltekit-blog-template/blob/main/src/routes/post/%5Bslug%5D/%2Bpage.svelte
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
export let data;
import { SITE_URL } from "$lib/metadata"; import { SITE_URL } from "$lib/metadata";
import GhReleasesDownload from "$lib/GhReleasesDownload.svelte"; import GhReleasesDownload from "$lib/GhReleasesDownload.svelte";
interface Props {
data: any;
}
let { data }: Props = $props();
// let GhReleasesDownload: Promise<any>; // let GhReleasesDownload: Promise<any>;
// if (data.ghReleaseData) { // if (data.ghReleaseData) {
// GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default) // GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default)
@@ -31,5 +35,5 @@
<GhReleasesDownload releaseData={data.ghReleaseData} /> <GhReleasesDownload releaseData={data.ghReleaseData} />
{/if} {/if}
<svelte:component this={data.component} /> <data.component />
</main> </main>
@@ -11,7 +11,7 @@ export async function load({ data }) {
// load the markdown file based on slug // load the markdown file based on slug
const component = const component =
// await import(data.page.filepath) // await import(data.page.filepath)
await import("Notes/Projects/" + data.page.filepath.name + ".md") await import(`$notes/Projects/${data.page.filepath.name}.md`)
// console.log(data.page.filepath) // console.log(data.page.filepath)
@@ -9,7 +9,7 @@ if (browser) {
throw new Error(`posts can only be imported server-side`) throw new Error(`posts can only be imported server-side`)
} }
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true })) export const pages = Object.entries(import.meta.glob('$notes/Projects/*.md', { eager: true }))
.map(([filepath, post]) => { .map(([filepath, post]) => {
const path = parse(filepath); const path = parse(filepath);
const slug = slugify(path.name, { lower: true }) const slug = slugify(path.name, { lower: true })
@@ -7,7 +7,7 @@ import slugify from 'slugify';
import { parse, format } from "node:path"; import { parse, format } from "node:path";
import { pages as blogPosts } from "../blog/posts" import { pages as blogPosts } from "../blog/posts"
const projects = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true })) const projects = Object.entries(import.meta.glob('$notes/Projects/*.md', { eager: true }))
.map(([filepath, post]) => { .map(([filepath, post]) => {
return parse(filepath) return parse(filepath)
}) })
+9 -9
View File
@@ -2,7 +2,7 @@ import { sentrySvelteKit } from "@sentry/sveltekit";
import { sveltekit } from "@sveltejs/kit/vite"; import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig, type PluginOption } from "vite"; import { defineConfig, type PluginOption } from "vite";
import { ViteImageOptimizer } from "vite-plugin-image-optimizer"; import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
import dynamicImport from 'vite-plugin-dynamic-import' // import dynamicImport from 'vite-plugin-dynamic-import'
import typeAsJsonSchemaPlugin from "rollup-plugin-type-as-json-schema"; import typeAsJsonSchemaPlugin from "rollup-plugin-type-as-json-schema";
// import dynamicImportVars from '@rollup/plugin-dynamic-import-vars'; // import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
import path from "node:path"; import path from "node:path";
@@ -104,7 +104,7 @@ import { visualizer } from "rollup-plugin-visualizer";
export default defineConfig({ export default defineConfig({
resolve: { resolve: {
alias: { alias: {
"Notes": path.join(__dirname, "node_modules/Notes") "$notes": path.join(__dirname, "node_modules/Notes")
} }
}, },
plugins: [ plugins: [
@@ -146,13 +146,13 @@ export default defineConfig({
// }), // }),
// mdsvex_transform(), // mdsvex_transform(),
sveltekit(), sveltekit(),
dynamicImport({ // dynamicImport({
filter(id) { // filter(id) {
if (id.includes('node_modules/Notes')) { // if (id.includes('node_modules/Notes')) {
return true // return true
} // }
} // }
}), // }),
// blurhash_transform(), // blurhash_transform(),
thumbHash({ thumbHash({
// exclude: [/\.svg/] // exclude: [/\.svg/]
+1590 -1718
View File
File diff suppressed because it is too large Load Diff