From 1ec00ea6dc2ab8e8fc5431d047d4a7bc700f4cd4 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Fri, 1 May 2026 16:57:38 +0800 Subject: [PATCH] redesign: dark premium retro + cover-image card listings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the earlier light editorial pass with a darker premium retro aesthetic for hype404 specifically: - Warm near-black bg (#0d0c0a) with subtle radial-gradient phosphor tint, cream ink (#ebe2cd) - Phosphor lime accent (#b8e25a) for brand mark, drop cap, code, tag hover (CRT/terminal nod, restrained — not the harsh #00ff66) - Hot magenta secondary (#f43f8c) for "Top story" flag, blockquote rule, drop cap (Y2K Wired-magazine vibe) - Cyan-leaning links (#7cd1ff) - Same Fraunces serif headlines + Inter body + JetBrains Mono code - No scanlines, no glitch, no marquee, no [LOG] tags Listing pages now use a magazine-style hero card (top story, 1.1:1 image+text grid, 36px headline) + image-row cards for the rest. Each row has a 220px cover thumb on the left, body on the right. Posts without images render text-only (CSS :has() fallback). Cover extracted via raw-markdown regex (no full render needed). Subtle scroll-reveal animation: cards fade+lift into view via IntersectionObserver, gracefully skips when unsupported. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/PostList.astro | 102 +++++++++-- src/layouts/Layout.astro | 335 +++++++++++++++++++++++++++------- 2 files changed, 358 insertions(+), 79 deletions(-) diff --git a/src/components/PostList.astro b/src/components/PostList.astro index 63431ff..70d82a3 100644 --- a/src/components/PostList.astro +++ b/src/components/PostList.astro @@ -1,23 +1,93 @@ --- const { posts, tag } = Astro.props; ---- -{tag &&

Tagged: {tag}

} -{posts.map((post) => ( -
-

- {post.title} -

- -

{post.rawExcerpt}

+// Extract first cover image directly from the raw markdown body. +// Cheap regex — avoids rendering the full HTML for each card. +function firstImage(body) { + const m = body && body.match(/!\[[^\]]*\]\((\/images\/[^)]+)\)/); + return m ? m[1] : null; +} + +const enriched = posts.map((p) => ({ + ...p, + cover: firstImage(p.body), +})); +const hero = enriched[0]; +const rest = enriched.slice(1); + +const fmt = (d) => new Date(d).toLocaleDateString('en-US', + { year: 'numeric', month: 'long', day: 'numeric' }); +--- +{tag && ( +

+ Tagged: {tag} +

+)} + +{enriched.length > 0 && !tag && hero && ( + +)} + +{(tag ? enriched : rest).map((post, i) => ( + ))} -{posts.length === 0 && ( -

No posts yet.

+{enriched.length === 0 && ( +

No posts yet.

)} + + diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index e073901..d84b74f 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -46,21 +46,25 @@ const year = new Date().getFullYear(); - +