- footer: 'built <ts> · <hash> · <n> notes', hash linking to Gitea (GARDEN_COMMIT passed in by build.sh; '+' marks dirty-tree builds) - homepage header: live strip fed by api.c0smere.net/spotify/summary (weekly aggregate + monthly top artist/genre), fail-closed like the odometer and header quote - /og/<slug>.png satori+resvg cards for every note + the homepage; og:/twitter: meta in Base - shiki github-dark-default (#0d1117 sits closer to the page ground) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
91 lines
2.6 KiB
Plaintext
91 lines
2.6 KiB
Plaintext
---
|
|
import { getCollection, render } from 'astro:content';
|
|
import Base from '../layouts/Base.astro';
|
|
import { slugForId, urlForId } from '../lib/quartz-compat.mjs';
|
|
|
|
export async function getStaticPaths() {
|
|
const entries = await getCollection('garden', (e) => !e.data.draft);
|
|
const ids = new Set(entries.map((e) => e.id));
|
|
|
|
const paths = entries
|
|
.filter((e) => e.id !== 'index')
|
|
.map((e) => ({
|
|
params: { slug: slugForId(e.id) },
|
|
props: { entry: e, listing: null },
|
|
}));
|
|
|
|
// synthetic listing pages for folders that have no index.md
|
|
const folders = new Set<string>();
|
|
for (const id of ids) {
|
|
let d = id.includes('/') ? id.slice(0, id.lastIndexOf('/')) : '';
|
|
while (d) {
|
|
folders.add(d);
|
|
d = d.includes('/') ? d.slice(0, d.lastIndexOf('/')) : '';
|
|
}
|
|
}
|
|
for (const folder of folders) {
|
|
if (ids.has(`${folder}/index`)) continue;
|
|
const children = entries
|
|
.filter((e) => {
|
|
const dir = e.id.includes('/') ? e.id.slice(0, e.id.lastIndexOf('/')) : '';
|
|
return dir === folder && !e.id.endsWith('/index');
|
|
})
|
|
.map((e) => ({
|
|
title: e.data.title ?? e.id.split('/').pop(),
|
|
url: urlForId(e.id),
|
|
}));
|
|
const subfolders = [...folders]
|
|
.filter((f) => {
|
|
const dir = f.includes('/') ? f.slice(0, f.lastIndexOf('/')) : '';
|
|
return dir === folder;
|
|
})
|
|
.map((f) => ({
|
|
title: f.split('/').pop(),
|
|
url: '/' + slugForId(f) + '/',
|
|
}));
|
|
paths.push({
|
|
params: { slug: slugForId(folder) + '/index' },
|
|
props: {
|
|
entry: null,
|
|
listing: { name: folder.split('/').pop(), items: [...subfolders, ...children] },
|
|
},
|
|
});
|
|
}
|
|
|
|
return paths;
|
|
}
|
|
|
|
const { entry, listing } = Astro.props;
|
|
const title = entry
|
|
? (entry.data.title ?? entry.id.split('/').pop())
|
|
: listing.name;
|
|
const rendered = entry ? await render(entry) : null;
|
|
const Content = rendered?.Content ?? null;
|
|
// notes whose body already opens with an identical h1 (common vault
|
|
// pattern) would show a doubled title — skip the synthetic one
|
|
const contentLeadsWithTitle =
|
|
rendered?.headings?.[0]?.depth === 1 &&
|
|
rendered.headings[0].text.trim() === String(title).trim();
|
|
---
|
|
|
|
<Base
|
|
title={title}
|
|
description={entry?.data.description}
|
|
headings={rendered?.headings ?? []}
|
|
ogSlug={entry ? slugForId(entry.id) : undefined}
|
|
>
|
|
{!contentLeadsWithTitle && <h1>{title}</h1>}
|
|
{Content && <Content />}
|
|
{
|
|
listing && (
|
|
<ul>
|
|
{listing.items.map((item) => (
|
|
<li>
|
|
<a href={item.url}>{item.title}</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)
|
|
}
|
|
</Base>
|