From 699a9c867df293edca9356f370abd021841b143e Mon Sep 17 00:00:00 2001 From: Daniel Naab Date: Wed, 29 Apr 2026 03:47:33 +0000 Subject: [PATCH 1/3] feat: redesign featured section as stacked content cards Replace the 4-column card grid with a single-column stacked layout. Each card now shows the project title, highlights as metadata tags, the summary, and an excerpt pulled from the detail page body content. Uses a left accent border instead of top border for visual hierarchy. --- src/design/components/featured-card/index.tsx | 33 +++++++--- .../components/featured-card/styles.css | 62 ++++++++++++------- src/design/layout.css | 8 ++- src/pages/home.tsx | 4 +- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/design/components/featured-card/index.tsx b/src/design/components/featured-card/index.tsx index de833b0..1fdc07a 100644 --- a/src/design/components/featured-card/index.tsx +++ b/src/design/components/featured-card/index.tsx @@ -1,25 +1,38 @@ import type { CatalogEntry } from '../../../catalog/types' import { url } from '../../../build/config' +import { raw } from 'hono/html' + +/** Extract first

from rendered HTML body */ +function firstParagraph(html: string): string | null { + const match = html.match(/

([\s\S]*?)<\/p>/) + return match ? match[1] : null +} export function FeaturedCard({ entry, basePath }: { entry: CatalogEntry; basePath: string }) { const href = url(`/work/${entry.name}/`, basePath) const title = entry.overlay?.title ?? entry.name const summary = entry.overlay?.summary ?? entry.description ?? '' const highlights = entry.overlay?.highlights + const excerpt = entry.overlay?.body ? firstParagraph(entry.overlay.body) : null return (

) diff --git a/src/design/components/featured-card/styles.css b/src/design/components/featured-card/styles.css index 5a40a39..3a670fd 100644 --- a/src/design/components/featured-card/styles.css +++ b/src/design/components/featured-card/styles.css @@ -1,17 +1,22 @@ .featured-card { - padding: var(--space-5); - border: 1px solid var(--color-surface-alt); - border-block-start: 3px solid var(--color-accent); - border-radius: var(--radius-md); + display: grid; + gap: var(--space-4); + padding: var(--space-5) var(--space-6); + border-inline-start: 3px solid var(--color-accent); + border-radius: var(--radius-sm); background: var(--color-surface); box-shadow: var(--shadow-card); - display: grid; +} + +.featured-card__header { + display: flex; + flex-wrap: wrap; + align-items: baseline; gap: var(--space-3); - align-content: start; } .featured-card__title { - font-size: var(--step-1); + font-size: var(--step-2); line-height: 1.2; } @@ -24,28 +29,43 @@ color: var(--color-link-hover); } -.featured-card__summary { - color: var(--color-ink-subtle); - font-size: var(--step--1); -} - -.featured-card__highlights { +.featured-card__tags { + display: flex; + flex-wrap: wrap; + gap: var(--space-2); list-style: none; padding: 0; - display: flex; - flex-direction: column; - gap: var(--space-1); + margin: 0; +} + +.featured-card__tags li { font-size: var(--step--1); + color: var(--color-ink-subtle); + padding: var(--space-1) var(--space-3); + background: var(--color-surface-highlight); + border-radius: var(--radius-sm); + white-space: nowrap; +} + +.featured-card__body { + display: grid; + gap: var(--space-3); + max-inline-size: var(--measure-prose); } -.featured-card__highlights li::before { - content: "\2713\0020"; - color: var(--color-tier-active); - font-weight: 700; +.featured-card__summary { + font-size: var(--step-0); + color: var(--color-ink-subtle); + font-weight: 500; +} + +.featured-card__excerpt { + font-size: var(--step--1); + color: var(--color-ink-subtle); + line-height: 1.6; } .featured-card__cta { - margin-block-start: auto; font-size: var(--step--1); } diff --git a/src/design/layout.css b/src/design/layout.css index bc8db33..5fb497b 100644 --- a/src/design/layout.css +++ b/src/design/layout.css @@ -66,7 +66,11 @@ margin-inline: calc(-1 * var(--space-5)); border-radius: var(--radius-md); } - .home-featured__grid, + .home-featured__list { + display: flex; + flex-direction: column; + gap: var(--space-5); + } .home-stats__grid, .work-index__list { display: grid; @@ -74,12 +78,10 @@ container-type: inline-size; } @container (min-width: 48rem) { - .home-featured__grid { grid-template-columns: repeat(2, 1fr); } .home-stats__grid { grid-template-columns: repeat(3, 1fr); } .work-index__list { grid-template-columns: repeat(2, 1fr); } } @container (min-width: 72rem) { - .home-featured__grid { grid-template-columns: repeat(4, 1fr); } .work-index__list { grid-template-columns: repeat(3, 1fr); } } .work-index__section-heading { diff --git a/src/pages/home.tsx b/src/pages/home.tsx index d76ab87..300b112 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -37,8 +37,8 @@ export function Home({