From 0f74467933ba01460425810a2b7d82213f8bb423 Mon Sep 17 00:00:00 2001 From: dsh Date: Wed, 16 Sep 2026 18:03:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E5=B1=8F=E5=BD=A9=E8=9B=8B=EF=BC=9A?= =?UTF-8?q?=E9=82=A3=E5=8F=A5=E8=AF=9D=E5=87=BA=E8=87=AA=E7=8E=8B=E5=B0=8F?= =?UTF-8?q?=E6=B3=A2=E3=80=8A=E4=B8=87=E5=AF=BF=E5=AF=BA=E3=80=8B=EF=BC=8C?= =?UTF-8?q?=E5=8F=AF=E8=B7=B3=E8=B1=86=E7=93=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 交互(默认完全看不出可点,保持留白): - 悬停/聚焦:整句话由墨黑转朱红 + 朱红细下划线,署名随之淡入 - 点那句话 → 直接去豆瓣人物页 - 点署名 → 展开一张极简作者卡片,卡片里也能去豆瓣 结构上的几个考量: - 用

而不是把 h1 变成链接:保住标题语义,点击热区只包住文字 而不是整行 1024px(点旁边空白也跳走会很怪) - 光标 ::after 挂在 h1 上(链接外面),点那个闪烁的竖线不会触发跳转 - 署名占一行固定高度(2.25rem)平时透明,hover 才淡入 —— 空间一直留着, 所以展开卡片时下面的按钮不会往上跳 - 卡片是手风琴式展开(max-height 过渡),留在文档流里,不盖住下面的按钮 - @media (hover: none) 下署名常显 —— 否则手机上这个彩蛋永远看不到 - aria-expanded / aria-controls / aria-label + focus-within 可见焦点, 键盘和读屏用户都能用 - prefers-reduced-motion 下关掉所有过渡 出处核实:多个豆瓣《万寿寺》原文摘录页都收录这句,确认为王小波《万寿寺》。 豆瓣链接在 curl 下会跳 sec.douban.com(反爬),真实浏览器可正常打开。 验证:pnpm build 退出码 0;dist/index.html 里豆瓣链接出现 2 次、 h1 内为 、署名与卡片均在、卡片默认 data-open="false"; 产物 CSS 含 16 条 hero-quote 规则(含 @media(hover:none)) --- src/components/hero.tsx | 67 ++++++++++++++++++--- src/data/reading.json | 2 +- src/styles/global.css | 127 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 8 deletions(-) diff --git a/src/components/hero.tsx b/src/components/hero.tsx index b61a3b0..6a0f4ea 100644 --- a/src/components/hero.tsx +++ b/src/components/hero.tsx @@ -9,6 +9,9 @@ import { site } from "@/data/site" * 原来那四句是 14/11/4/4 字,长短差 3.5 倍,只能靠自适应字号兜底, * 结果是每换一句首屏最大的字就跳 1.5 倍。 */ +/** 王小波的豆瓣人物页。点击那句话或卡片里的链接都去这里。 */ +const DOUBAN_URL = "https://www.douban.com/personage/27480512/" + const phrases = [ { prefix: "一个人只拥有此生此世", highlight: "是不够的," }, { prefix: "他还需要一个", highlight: "诗意的世界。" }, @@ -31,6 +34,8 @@ const HERO_SIZE_CLASSES = "text-[clamp(1.125rem,5.6vw,4rem)]" export function Hero() { const [phraseIndex, setPhraseIndex] = useState(0) + /** 「作者卡片」展开状态:点署名展开,再点收起 */ + const [cardOpen, setCardOpen] = useState(false) const [displayText, setDisplayText] = useState("") const [isDeleting, setIsDeleting] = useState(false) // Pause the typewriter loop when the hero is offscreen or the tab is hidden; @@ -159,14 +164,62 @@ export function Hero() { {site.tagline}

- {/* 光标是 CSS ::after 画的一个竖线字符,见 styles/global.css 的 .hero-typewriter */} -

- {renderText()} -

+ {/* + 彩蛋:这句话出自王小波《万寿寺》。 + - 悬停/聚焦:整句话由墨黑变朱红,下方淡入署名(无 hover 的设备常显署名) + - 点那句话 → 直接去豆瓣人物页 + - 点署名 → 展开一张极简卡片,卡片里也能去豆瓣 -
+ 结构上用

而不是把 h1 本身变成链接:保住标题语义, + 而且点击热区只包住文字,不会连整行空白一起可点。 + 光标 ::after 挂在 h1 上(链接外面),点光标不会触发跳转。 + */} +
+

+ + {renderText()} + +

+ + {/* 固定高度的一行,内容 hover 才淡入 —— 这样展开卡片时按钮不会跳 */} +
+ +
+ +
+
+ + 王小波1952–1997 + + + 豆瓣主页 + +
+
+
+ +