feat: moved content back into this repository, and moved private content out

This commit is contained in:
Lewis Wynne 2026-03-23 23:47:40 +00:00
parent 7fb4035f31
commit 63a079deb1
14 changed files with 62 additions and 132 deletions

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "www/src/content"]
path = www/src/content
url = git@github.com:Llywelwyn/wynne.rs-content.git

@ -1 +0,0 @@
Subproject commit 01cb4bd1a06375ff1bdc0bc4e64024a1041fd908

View file

@ -14,16 +14,6 @@ const md = defineCollection({
}) })
}); });
const dnd = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/dnd' }),
schema: z.object({
title: z.string(),
pinned: z.boolean().optional(),
category: z.string().optional(),
related: z.array(z.string()).optional(),
})
});
const bookmarks = defineCollection({ const bookmarks = defineCollection({
loader: file('./src/content/bookmarks.yaml', { loader: file('./src/content/bookmarks.yaml', {
parser: (text) => { parser: (text) => {
@ -38,4 +28,4 @@ const bookmarks = defineCollection({
}) })
}); });
export const collections = { md, dnd, bookmarks }; export const collections = { md, bookmarks };

View file

@ -0,0 +1,19 @@
- date: 2026-01-23
title: personal websites with a /now page
url: https://nownownow.com/
- date: 2025-04-18
title: Accessible UK Train Timetables
url: https://traintimes.org.uk/
- date: 2024-05-20
title: Game Programming Patterns
url: https://gameprogrammingpatterns.com/contents.html
- date: 2023-09-04
title: Procedural Map Generation Techniques
url: https://www.youtube.com/watch?v=TlLIOgWYVpI
- date: 2023-09-04
title: Procedural Level Design in Brogue and Beyond
url: https://www.youtube.com/watch?v=Uo9-IcHhq_w

View file

@ -0,0 +1,33 @@
---
title: hello world
pinned: true
---
i've always kept my projects online and public, and i've always had some sort of homepage. it was originally bebo, then some sites i made through school, then facebook.
:right[i liked farmville but otherwise didnt use facebook much]
my next site after that was one that i kept updated for years. but every time i updated it, i also tacked on features i liked, and then ultimately it became a mess of ideas. it was never supposed to be well-engineered, but i like clean code and i ended up too busy fixing things to do anything new or interesting
so i deleted everything i could think of that was even remotely fancy and made this
there's one bit of javascript on this site, and that's the [/random](https://wynne.rs/random/) route to take you to a random page
everything else is mostly vanilla. there's no pagination or searching, though i did add categorisation
plain text files are hosted and indexed at [/txt](https://wynne.rs/txt/),
longer form things are in categories at [/md](https://wynne.rs/md/),
there are [/bookmarks](https://wynne.rs/bookmarks/) for things that link elsewhere,
and there's a [/guestbook](https://wynne.rs/guestbook/) that used to have placeable stickers and selectable card backgrounds, and hand-drawn art and pagination, and a gallery section where people could paint pictures, and... is now just a list of names and the text that was left, which i prefer
:right[the old guestbook still exists; its just not the one i link anymore]
in the end, everything on this site is visible straight from the index page in one massive list, ordered by date, with pinned posts at the top of their respective category.
and that's it. i don't need anything else to archive things i care about
cheers,
lewis x

View file

@ -1,34 +0,0 @@
import type { CollectionEntry } from 'astro:content';
import { getSlug, resolveRelatedPosts } from './md';
type DndPost = CollectionEntry<'dnd'>;
export { getSlug, resolveRelatedPosts };
export function organizePostsByCategory(posts: DndPost[]): {
grouped: Record<string, DndPost[]>;
categories: string[];
} {
const grouped = posts.reduce((acc, post) => {
const category = post.data.category ?? 'dnd';
if (!acc[category]) acc[category] = [];
acc[category].push(post);
return acc;
}, {} as Record<string, DndPost[]>);
const categories = Object.keys(grouped).sort((a, b) => {
if (a === 'dnd') return -1;
if (b === 'dnd') return 1;
return a.localeCompare(b);
});
for (const category of categories) {
grouped[category] = grouped[category].slice().sort((a, b) => {
if (a.data.pinned && !b.data.pinned) return -1;
if (!a.data.pinned && b.data.pinned) return 1;
return a.data.title.localeCompare(b.data.title);
});
}
return { grouped, categories };
}

View file

@ -1,8 +1,8 @@
--- ---
import { getCollection, render } from 'astro:content'; import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Layout.astro'; import Layout from '../layouts/Layout.astro';
import { formatDate, formatListItem } from '../../lib/format'; import { formatDate, formatListItem } from '../lib/format';
import { getSlug, enrichPostWithDates, enrichPostsWithDates, resolveRelatedPosts } from '../../lib/md'; import { getSlug, enrichPostWithDates, enrichPostsWithDates, resolveRelatedPosts } from '../lib/md';
export async function getStaticPaths() { export async function getStaticPaths() {
const rawPosts = await getCollection('md'); const rawPosts = await getCollection('md');
@ -27,7 +27,7 @@ const related = post.data.related ? resolveRelatedPosts(post.data.related, allPo
{related.length > 0 && ( {related.length > 0 && (
<details open> <details open>
<summary>related</summary> <summary>related</summary>
<pre set:html={related.map(p => formatListItem(p.dates.created, `/md/${getSlug(p.id)}`, p.data.title)).join('\n')} /> <pre set:html={related.map(p => formatListItem(p.dates.created, `/${getSlug(p.id)}`, p.data.title)).join('\n')} />
</details> </details>
)} )}
</Layout> </Layout>

View file

@ -1,38 +0,0 @@
---
export const prerender = false;
import { getCollection, render } from 'astro:content';
import { requireAdminSession } from '../../lib/auth';
import Layout from '../../layouts/Layout.astro';
import { getSlug, resolveRelatedPosts } from '../../lib/dnd';
const { session, error } = await requireAdminSession(Astro.request);
if (error) return error;
if (!session) return Astro.redirect('/api/auth/signin');
const slug = Astro.params.slug;
const allPosts = await getCollection('dnd');
const post = allPosts.find(p => getSlug(p.id) === slug);
if (!post) {
return new Response('Not found', { status: 404 });
}
const { Content } = await render(post);
const related = post.data.related ? resolveRelatedPosts(post.data.related, allPosts) : [];
---
<Layout title={`${post.data.title} - lewis m.w.`}>
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
{related.length > 0 && (
<details open>
<summary>related</summary>
<pre set:html={related.map(p =>
`<a href="/dnd/${getSlug(p.id)}">${p.data.title}</a>`
).join('\n')} />
</details>
)}
</Layout>

View file

@ -1,35 +0,0 @@
---
export const prerender = false;
import { getCollection } from 'astro:content';
import { requireAdminSession } from '../../lib/auth';
import Layout from '../../layouts/Layout.astro';
import { organizePostsByCategory, getSlug } from '../../lib/dnd';
import map from '../../content/dnd/drakkenheim/map.jpg';
const { session, error } = await requireAdminSession(Astro.request);
if (error) return error;
if (!session) return Astro.redirect('/api/auth/signin');
const posts = await getCollection('dnd');
const { grouped, categories: sortedCategories } = organizePostsByCategory(posts);
---
<Layout title="dnd - lewis m.w.">
<p class="muted">logged in as {session.user?.name} <a href="/api/auth/signout">sign out</a></p>
<img src={map.src} alt="Drakkenheim map" />
{sortedCategories.length === 0 ? (
<p class="muted">nothing here</p>
) : (
sortedCategories.map(category => (
<details open>
<summary>{category}</summary>
<pre set:html={grouped[category].map(post =>
`<a href="/dnd/${getSlug(post.id)}">${post.data.title}</a>${post.data.pinned ? ' [pinned]' : ''}`
).join('\n')} />
</details>
))
)}
</Layout>

View file

@ -14,7 +14,7 @@ export async function GET(context: APIContext) {
...posts.map(post => ({ ...posts.map(post => ({
title: post.data.title, title: post.data.title,
pubDate: post.dates.created, pubDate: post.dates.created,
link: `/md/${getSlug(post.id)}`, link: `/${getSlug(post.id)}`,
description: post.data.title, description: post.data.title,
})), })),
...txtFiles.map(txt => ({ ...txtFiles.map(txt => ({

View file

@ -31,7 +31,7 @@ try {
<details open> <details open>
<summary>{category}</summary> <summary>{category}</summary>
<pre set:html={[ <pre set:html={[
...categoryPosts.slice(0, 10).map(post => formatListItem(post.dates.created, `/md/${getSlug(post.id)}`, post.data.title, { pinned: post.data.pinned })), ...categoryPosts.slice(0, 10).map(post => formatListItem(post.dates.created, `/${getSlug(post.id)}`, post.data.title, { pinned: post.data.pinned })),
...(categoryPosts.length > 10 ? [`<a href="/md/">+${categoryPosts.length - 10} more</a>`] : []) ...(categoryPosts.length > 10 ? [`<a href="/md/">+${categoryPosts.length - 10} more</a>`] : [])
].join('\n')} /> ].join('\n')} />
</details> </details>

View file

@ -13,7 +13,7 @@ const { grouped, categories: sortedCategories } = organizePostsByCategory(posts)
{sortedCategories.map(category => ( {sortedCategories.map(category => (
<details open> <details open>
<summary>{category}</summary> <summary>{category}</summary>
<pre set:html={grouped[category].map(post => formatListItem(post.dates.created, `/md/${getSlug(post.id)}`, post.data.title, { pinned: post.data.pinned })).join('\n')} /> <pre set:html={grouped[category].map(post => formatListItem(post.dates.created, `/${getSlug(post.id)}`, post.data.title, { pinned: post.data.pinned })).join('\n')} />
</details> </details>
))} ))}
</Layout> </Layout>

View file

@ -12,7 +12,7 @@ export async function GET(context: APIContext) {
const txtFiles = getTxtFileNames(); const txtFiles = getTxtFileNames();
const urls = [ const urls = [
...posts.map(post => `/md/${getSlug(post.id)}`), ...posts.map(post => `/${getSlug(post.id)}`),
...txtFiles.map(txt => `/${txt}`), ...txtFiles.map(txt => `/${txt}`),
...bookmarks.map(b => b.data.url), ...bookmarks.map(b => b.data.url),
]; ];

View file

@ -14,8 +14,7 @@ export async function GET(context: APIContext) {
const urls = [ const urls = [
'/', '/',
'/md', ...posts.map(post => `/${getSlug(post.id)}`),
...posts.map(post => `/md/${getSlug(post.id)}`),
'/txt', '/txt',
...txtFiles.map(txt => `/${txt}`), ...txtFiles.map(txt => `/${txt}`),
'/bookmarks', '/bookmarks',