This commit is contained in:
Barrett Ruth 2025-10-08 19:04:25 -04:00
parent 846bce9480
commit 60aea94006
32 changed files with 328 additions and 278 deletions

View file

@ -0,0 +1,33 @@
---
import { getCollection } from "astro:content";
import PostLayout from "../../layouts/PostLayout.astro";
export async function getStaticPaths() {
const CATS = ["algorithms", "software", "meditations", "autonomous-racing"];
const entries = [];
for (const c of CATS) {
const docs = await getCollection(c);
for (const d of docs) {
entries.push({
params: { category: c, slug: d.slug },
props: { post: d },
});
}
}
return entries;
}
const { post } = Astro.props;
const category = Astro.params.category;
const pageTitle = `${category}/${post.data.title ?? post.slug}`;
const { Content } = await post.render();
---
<PostLayout frontmatter={post.data}>
<Fragment slot="head">
<title>{pageTitle}</title>
<script type="module" src="/scripts/index.js"></script>
</Fragment>
<Content />
</PostLayout>

View file

@ -0,0 +1,61 @@
---
import BaseLayout from "../../layouts/BaseLayout.astro";
import { getCollection } from "astro:content";
export async function getStaticPaths() {
const posts = await getCollection("posts");
const categories = Array.from(new Set(posts.map((p) => p.id.split("/")[0])));
return categories.map((category) => ({ params: { category } }));
}
const category = Astro.params.category;
const title = "Barrett Ruth";
const allPosts = await getCollection("posts");
const postsByCategory = allPosts.reduce((acc, post) => {
const c = post.id.split("/")[0];
(acc[c] ||= []).push(post);
return acc;
}, {});
Object.keys(postsByCategory).forEach((c) => {
postsByCategory[c].sort((a, b) => {
const parseEuroDate = (dateStr) => {
if (!dateStr) return new Date(0);
const [day, month, year] = (dateStr || "").split("/");
return new Date(year, month - 1, day);
};
return parseEuroDate(b.data.date) - parseEuroDate(a.data.date);
});
});
---
<BaseLayout title={title}>
<slot name="head" slot="head">
<link rel="stylesheet" href="/styles/index.css" />
</slot>
<div class="content">
<ul class="topics">
<li class="topic algorithms">
<a href="/algorithms" data-topic="algorithms">algorithms</a>
</li>
<li class="topic software">
<a href="/software" data-topic="software">software</a>
</li>
<li class="topic meditations">
<a href="/meditations" data-topic="meditations">meditations</a>
</li>
</ul>
<div class="posts" id="posts"></div>
</div>
<script
slot="scripts"
define:vars={{ postsByCategory, SELECTED_CATEGORY: category }}
>
window.postsByCategory = postsByCategory;
window.SELECTED_CATEGORY = SELECTED_CATEGORY;
</script>
<script slot="scripts" type="module" src="/scripts/index.js"></script>
</BaseLayout>

View file

@ -15,17 +15,18 @@ gists.sort((a, b) => a.slug.localeCompare(b.slug));
<div class="content">
<ul class="topics">
{gists.map((gist) => (
<li class="topic">
<a
href={`/gist/${gist.slug}.html`}
data-gist={gist.slug}
>
{gist.data.title || gist.slug}
</a>
</li>
))}
{
gists.map((gist) => (
<li class="topic">
<a
href={`/gist/${gist.slug}.html`}
data-topic={`gist/${gist.slug}`}
>
{gist.data.title || gist.slug}
</a>
</li>
))
}
</ul>
</div>
</BaseLayout>

View file

@ -4,7 +4,6 @@ import PostLayout from "../../layouts/PostLayout.astro";
export async function getStaticPaths() {
const gists = await getCollection("gists");
return gists.map((gist) => ({
params: { slug: gist.slug },
props: { gist },
@ -13,9 +12,13 @@ export async function getStaticPaths() {
const { gist } = Astro.props;
const { Content } = await gist.render();
const pageTitle = `gist/${gist.data.title ?? gist.slug}`;
---
<PostLayout frontmatter={gist.data}>
<Fragment slot="head">
<title>{pageTitle}</title>
<script type="module" src="/scripts/index.js"></script>
</Fragment>
<Content />
</PostLayout>

View file

@ -1,7 +1,10 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
import { getCollection } from "astro:content";
const title = "Git Repositories";
const repos = await getCollection("git");
repos.sort((a, b) => a.slug.localeCompare(b.slug));
---
<BaseLayout title={title}>
@ -11,43 +14,17 @@ const title = "Git Repositories";
</slot>
<div class="content">
<ul class="topics" id="repo-list"></ul>
<ul class="topics" id="repo-list">
{
repos.map((r) => (
<li class="topic">
<a href={`/git/${r.slug}.html`} data-topic={`git/${r.slug}`}>
{r.data.title || r.slug}
</a>
</li>
))
}
</ul>
<div class="posts" id="posts"></div>
</div>
<script slot="scripts" type="module">
const listEl = document.getElementById("repo-list");
async function loadRepos() {
try {
const res = await fetch("https://git.barrettruth.com/api/repositories", { mode: "cors" });
if (!res.ok) throw new Error("HTTP " + res.status);
const data = await res.json();
const repos = Array.isArray(data?.repositories) ? data.repositories : [];
listEl.innerHTML = "";
repos.sort((a, b) => a.localeCompare(b));
for (const name of repos) {
const label = name.replace(/\.git$/, "");
const li = document.createElement("li");
li.className = `topic repo-${label}`;
const a = document.createElement("a");
a.href = `/git/${label}.html`;
a.textContent = label;
a.dataset.topic = "git";
a.dataset.repo = label;
li.appendChild(a);
listEl.appendChild(li);
}
} catch (_) {}
}
loadRepos();
</script>
</BaseLayout>

View file

@ -17,22 +17,27 @@ const { Content } = await entry.render();
const repoName = `${slug}.git`;
let cloneCommand = "";
try {
const res = await fetch("https://git.barrettruth.com/api/repositories");
const json = res.ok ? await res.json() : { repositories: [] };
const exists = json.repositories?.includes(repoName);
if (exists) {
if (exists)
cloneCommand = `git clone https://git.barrettruth.com/${repoName}`;
}
} catch {}
const pageTitle = `git/${entry.data.title ?? slug}`;
---
<GitLayout frontmatter={entry.data} post={entry}>
{cloneCommand && (
<div class="clone-line">
<code><span class="prompt">&gt;&nbsp;</span>{cloneCommand}</code>
</div>
)}
<Fragment slot="head">
<title>{pageTitle}</title>
</Fragment>
{
cloneCommand && (
<div class="clone-line">
<code>&gt; {cloneCommand}</code>
</div>
)
}
<Content />
</GitLayout>

View file

@ -3,34 +3,38 @@ import BaseLayout from "../layouts/BaseLayout.astro";
import { getCollection } from "astro:content";
const title = "Barrett Ruth";
const CATS = ["algorithms", "software", "meditations", "autonomous-racing"];
const allPosts = await getCollection("posts");
const postsByCategory = allPosts.reduce((acc, post) => {
const category = post.id.split("/")[0];
if (!acc[category]) acc[category] = [];
acc[category].push(post);
return acc;
}, {});
function parseEuroDate(dateStr) {
if (!dateStr) return new Date(0);
const [d, m, y] = (dateStr || "").split("/");
return new Date(Number(y), Number(m) - 1, Number(d));
}
Object.keys(postsByCategory).forEach((category) => {
postsByCategory[category].sort((a, b) => {
const parseEuroDate = (dateStr) => {
if (!dateStr) return new Date(0);
const [day, month, year] = dateStr.split("/");
return new Date(year, month - 1, day);
};
const dateA = parseEuroDate(a.data.date);
const dateB = parseEuroDate(b.data.date);
return dateB.getTime() - dateA.getTime();
});
});
const postsByCategory = {};
for (const c of CATS) {
const entries = await getCollection(c);
entries.sort(
(a, b) =>
parseEuroDate(b.data.date).getTime() -
parseEuroDate(a.data.date).getTime(),
);
postsByCategory[c] = entries.map((e) => ({
id: `${c}/${e.slug}.mdx`,
slug: e.slug,
data: {
title: e.data.title ?? e.slug,
date: e.data.date ?? null,
},
}));
}
---
<BaseLayout title={title}>
<slot name="head" slot="head">
<link rel="stylesheet" href="/styles/index.css" />
</slot>
<div class="content">
<ul class="topics">
<li class="topic algorithms">
@ -42,6 +46,11 @@ Object.keys(postsByCategory).forEach((category) => {
<li class="topic meditations">
<a href="#meditations" data-topic="meditations">meditations</a>
</li>
<li class="topic autonomous-racing">
<a href="#autonomous-racing" data-topic="autonomous-racing"
>autonomous racing</a
>
</li>
</ul>
<div class="posts" id="posts"></div>
</div>

View file

@ -1,35 +0,0 @@
---
import { getCollection } from "astro:content";
import PostLayout from "../../../layouts/PostLayout.astro";
import path from "path";
export async function getStaticPaths() {
const allPosts = await getCollection("posts");
const routes = [];
for (const post of allPosts) {
const filePath = post.id;
const pathParts = filePath.split("/");
const category = pathParts[0];
const slug = path.basename(post.id, path.extname(post.id));
routes.push({
params: { category, slug },
props: { post },
});
}
return routes;
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<PostLayout frontmatter={post.data} post={post}>
<Content />
</PostLayout>