diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index 265e574..2dee0ab 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -2,14 +2,22 @@ import Layout from "../../layouts/Layout.astro"; import Section from "../../components/Section.astro"; import PostList from "../../components/PostList.astro"; -import { getPosts, allTags } from "../../lib/blog"; +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]; --- -
+

Lessons from edge Kubernetes, GPUs, and running infrastructure like it matters.

@@ -23,7 +31,44 @@ const tags = allTags(posts); )} - + {featured && ( + + + {featured.data.hero && ( + + )} + + )} + +
@@ -49,4 +94,120 @@ const tags = allTags(posts); 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%); + } + [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%); + } + }