start working on posts with placeholder content

This commit is contained in:
2026-02-28 09:26:10 -05:00
parent 95b58b5615
commit c28f340333
16 changed files with 372 additions and 15 deletions

95
src/components/Post.astro Normal file
View File

@@ -0,0 +1,95 @@
---
import type { CollectionEntry } from 'astro:content';
import { render } from 'astro:content';
import { formatDate } from '@lib/datefmt';
export interface Props {
entry: CollectionEntry<'posts'>,
prevSlug: string | null,
nextSlug: string | null,
};
const { entry, prevSlug, nextSlug } = Astro.props;
const { Content } = await render(entry);
---
<style>
/* 3-column grid: left gutter, center content, and right gutter */
article {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, var(--content-width)) minmax(0, 1fr);
/* a bit of breathing room for narrow screens */
padding: 0 var(--content-padding);
}
.left-gutter {
grid-column: 1 / 2;
justify-self: end;
}
.right-gutter {
grid-column: 3 / 4;
justify-self: start;
}
.title {
grid-column: 2 / 3;
}
.subtitle {
font-size: 0.9em;
font-style: italic;
margin-top: -0.75rem;
}
.post {
grid-column: 2 / 3;
}
footer {
grid-column: 2 / 3;
margin-bottom: 2.5rem;
display: flex;
justify-content: space-between;
& a {
font-size: 1.25rem;
color: var(--content-color-faded);
text-decoration: underline;
text-underline-offset: 0.25em;
text-decoration-color: transparent;
transition: 150ms;
&:hover {
text-decoration-color: currentColor;
text-decoration: underline;
}
}
}
</style>
<article>
<header class="title">
<h1>{ entry.data.title }</h1>
<p class="subtitle">{ formatDate(entry.data.date) }</p>
</header>
<div class="left-gutter" />
<section class="post">
<Content />
</section>
<div class="right-gutter" />
<footer>
{prevSlug && (
<a href={`/${prevSlug}`} data-astro-prefetch>Older</a>
)}
{nextSlug && (
<a href={`/${nextSlug}`} data-astro-prefetch>Newer</a>
)}
</footer>
</article>

19
src/content.config.ts Normal file
View File

@@ -0,0 +1,19 @@
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const posts = defineCollection({
loader: glob({ pattern: '*.mdx', base: './posts' }),
schema: z.object({
title: z.string(),
date: z.date(),
draft: z.boolean().default(false),
dropcap: z.boolean().default(true),
toc: z.boolean().default(true),
})
});
export const collections = { posts };

View File

@@ -3,8 +3,8 @@ import '@styles/main.css';
---
<style>
.header {
background: var(--primary-color-faded);
header {
background-color: var(--primary-color-faded);
}
nav {
@@ -37,13 +37,13 @@ import '@styles/main.css';
<meta name="viewport" content="width=device-width" />
</head>
<body>
<div class="header">
<header>
<nav>
<a href="/" data-astro-prefetch>Home</a>
<a href="/posts" data-astro-prefetch>Posts</a>
<a href="/about" data-astro-prefetch>About</a>
</nav>
</div>
</header>
<main>
<slot />

View File

@@ -2,19 +2,55 @@
import BaseLayout from '@layouts/BaseLayout.astro';
---
<style>
/* 3-column grid: left gutter, center content, and right gutter */
article {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, var(--content-width)) minmax(0, 1fr);
/* a bit of breathing room for narrow screens */
padding: 0 var(--content-padding);
}
.left-gutter {
grid-column: 1 / 2;
justify-self: end;
}
.right-gutter {
grid-column: 3 / 4;
justify-self: start;
}
.title {
grid-column: 2 / 3;
}
.subtitle {
font-size: 0.9em;
font-style: italic;
margin-top: -0.75rem;
}
.post {
grid-column: 2 / 3;
}
</style>
<BaseLayout>
<div class="page">
<h1>Working Title</h1>
<p class="subtitle">Subtitle</p>
<article>
<header class="title">
<h1>Working Title</h1>
<p class="subtitle">Subtitle</p>
</header>
<div class="left-gutter" />
<div class="post">
<section class="post">
<slot />
</div>
</section>
<div class="right-gutter" />
<div class="footer" />
</div>
<footer />
</article>
</BaseLayout>

27
src/lib/datefmt.ts Normal file
View File

@@ -0,0 +1,27 @@
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const ordinals = [
'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh',
'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth',
'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth', 'eighteenth',
'nineteenth', 'twentieth', 'twenty-first', 'twenty-second', 'twenty-third',
'twenty-fourth', 'twenty-fifth', 'twenty-sixth', 'twenty-seventh',
'twenty-eighth', 'twenty-ninth', 'thirtieth', 'thirty-first'
];
const weekdays = [
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
];
export function formatDate(date: Date) {
const year = date.getFullYear();
const month = months[date.getMonth() - 1];
const monthday = ordinals[date.getDate() - 1];
const weekday = weekdays[date.getDay() - 1];
return `${weekday}, the ${monthday} of ${month}, A.D. ${year}`;
}

24
src/pages/[slug].astro Normal file
View File

@@ -0,0 +1,24 @@
---
import { getCollection } from 'astro:content';
import BaseLayout from '@layouts/BaseLayout.astro';
import Post from '@components/Post.astro';
export async function getStaticPaths() {
const entries = await getCollection('posts');
entries.sort((a, b) => a.data.date.getTime() - b.data.date.getTime())
return entries.map((entry, idx) => {
const prevSlug = entries[idx - 1]?.id || null;
const nextSlug = entries[idx + 1]?.id || null;
return {
params: { slug: entry.id },
props: { entry, prevSlug, nextSlug },
}
});
}
---
<BaseLayout>
<Post {...Astro.props} />
</BaseLayout>