Files
bztmon-site/src/pages/blog/index.astro
T
jwright 4e13bf596c facelift: fix light-theme scrims/thumbs - :global() the data-theme overrides
Astro scopes compound selectors, so [data-theme=light] .hero__scrim inside a component style
block could never match html[data-theme] - the light theme rendered dark scrims (embossed
low-contrast copy). Wrap the theme prefix in :global() in Hero, ProjectCard and the blog index.
Light 'blueprint' hero now reads clean.
2026-07-03 19:50:18 +10:00

214 lines
5.8 KiB
Plaintext

---
import Layout from "../../layouts/Layout.astro";
import Section from "../../components/Section.astro";
import PostList from "../../components/PostList.astro";
import { getPosts, allTags, formatDate } from "../../lib/blog";
import { readingTime } from "../../lib/reading";
import { series } from "../../data/series";
import { site } from "../../data/site";
const posts = await getPosts();
const tags = allTags(posts);
// Featured = the security-series opener when present, else the newest post.
const featured = posts.find((p) => p.id === "secret-zero") ?? posts[0];
const rest = posts.filter((p) => p.id !== featured.id);
const featuredSeries = series[featured.id];
---
<Layout title="Blog" path="/blog" description="Notes on platform engineering, edge Kubernetes, GPUs and homelab infrastructure.">
<Section id="blog" eyebrow={`~/${site.handle}/blog`} index="*" title="Notes from the build.">
<p class="lead blog__intro" data-reveal>
Lessons from edge Kubernetes, GPUs, and running infrastructure like it matters.
</p>
{tags.length > 0 && (
<nav class="blog__tags" aria-label="Filter by tag" data-reveal>
<span class="mono blog__tags-label">tags:</span>
{tags.map((t) => (
<a class="tag blog__tag" href={`/blog/tags/${t}/`}>{t}</a>
))}
</nav>
)}
{featured && (
<a class="featured" href={`/blog/${featured.id}/`} data-reveal>
<div class="featured__body">
<div class="featured__meta mono">
{featuredSeries && (
<span class="featured__series">
{featuredSeries.name} · {String(featuredSeries.number).padStart(2, "0")}
</span>
)}
<time datetime={featured.data.date.toISOString()}>{formatDate(featured.data.date)}</time>
<span class="featured__sep">·</span>
<span>{readingTime(featured.body)}</span>
</div>
<h3 class="featured__title">{featured.data.title}</h3>
<p class="featured__summary">{featured.data.summary}</p>
<ul class="featured__tags" role="list">
{featured.data.tags.map((t) => (
<li class="tag">{t}</li>
))}
</ul>
<span class="featured__read mono">Read the post →</span>
</div>
{featured.data.hero && (
<div class="featured__art" aria-hidden="true">
<img
src={`${featured.data.hero}?v=2`}
alt=""
width="1600"
height="1073"
loading="eager"
decoding="async"
/>
</div>
)}
</a>
)}
<PostList posts={rest} />
</Section>
</Layout>
<style>
.blog__intro {
max-width: 50ch;
margin-bottom: var(--space-5);
}
.blog__tags {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
margin-bottom: var(--space-6);
}
.blog__tags-label {
font-size: var(--step--1);
color: var(--text-faint);
margin-right: 0.25rem;
}
.blog__tag:hover {
border-color: var(--accent-line);
color: var(--text);
text-decoration: none;
}
/* featured card — text left, hero art right, scrimmed into the panel */
.featured {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
background: var(--panel);
border: 1px solid var(--border-accent);
border-radius: 12px;
overflow: hidden;
color: inherit;
text-decoration: none;
backdrop-filter: var(--panel-blur);
-webkit-backdrop-filter: var(--panel-blur);
margin-bottom: var(--space-6);
transition:
border-color 180ms var(--ease),
box-shadow 180ms var(--ease);
}
.featured:hover {
text-decoration: none;
border-color: var(--border-accent-hover);
box-shadow: var(--glow-card);
}
.featured__body {
padding: var(--space-6);
display: flex;
flex-direction: column;
gap: var(--space-3);
position: relative;
z-index: 1;
}
.featured__meta {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
font-size: 0.72rem;
color: var(--text-faint);
}
.featured__series {
color: var(--accent-2);
border: 1px solid var(--border-magenta);
border-radius: 3px;
padding: 2px 7px;
letter-spacing: 0.1em;
font-size: 0.66rem;
}
.featured__sep {
opacity: 0.6;
}
.featured__title {
margin: 0;
font-family: var(--font-display);
font-size: var(--step-2);
font-weight: 600;
color: var(--text-strong);
letter-spacing: -0.01em;
}
.featured__summary {
margin: 0;
color: var(--text-dim);
font-size: var(--step-0);
line-height: 1.65;
text-wrap: pretty;
}
.featured__tags {
list-style: none;
padding: 0;
margin: var(--space-2) 0 0;
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.featured__read {
margin-top: auto;
padding-top: var(--space-3);
font-size: 0.8rem;
color: var(--accent);
}
.featured__art {
position: relative;
min-height: 280px;
}
.featured__art img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
/* scrim the art into the panel from the text side */
.featured__art::before {
content: "";
position: absolute;
inset: 0;
z-index: 1;
background: linear-gradient(90deg, var(--panel-solid) 0%, transparent 45%);
}
:global([data-theme="light"]) .featured__art::before {
background: linear-gradient(90deg, var(--panel-solid) 0%, transparent 45%);
opacity: 0.85;
}
@media (max-width: 860px) {
.featured {
grid-template-columns: 1fr;
}
.featured__art {
order: -1;
min-height: 200px;
}
.featured__art::before {
background: linear-gradient(180deg, transparent 55%, var(--panel-solid) 100%);
}
}
</style>