From d74f68215517e9da2496dd6bb1df254044b25682 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Thu, 14 May 2026 11:30:04 +0200 Subject: [PATCH] removed numbers + card redesign --- frontend/src/components/react/PostList.tsx | 32 +++--------- frontend/src/pages/posts/[slug].astro | 24 +-------- frontend/src/styles/global.css | 60 +++++++++++++--------- 3 files changed, 43 insertions(+), 73 deletions(-) diff --git a/frontend/src/components/react/PostList.tsx b/frontend/src/components/react/PostList.tsx index cf134d2..26026a2 100644 --- a/frontend/src/components/react/PostList.tsx +++ b/frontend/src/components/react/PostList.tsx @@ -42,19 +42,6 @@ function formatMonth(date: string) { return new Date(date).toLocaleDateString('en-US', { month: 'short' }).toUpperCase(); } -function toRoman(n: number): string { - const map: [number, string][] = [ - [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], - [100, 'C'], [90, 'XC'], [50, 'L'], [40, 'XL'], - [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'], - ]; - let out = ''; - for (const [val, sym] of map) { - while (n >= val) { out += sym; n -= val; } - } - return out; -} - // Deterministic salon-hang layout. Each tile gets a col-span (out of 12) and an aspect ratio. // The cycle is chosen so the room reads asymmetric but balanced. const LAYOUT_CYCLE: Array<{ col: number; aspect: string; tilt: number }> = [ @@ -123,7 +110,6 @@ export default function PostList({ posts: initialPosts, isAdmin = false }: Props const displayTitle = post.title || formatSlug(post.slug); const isDeleting = deleting === post.slug; const layout = LAYOUT_CYCLE[idx % LAYOUT_CYCLE.length]; - const exhibitNumber = toRoman(idx + 1); const hasCover = !!post.cover_image?.url; return ( @@ -141,8 +127,6 @@ export default function PostList({ posts: initialPosts, isAdmin = false }: Props style={{ transform: `rotate(${layout.tilt}deg)` }} aria-label={`View ${displayTitle}`} > - № {exhibitNumber} -
-
-
{displayTitle}
- {post.summary && ( -
- {post.summary} -
- )} -
+
{displayTitle}
+ {post.summary && ( +
{post.summary}
+ )}
{formatMonth(post.date)} - · + {formatYear(post.date)} + + {post.reading_time} min
diff --git a/frontend/src/pages/posts/[slug].astro b/frontend/src/pages/posts/[slug].astro index 200e354..ede2331 100644 --- a/frontend/src/pages/posts/[slug].astro +++ b/frontend/src/pages/posts/[slug].astro @@ -28,19 +28,6 @@ function formatDate(d: string) { return new Date(d).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); } -function toRoman(n: number): string { - const map: [number, string][] = [ - [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], - [100, 'C'], [90, 'XC'], [50, 'L'], [40, 'XL'], - [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'], - ]; - let out = ''; - for (const [val, sym] of map) { - while (n >= val) { out += sym; n -= val; } - } - return out; -} - function formatSlug(s: string) { if (!s) return ''; return s.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '); @@ -49,7 +36,7 @@ function formatSlug(s: string) { let post: PostDetail | null = null; let html = ''; let error = ''; -let neighbors: { prev?: PostInfo; next?: PostInfo; index: number; total: number } = { index: -1, total: 0 }; +let neighbors: { prev?: PostInfo; next?: PostInfo } = {}; try { const [postRes, listRes] = await Promise.all([ @@ -67,8 +54,6 @@ try { const i = list.findIndex(p => p.slug === slug); if (i >= 0) { neighbors = { - index: i, - total: list.length, prev: i > 0 ? list[i - 1] : undefined, next: i < list.length - 1 ? list[i + 1] : undefined, }; @@ -82,7 +67,6 @@ try { const isAdmin = Astro.cookies.get('admin_session')?.value === '1'; const displayTitle = post ? (post.title || formatSlug(post.slug)) : 'Work'; -const exhibitNumber = neighbors.index >= 0 ? toRoman(neighbors.index + 1) : ''; --- = 0 ? toRoman(neighbors.index + 1) : ''; {/* Plaque header */}
- {exhibitNumber && ( -
- № {exhibitNumber} / {neighbors.total} -
- )} -

{displayTitle}

diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 7eabefe..fee5552 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -553,46 +553,56 @@ code, pre, kbd, samp { filter: saturate(1.05) contrast(1.04); } .plate .plate-caption { - padding: 12px 4px 14px 4px; + padding: 14px 6px 16px 6px; + margin-top: 2px; + border-top: 1px solid color-mix(in srgb, var(--surface2) 50%, transparent); display: flex; - align-items: flex-end; - justify-content: space-between; - gap: 1rem; + flex-direction: column; + gap: 0.4rem; } .plate .plate-caption-title { font-family: var(--font-display); font-style: italic; font-weight: 500; - font-size: 1.05rem; - line-height: 1.2; + font-size: 1.18rem; + line-height: 1.18; color: var(--text); letter-spacing: -0.005em; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + transition: color 0.25s ease; +} +.plate:hover .plate-caption-title { + color: var(--mauve); +} +.plate .plate-caption-summary { + font-family: var(--font-sans); + font-style: italic; + font-size: 0.82rem; + line-height: 1.4; + color: var(--subtext0); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; } .plate .plate-caption-meta { font-family: var(--font-sans); - font-size: 0.72rem; + font-size: 0.68rem; text-transform: uppercase; - letter-spacing: 0.18em; + letter-spacing: 0.22em; color: var(--subtext0); white-space: nowrap; - align-self: flex-start; - padding-top: 0.35rem; + display: flex; + align-items: center; + gap: 0.5rem; + padding-top: 0.25rem; } - -/* The little exhibit number stuck to the corner of a plate */ -.plate-tag { - position: absolute; - top: -10px; - left: 14px; - background: var(--mauve); - color: var(--rosewater); - font-family: var(--font-display); - font-size: 0.7rem; - font-weight: 600; - letter-spacing: 0.18em; - padding: 4px 8px; - text-transform: uppercase; - box-shadow: 0 2px 6px -2px rgba(20, 16, 12, 0.45); +.plate .plate-caption-sep { + color: var(--mauve); + opacity: 0.55; } .plate-tag-mini { position: absolute;