RC: (add) filter by blog tag
Some checks failed
Build and Update Flux / build-push-update (push) Has been cancelled

This commit is contained in:
Raul Costa
2026-04-02 00:01:07 +01:00
parent bbea284c49
commit edc3e97d3b
3 changed files with 144 additions and 15 deletions

View File

@@ -5,6 +5,7 @@ const posts = (await getCollection('blog'))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
.slice(0, 3);
---
<section class="section recent-posts" id="recent-posts">
<div class="container">
<div class="section-header">
@@ -31,7 +32,7 @@ const posts = (await getCollection('blog'))
</time>
<div class="post-card-tags">
{(post.data.tags ?? []).slice(0,3).map((t: string) => (
<span class="tag">{t}</span>
<a href={`/tags/${t}`} class="tag" onclick="event.stopPropagation()">{t}</a>
))}
</div>
</div>
@@ -51,9 +52,7 @@ const posts = (await getCollection('blog'))
</section>
<style>
.recent-posts {
padding-bottom: 1rem;
padding-top: 15rem; }
.recent-posts { padding-bottom: 2rem; }
.section-header { margin-bottom: 3rem; }

109
src/pages/tags/[tag].astro Normal file
View File

@@ -0,0 +1,109 @@
---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog', ({ data }) => !data.draft);
const tags = [...new Set(posts.flatMap(p => p.data.tags ?? []))];
return tags.map(tag => ({
params: { tag },
props: {
tag,
posts: posts
.filter(p => p.data.tags?.includes(tag))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()),
},
}));
}
const { tag, posts } = Astro.props;
---
<BaseLayout title={`#${tag}`} description={`All posts tagged ${tag}`}>
<div class="tag-page">
<div class="container page-hero">
<a href="/blog" class="back-link font-mono">← all posts</a>
<div class="accent-line" style="margin-top:1rem"></div>
<h1>
<span class="text-muted" style="font-weight:400">#</span>{tag}
</h1>
<p class="text-muted font-mono" style="font-size:0.85rem;margin-top:0.5rem">
{posts.length} {posts.length === 1 ? 'entry' : 'entries'}
</p>
</div>
<div class="container post-list">
{posts.map(post => (
<article class="card post-row">
<a href={`/blog/${post.id}`} class="post-row-link">
<div class="post-row-left">
{post.data.day && (
<div class="font-mono" style="font-size:0.7rem;color:var(--petronas-teal);letter-spacing:0.1em;margin-bottom:0.3rem">
entry_{String(post.data.day).padStart(3,'0')}
</div>
)}
<h2 class="post-row-title">{post.data.title}</h2>
<p class="text-muted post-row-desc">{post.data.description}</p>
<div class="post-row-meta">
<time class="font-mono text-muted" style="font-size:0.72rem">
{post.data.pubDate.toLocaleDateString('en-GB', { day:'numeric', month:'short', year:'numeric' })}
</time>
<div style="display:flex;gap:0.35rem;flex-wrap:wrap">
{(post.data.tags ?? []).map((t: string) => (
<a href={`/tags/${t}`} class="tag">{t}</a>
))}
</div>
</div>
</div>
<div class="post-row-arrow text-accent font-display">→</div>
</a>
</article>
))}
</div>
</div>
</BaseLayout>
<style>
.tag-page { padding-top: 8rem; padding-bottom: 4rem; }
.page-hero { margin-bottom: 3rem; }
.back-link {
font-size: 0.78rem;
color: var(--text-muted);
letter-spacing: 0.08em;
transition: color 150ms;
}
.back-link:hover { color: var(--petronas-teal); }
.post-list { display: flex; flex-direction: column; gap: 1rem; }
.post-row { padding: 0; }
.post-row-link {
display: flex;
align-items: center;
gap: 1.5rem;
padding: 1.5rem;
color: inherit;
}
.post-row-left { flex: 1; }
.post-row-title { font-size: 1.05rem; margin-bottom: 0.4rem; transition: color 150ms; }
.post-row:hover .post-row-title { color: var(--petronas-teal); }
.post-row-desc { font-size: 0.85rem; line-height: 1.55; margin-bottom: 0.75rem; }
.post-row-meta {
display: flex;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
}
.post-row-arrow {
font-size: 1.5rem;
opacity: 0.3;
transition: opacity 150ms, transform 150ms;
flex-shrink: 0;
}
.post-row:hover .post-row-arrow { opacity: 1; transform: translateX(4px); }
</style>

View File

@@ -115,13 +115,23 @@ pre {
}
pre {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
background: #0d1918;
border: 1px solid rgba(0, 210, 190, 0.12);
border-left: 3px solid var(--petronas-teal);
padding: 1.25rem 1.5rem;
border-radius: 0 8px 8px 0;
overflow-x: auto;
margin: 2rem 0;
color: #a8c8c6; /* single readable text colour — no syntax highlighting */
}
/* Kill any syntax highlighter span colours — keep it monochrome */
pre span,
pre code span {
color: inherit !important;
background: transparent !important;
font-style: normal !important;
font-weight: normal !important;
}
/* ── Layout ────────────────────────────────────────────────── */
@@ -193,14 +203,24 @@ pre {
/* ── Tag / Badge ───────────────────────────────────────────── */
.tag {
display: inline-block;
padding: 0.2rem 0.65rem;
padding: 0.15rem 0.55rem;
font-family: var(--font-mono);
font-size: 0.72rem;
font-size: 0.68rem;
color: var(--petronas-teal);
background: var(--petronas-glow);
border: 1px solid rgba(0, 210, 190, 0.2);
border-radius: 3px;
border-radius: 20px;
letter-spacing: 0.04em;
white-space: nowrap;
transition:
background var(--transition-fast),
border-color var(--transition-fast),
color var(--transition-fast);
}
a.tag:hover {
background: rgba(0, 210, 190, 0.2);
border-color: rgba(0, 210, 190, 0.5);
color: var(--text-primary);
}
/* ── Glow Divider ──────────────────────────────────────────── */
@@ -215,7 +235,6 @@ pre {
);
margin: 4rem 0;
opacity: 0.3;
margin: 4rem auto;
}
/* ── Noise texture overlay ─────────────────────────────────── */
@@ -246,7 +265,7 @@ body::after {
/* ── Prose (blog posts) ────────────────────────────────────── */
.prose {
max-width: 72ch;
color: var(--text-secondary);
color: #9bbfbd; /* brighter than text-secondary for long-form readability */
}
.prose h2,
.prose h3 {
@@ -255,6 +274,7 @@ body::after {
}
.prose p {
margin-bottom: 1.4rem;
line-height: 1.8;
}
.prose ul,
.prose ol {
@@ -285,8 +305,9 @@ body::after {
font-weight: 500;
}
.prose code {
background: var(--bg-surface);
padding: 0.15em 0.4em;
background: #0d1918;
padding: 0.15em 0.45em;
border-radius: 3px;
color: var(--petronas-teal);
color: #7dcfca; /* slightly muted teal — readable but distinct from body text */
font-size: 0.85em;
}