--- /** * 书架改版方案预览(Phase 5i T7):一页并陈三个方案,供用户直接点选。 * * 为什么做成预览页而不是直接改 /books:书架是纯审美决策,改错要回滚一轮; * 一页三案 + 页顶锚点,用户在手机或桌面点开就能比,选定后我再把选中的方案 * 落到 BooksPage.astro,然后删掉本预览路由(含 sitemap 排除与 noindex)。 * * 三方案共同的数据契约与 BooksPage 一致:posts 里 category=reading 的条目, * 封面走 Astro image()(cover 缺省时用 mood 色脊兜底),description 缺省取正文首段。 */ import { getCollection } from 'astro:content'; import { Image } from 'astro:assets'; import BaseLayout from '../layouts/BaseLayout.astro'; import { sortPosts } from '../lib/post-order'; const books = sortPosts( await getCollection( 'posts', ({ data }) => !data.draft && data.category === 'reading' && !data.tags.includes('hidden'), ), ); /** description 缺省回退正文首段(去 markdown 记号、截 60 字),与 BooksPage 同契约 */ const firstPara = (body: string | undefined): string => { const line = (body ?? '') .split(/\n\s*\n/) .map((l) => l.trim()) .find((l) => l && !l.startsWith('#') && !l.startsWith('---')) ?? ''; return line.replace(/[*_>`[\]]/g, '').slice(0, 60); }; const items = books.map((b) => ({ id: b.id, title: b.data.title, author: b.data.bookAuthor ?? '', desc: b.data.description ?? firstPara(b.body), cover: b.data.cover, mood: b.data.mood ?? 'var(--ink-4)', year: b.data.pubDate.getFullYear(), href: `/archives/${b.id}/`, })); const years = [...new Set(items.map((i) => i.year))].sort((a, b) => b - a); const withCover = items.filter((i) => i.cover).length; ---

书架改版:三个方案

共 {items.length} 本书,其中 {withCover} 本有封面图。三个方案用同一份数据渲染, 看完告诉我选哪个(回「A」「B」或「C」即可,也可以说「B 但标题字大一点」这类微调)。

A

竖排色脊墙

像真书架:书脊竖排、颜色即情绪。优点最像"书架";代价无封面的书看不出内容,标题长会挤。

{years.map((year) => (

{year} · {items.filter((i) => i.year === year).length} 本

))}
B

封面网格

以封面为主角,悬停浮起并显出简介。优点视觉最抓人、信息最全;兜底无封面的书用色脊占位,不出现空洞卡。

{years.map((year) => (

{year} · {items.filter((i) => i.year === year).length} 本