diff options
| -rw-r--r-- | .vscode/settings.json | 3 | ||||
| -rw-r--r-- | README.md | 9 | ||||
| -rw-r--r-- | src/app.css | 95 | ||||
| -rw-r--r-- | src/app.html | 1 | ||||
| -rw-r--r-- | src/lib/blog/TableWrapper.svelte | 15 | ||||
| -rw-r--r-- | src/routes/blog/+page.svelte | 25 | ||||
| -rw-r--r-- | src/routes/blog/[id=int]/+page.svelte | 25 | ||||
| -rw-r--r-- | src/routes/blog/posts/test-post.svx | 105 | ||||
| -rw-r--r-- | static/spacegrotesk/SpaceGrotesk.woff2 | bin | 0 -> 48872 bytes | |||
| -rw-r--r-- | static/spacegrotesk/spacegrotesk.css | 7 |
10 files changed, 258 insertions, 27 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 6bb5266..7b1cffd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,4 +2,7 @@ "files.associations": { "*.css": "tailwindcss", }, + "files.exclude": { + "$": true + }, } @@ -2,11 +2,6 @@ css animation hellhole as i wanted to make noscript eyecandy -## forks +## design -if you fork this, note that - -1. you must make available the source of your fork to anyone who can access the built form (incl. those who can see it in their browse), as per AGPL-1.0-ONLY, and; -2. you really should update the repository URL in the package.json; the /upstream route (linked to in app.html) uses it to assist people in discovering the source if they have access to the binary form. - -a future version may embed the source into a blob in the binary form. +the design is quite inconsistent due to the main page being a demo, the blog being built around a bunch of trying to make a blog look minimal yet good, and the canaries page being a tool. diff --git a/src/app.css b/src/app.css index ae807c9..7dcddd4 100644 --- a/src/app.css +++ b/src/app.css @@ -13,7 +13,8 @@ --font-sans: InterVariable, Inter, "Noto Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", - "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; + --font-space-grotesk: "Space Grotesk", var(--font-sans), sans-serif; --font-bios: 'Ac437 IBM EGA 8x14', 'Hack', 'Courier New', 'Courier', 'monospace'; --font-grub: @@ -23,6 +24,43 @@ 'PxPlus IBM EGA 8x14', 'Hack', 'Courier New', 'Courier', 'monospace'; --font-genericmono: 'JetBrainsMono NF', 'Jetbrains Mono', 'JetBrains Mono', monospace; + --color-formatted-table-border: var(--color-neutral-900); + --color-formatted-table-background: var(--color-neutral-950); + --color-codeblock-border: var(--color-neutral-900); + --color-codeblock-background: var(--color-neutral-950); +} + +@utility afterunderline-* { + @apply relative; + &::before { + content: ''; + background: --value(--color-*); + @apply absolute top-full left-0 -mt-0.5 h-[0.2rem] w-full transition-all -z-10; + } +} +@utility afterunderline-hoverstate { + &::before { + @apply top-0 left-0 mt-0 h-full w-full; + } +} + +@utility formatted-table { + @apply relative overflow-x-auto shadow-xs rounded-xl border bg-formatted-table-background border-formatted-table-border; + table { + @apply w-full text-sm text-left rtl:text-right bg-formatted-table-background; + thead { + @apply text-sm border-b rounded-xl border-formatted-table-border; + } + tbody tr { + @apply not-last:border-b border-formatted-table-border; + } + th,td { + @apply px-6 py-3; + } + td > b:first-child:last-child { + @apply px-6 py-4 font-medium whitespace-nowrap; + } + } } @utility internal-header-active { @@ -35,8 +73,11 @@ } #postmd { @apply font-sans; + a { + @apply text-red-400 transition-all afterunderline-red-400 hover:afterunderline-hoverstate hover:text-white; + } h1 { - @apply first:font-bios first:text-5xl text-4xl mb-1.5 mt-2; + @apply text-4xl mb-1.5 mt-2; } h2 { @apply my-1.5 text-2xl; @@ -62,6 +103,9 @@ &:hover::after { @apply -ml-3 bg-gray-200/75; } + &:hover ~ p:is(p)::after { + @apply bg-gray-200/4; + } } h1 { &:not(:hover):has(~*:hover):not(:has(~h1~*:hover)) { @@ -94,6 +138,53 @@ p { @apply my-1; } + code { + @apply font-genericmono; + } + p code { + @apply bg-codeblock-background -my-1 p-1 rounded-lg; + } + pre { + @apply p-3 -mx-2 overflow-scroll bg-codeblock-background border border-codeblock-border rounded-lg transition-colors max-h-[min(75vh,38rem)]; + code { + .token { + @apply text-red-500; + } + &, + .token.builtin, + .token.interpolation { + @apply text-[#9CDCFE] selection:bg-[#9CDCFE] selection:text-black; + } + .token.operator { + @apply text-[#d4d4d4] selection:bg-[#d4d4d4] selection:text-black; + } + .token.class-name { + @apply text-[#4ec9b0] selection:bg-[#4ec9b0] selection:text-black; + } + .token.number { + @apply text-[#b5cea8] selection:bg-[#b5cea8] selection:text-black; + } + .token.comment { + @apply text-[#6a9955] selection:bg-[#6a9955] selection:text-black; + } + .token.keyword { + @apply text-[#c586c0] selection:bg-[#c586c0] selection:text-black; + } + .token.punctuation { + @apply text-[white] selection:bg-[white] selection:text-black; + } + .token.function { + @apply text-[#dcdcaa] selection:bg-[#dcdcaa] selection:text-black; + } + .token.string { + @apply text-[#ce9178] selection:bg-[#ce9178] selection:text-black; + } + .token.boolean, + .token.interpolation-punctuation { + @apply text-[#5293c9] selection:bg-[#5293c9] selection:text-black; + } + } + } } /* diff --git a/src/app.html b/src/app.html index 2d05f4f..aaf7ac2 100644 --- a/src/app.html +++ b/src/app.html @@ -21,6 +21,7 @@ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="icon" href="%sveltekit.assets%/favicon.webp" /> <link rel="stylesheet" href="%sveltekit.assets%/inter/inter.css" /> + <link rel="stylesheet" href="%sveltekit.assets%/spacegrotesk/spacegrotesk.css" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> %sveltekit.head% </head> diff --git a/src/lib/blog/TableWrapper.svelte b/src/lib/blog/TableWrapper.svelte new file mode 100644 index 0000000..ddf3d73 --- /dev/null +++ b/src/lib/blog/TableWrapper.svelte @@ -0,0 +1,15 @@ +<script lang="ts"> + import type { Snippet } from 'svelte'; + + const { + children, + maxwidth = false, + }: { + children: Snippet; + maxwidth?: boolean; + } = $props(); +</script> + +<div class={{ 'formatted-table my-1': true, 'w-max': !maxwidth }}> + {@render children()} +</div> diff --git a/src/routes/blog/+page.svelte b/src/routes/blog/+page.svelte index a817d44..89a3b3a 100644 --- a/src/routes/blog/+page.svelte +++ b/src/routes/blog/+page.svelte @@ -1,13 +1,26 @@ <script lang="ts"> + import { resolve } from '$app/paths'; import type { PageProps } from './$types'; let { data }: PageProps = $props(); </script> -<div class="font-mono"> - {#each Object.entries(data.posts) as [_filename, post]} - {JSON.stringify(post.metadata, (k, v) => - v instanceof Date ? v.toISOString() : v, - )} - {/each} +<div class="flex justify-center"> + <div class="max-w-2xl"> + <div class="font-genericmono"> + {#each Object.entries(data.posts) as [_filename, post]} + <a + href={resolve('/blog/[id=int]-[slug]', { + id: post.metadata.id.toString(), + slug: post.metadata.slug, + })} + class="text-red-400 transition-all afterunderline-red-400 hover:afterunderline-hoverstate hover:text-white" + >link</a + > + {JSON.stringify(post.metadata, (k, v) => + v instanceof Date ? v.toISOString() : v, + )} + {/each} + </div> + </div> </div> diff --git a/src/routes/blog/[id=int]/+page.svelte b/src/routes/blog/[id=int]/+page.svelte index 16fc586..b2f6807 100644 --- a/src/routes/blog/[id=int]/+page.svelte +++ b/src/routes/blog/[id=int]/+page.svelte @@ -10,19 +10,22 @@ let { data }: PageProps = $props(); + let route = $derived( + forceTrailingSlash( + resolve('/blog/[id=int]-[slug]', { + id: data.post.metadata.id.toString(), + slug: data.post.metadata.slug, + }), + ), + ); + onMount(() => { - tick().then(() => - replaceState( - forceTrailingSlash( - resolve('/blog/[id=int]-[slug]', { - id: data.post.metadata.id.toString(), - slug: data.post.metadata.slug, - }), - ), - page.state, - ), - ); + tick().then(() => replaceState(route, page.state)); }); </script> +<svelte:head> + <link rel="canonical" href={new URL(route, page.url).href} /> +</svelte:head> + <Post post={data.post} /> diff --git a/src/routes/blog/posts/test-post.svx b/src/routes/blog/posts/test-post.svx index a3f8248..71d8c21 100644 --- a/src/routes/blog/posts/test-post.svx +++ b/src/routes/blog/posts/test-post.svx @@ -10,9 +10,45 @@ created: "2026-01-14T01:25:14Z" updated: "2026-01-14T01:25:14Z" --- +<script lang="ts"> + import TableWrapper from '$/lib/blog/TableWrapper.svelte'; +</script> + # Test Post -this is a test blog post +this is a test blog post. + +## markdown + +[this is a link](https://en.wikipedia.org/wiki/Catgirl). + +*this is italic*, and _this is too_. __this is underscore bolded__, and **this is asterisk bolded**. + +`this is single backticked`. + +```js +console.log('and this is a codeblock'); +``` + +### unwrapped table + +| | awawa | test | +|-------|-------|-------| +| **a** | b | k | +| **z** | c | | +| **f** | d | f | + +### wrapped table + +<TableWrapper> + +| | awawa | test | +|-------|-------|-------| +| **a** | b | k | +| **z** | c | | +| **f** | d | f | + +</TableWrapper> # section testing @@ -79,3 +115,70 @@ Eaque cum dolores ut enim voluptatibus id velit velit. Iure eveniet alias dolori Autem ut nam sapiente et a magni. Qui maiores in qui earum. Veniam veniam omnis id architecto. Et optio et et molestias. Eaque cum dolores ut enim voluptatibus id velit velit. Iure eveniet alias doloribus. Ratione in in est aspernatur. + +## some code + +```ts +/* + Copyright (C) 2024-2026 memdmp + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by Affero, Inc., at version 1. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Affero General Public License for more details. + + You should have received a copy of the Affero General Public License along with this program. If not, see <https://spdx.org/licenses/AGPL-1.0-only>. +*/ +import { Animation, MultiObjectKeyframe } from '@memdmp/keyframegen'; +import { + biosStepInterval, + biosSteps, + getDelay, + login, + ttyLines, +} from './shared.ts'; +import fs from 'node:fs'; +import esbuild from 'esbuild'; +console.log('hi'); +const anim = new Animation(); +let ttyCtr = 0; +const stages = [ + anim.selector('.anmroot #bios'), + anim.selector('.anmroot #grub'), + anim.selector('.anmroot #grub-term'), + anim.selector('.anmroot #openrc'), + ...ttyLines.flatMap((v) => + v.kind === 'clear' ? [anim.selector('.anmroot #tty-' + ttyCtr++)] : [], + ), +]; +const handleSteps: Step[] = [ + // (n) => { + // toStage(0); + // anim.in(500, n); + // }, + ...biosStepHandlers, + ...grubStepHandlers, + ...openrcStepHandlers(1), + ...ttyStepHandlers, + (n) => { + const s = anim.selector('.anmroot #app .hidden-after-anim'); + s.style(visibleStyles); + anim._internal_timeline.now += 1; + s.style(hiddenStyles); + anim.in(1000, n); + }, +]; +fs.writeFileSync( + 'src/routes/anim.css', + `${comment} +${esbuild.buildSync({ + stdin: { + contents: `${exported} +${tail}`, + loader: 'css', + }, + write: false, + minify: false, + }).outputFiles![0].text + }`, +); +``` diff --git a/static/spacegrotesk/SpaceGrotesk.woff2 b/static/spacegrotesk/SpaceGrotesk.woff2 Binary files differnew file mode 100644 index 0000000..fce95d6 --- /dev/null +++ b/static/spacegrotesk/SpaceGrotesk.woff2 diff --git a/static/spacegrotesk/spacegrotesk.css b/static/spacegrotesk/spacegrotesk.css new file mode 100644 index 0000000..cd57e76 --- /dev/null +++ b/static/spacegrotesk/spacegrotesk.css @@ -0,0 +1,7 @@ +@font-face { + font-family: InterVariable; + font-style: normal; + font-weight: 300 700; + font-display: swap; + src: url("SpaceGrotesk.woff2") format("woff2"); +} |