← back to Goodquestion Ai
src/layouts/PostLayout.astro
103 lines
---
import BlogLayout from './BlogLayout.astro';
interface Props {
title: string;
description: string;
date: Date;
author?: string;
tags?: string[];
}
const { title, description, date, author = 'Agent Abrams', tags = [] } = Astro.props;
const formattedDate = date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
// Rough reading time estimate
const content = await Astro.slots.render('default');
const words = content.replace(/<[^>]*>/g, '').split(/\s+/).length;
const readingTime = Math.max(1, Math.ceil(words / 250));
---
<BlogLayout title={title} description={description}>
<article itemscope itemtype="https://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title" itemprop="headline">{title}</h1>
<div class="post-meta" aria-label="Post metadata">
<time datetime={date.toISOString()} itemprop="datePublished">{formattedDate}</time>
<span aria-label={`${readingTime} minute read`}>{readingTime} min read</span>
<span itemprop="author">{author}</span>
</div>
{tags.length > 0 && (
<div class="post-card-tags" aria-label="Tags">
{tags.map(tag => (
<span class="tag">{tag}</span>
))}
</div>
)}
</header>
<div class="post-content" itemprop="articleBody">
<slot />
</div>
<!-- Back link -->
<nav class="post-footer-nav" aria-label="Post navigation">
<a href="/" class="back-link">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<polyline points="15 18 9 12 15 6"/>
</svg>
All posts
</a>
</nav>
</article>
</BlogLayout>
<style>
/* Back-link nav */
.post-footer-nav {
margin-top: 4rem;
padding-top: 2rem;
border-top: 1px solid var(--border);
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-secondary);
text-decoration: none;
padding: 0.4rem 0.75rem 0.4rem 0.5rem;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: var(--bg-secondary);
transition: color var(--duration-fast) var(--ease-out),
border-color var(--duration-fast) var(--ease-out),
background var(--duration-fast) var(--ease-out);
}
.back-link:hover {
color: var(--accent);
border-color: var(--accent);
background: var(--accent-subtle);
text-decoration: none;
}
/* Separator dots in post-meta */
.post-meta span + span::before,
.post-meta time + span::before {
content: '·';
margin: 0 0.5rem;
color: var(--text-muted);
opacity: 0.5;
}
</style>