start working on posts with placeholder content
This commit is contained in:
95
src/components/Post.astro
Normal file
95
src/components/Post.astro
Normal 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
19
src/content.config.ts
Normal 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 };
|
||||
@@ -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 />
|
||||
|
||||
@@ -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
27
src/lib/datefmt.ts
Normal 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
24
src/pages/[slug].astro
Normal 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>
|
||||
Reference in New Issue
Block a user