M2: content collections — case studies, blog, RSS, tags, sitemap
Projects + blog as schema-validated content collections; structured case studies (problem/design/outcome), blog with tag pages, reading time, RSS feed (drafts excluded), sitemap, and Shiki dual-theme code highlighting.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { formatDate } from "../lib/blog";
|
||||
import { readingTime } from "../lib/reading";
|
||||
|
||||
interface Props {
|
||||
posts: CollectionEntry<"blog">[];
|
||||
}
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<ol class="posts">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<li class="post" data-reveal>
|
||||
<a class="post__link" href={`/blog/${post.id}`}>
|
||||
<div class="post__meta mono">
|
||||
<time datetime={post.data.date.toISOString()}>{formatDate(post.data.date)}</time>
|
||||
<span class="post__sep">·</span>
|
||||
<span>{readingTime(post.body)}</span>
|
||||
</div>
|
||||
<h3 class="post__title">{post.data.title}</h3>
|
||||
<p class="post__summary">{post.data.summary}</p>
|
||||
<ul class="post__tags">
|
||||
{post.data.tags.map((t) => (
|
||||
<li class="tag">{t}</li>
|
||||
))}
|
||||
</ul>
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
|
||||
<style>
|
||||
.posts {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
.post__link {
|
||||
display: block;
|
||||
padding: var(--space-5);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: var(--surface);
|
||||
color: inherit;
|
||||
transition: border-color 0.2s var(--ease), transform 0.2s var(--ease);
|
||||
}
|
||||
.post__link:hover {
|
||||
text-decoration: none;
|
||||
border-color: var(--accent-line);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.post__meta {
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-faint);
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.post__sep {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.post__title {
|
||||
margin-top: var(--space-2);
|
||||
font-size: var(--step-1);
|
||||
color: var(--text);
|
||||
}
|
||||
.post__summary {
|
||||
margin-top: var(--space-2);
|
||||
color: var(--text-dim);
|
||||
font-size: var(--step--1);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.post__tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: var(--space-3) 0 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user