去重「我的介绍」:页脚改放站点信息卡片,关于页入口只留在侧栏
「我的介绍」重复 - 页脚原来那栏和侧栏作者卡片是同一份内容(同头像、同站名、同一句签名), 手机端首页从头刷到尾会看到两次 - 页脚那栏整栏删除,只保留侧栏作者卡片 - 空出来的左侧位置给站点信息卡片 站点信息改成卡片 - 从原来横跨全宽的裸信息带,改成和侧栏作者卡片/分类卡片同一套语言: bg-card + border-border/50 + rounded-xl + p-5,标题带那道红色短竖线 - 内部 2 列 × 3 行:建站时间 / 已运行 / 文章 / 偶得 / 总字数 / 最近更新 - 桌面页脚高 529 -> 476px;手机 822 -> 760px(相比最初的 957px 共省 197px) 关于页入口 - 只留在侧栏作者卡片:站名和签名两行包在同一个 <a href="/about/"> 里 - 按要求去掉所有 hover 装饰(原来有头像描边转主色、站名转主色、箭头位移), 也不再放「关于我 →」提示,两行就是安静的文字链接 - 头像不参与:下面社交图标本身是 <a>,<a> 不能嵌套 <a> 验证(headless Chrome 131,禁用缓存) - 页脚站点信息卡片计算样式:bg oklch(0.98 0.011 84)、border 1px …/0.5、 radius 12px、padding 20px,与侧栏卡片一致 - 页脚内已无「时之刃的小站 / 只是将博客作为新的爱好的普通人」字样 - 侧栏 <a> href=/about/,链接文本为「时之刃只是将博客作为新的爱好的普通人!」, className 为空(无 hover 类);点名字跳转 /about/ 正常 - a a 嵌套数 0,无横向溢出;桌面/手机截图正常
This commit is contained in:
@@ -241,18 +241,17 @@ prose-p:leading-[1.78] md:prose-p:leading-[1.85]
|
|||||||
|
|
||||||
| 区块 | 内容 | 显示范围 |
|
| 区块 | 内容 | 显示范围 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 我的介绍 | 头像 + 站名 + 签名,**整块可点去 `/about/`** | 全部 |
|
| 站点信息卡片 | 建站时间 / 已运行 / 文章 / 偶得 / 总字数 / 最近更新,卡片样式沿用侧栏作者卡片 | 全部 |
|
||||||
| 最新文章 | 最近 4 篇(按发布时间倒序,不把置顶提前) | 桌面 |
|
| 最新文章 | 最近 4 篇(按发布时间倒序,不把置顶提前) | 桌面 |
|
||||||
| 联系 | 社交图标 + 订阅 RSS | 全部 |
|
| 联系 | 社交图标 + 订阅 RSS | 全部 |
|
||||||
| 站点信息 | 建站时间 / 已运行 / 文章 / 偶得 / 总字数 / 最近更新 | 全部(想只在桌面显示就给它加 `hidden md:grid`) |
|
|
||||||
| 底栏 | 版权 / 备案 / 主题署名 | 全部 |
|
| 底栏 | 版权 / 备案 / 主题署名 | 全部 |
|
||||||
|
|
||||||
**原来的「导航」栏已删除** —— 它是顶部导航的逐项复制(9 条名字和目标完全一样),手机上白占 312px。桌面端改用「最新文章」,把重复变成发现。不影响 SEO:顶部导航和移动端菜单里的链接在每页 HTML 里都还在。
|
两处**刻意不放**的东西:
|
||||||
|
|
||||||
两点需要注意:
|
- **「导航」栏已删除** —— 它是顶部导航的逐项复制(9 条名字和目标完全一样),手机上白占 312px。桌面端改用「最新文章」,把重复变成发现。不影响 SEO:顶部导航和移动端菜单里的链接在每页 HTML 里都还在。
|
||||||
|
- **页脚不再放「我的介绍」** —— 侧栏作者卡片已经有了,再放一份是重复。页脚那份的视觉位置让给了站点信息卡片。
|
||||||
|
|
||||||
- **「我的介绍」整块包 `<a>` 是合法的**,因为这一块里没有别的链接。但**侧栏的作者卡片不行** —— 它下面有社交图标(本身是 `<a>`),`<a>` 不能嵌套。所以那里只包到签名那一段。
|
「我的介绍 → 关于页」在**侧栏作者卡片**里(`sidebar.tsx`):站名和签名那两行包在同一个 `<a href="/about/">` 里,不做 hover 装饰。只能包这两行——下面的社交图标本身是 `<a>`,`<a>` 不能嵌套 `<a>`。`aria-label` 是必须的,否则读屏会把「站名 + 签名」念成链接名。
|
||||||
- 整块链接要给 `aria-label`,否则读屏会把「头像 alt + 站名 + 签名」整段念成链接名。
|
|
||||||
|
|
||||||
统计数据在 `src/lib/site-stats.ts`:文章数/偶得数/分类数/标签数/总字数在构建时算,「已运行 N 天」和「最近更新」由页脚里的内联脚本按**真实时间**刷新(站点久不重建也不会停在构建那天),服务端会先渲染一份构建时兜底值,关 JS 也不空。加减统计项改 `footer.astro` 里的 `statCells` 数组即可。
|
统计数据在 `src/lib/site-stats.ts`:文章数/偶得数/分类数/标签数/总字数在构建时算,「已运行 N 天」和「最近更新」由页脚里的内联脚本按**真实时间**刷新(站点久不重建也不会停在构建那天),服务端会先渲染一份构建时兜底值,关 JS 也不空。加减统计项改 `footer.astro` 里的 `statCells` 数组即可。
|
||||||
|
|
||||||
|
|||||||
+20
-36
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import type { ComponentType, SVGProps } from "react"
|
import type { ComponentType, SVGProps } from "react"
|
||||||
import { ArrowRight, Github, Mail, Music, Rss } from "lucide-react"
|
import { Github, Mail, Music, Rss } from "lucide-react"
|
||||||
import { QqIcon } from "@/components/icons/qq-icon"
|
import { QqIcon } from "@/components/icons/qq-icon"
|
||||||
import { profile, type ExternalProfileLink, type ExternalProfileLinkType } from "@/data/profile"
|
import { profile, type ExternalProfileLink, type ExternalProfileLinkType } from "@/data/profile"
|
||||||
import { site } from "@/data/site"
|
import { site } from "@/data/site"
|
||||||
@@ -32,30 +32,27 @@ const statCells = [
|
|||||||
<div class="max-w-6xl mx-auto px-6 py-16">
|
<div class="max-w-6xl mx-auto px-6 py-16">
|
||||||
<div class="grid gap-12 md:grid-cols-3">
|
<div class="grid gap-12 md:grid-cols-3">
|
||||||
{/*
|
{/*
|
||||||
我的介绍:整块可点去关于页(这里没有嵌套链接,所以整块包 <a> 是合法的)。
|
站点信息卡片:沿用侧栏作者卡片/分类卡片的语言
|
||||||
aria-label 是为了不让读屏把头像 alt + 站名 + 签名全念成链接名。
|
(bg-card + border/50 + rounded-xl + 红色短竖线标题)。
|
||||||
|
「我的介绍」不在这里重复展示 —— 侧栏作者卡片已经有了。
|
||||||
*/}
|
*/}
|
||||||
<a href="/about/" class="group block" aria-label={`关于 ${profile.name}`}>
|
<div class="bg-card border border-border/50 rounded-xl p-5">
|
||||||
<div class="flex items-center gap-3 mb-4">
|
<div class="flex items-center gap-2 mb-4">
|
||||||
<div class="w-8 h-8 rounded-full overflow-hidden border border-primary/20 bg-secondary transition-colors duration-200 group-hover:border-primary/60">
|
<div class="w-1 h-4 bg-primary rounded-full" />
|
||||||
<img
|
<h4 class="font-medium text-foreground">站点信息</h4>
|
||||||
src={profile.avatar}
|
</div>
|
||||||
alt={profile.name}
|
<div class="grid grid-cols-2 gap-x-4 gap-y-4">
|
||||||
loading="lazy"
|
{statCells.map((cell) => (
|
||||||
decoding="async"
|
<div>
|
||||||
class="w-full h-full object-cover"
|
<div class="text-xs text-muted-foreground mb-1">{cell.label}</div>
|
||||||
/>
|
<div class="text-sm text-foreground font-medium tabular-nums">
|
||||||
|
<span data-stat={cell.live}>{cell.value}</span>
|
||||||
|
{cell.unit && <span class="text-xs text-muted-foreground ml-0.5">{cell.unit}</span>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<span class="text-foreground font-medium transition-colors duration-200 group-hover:text-primary">
|
|
||||||
{site.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="text-muted-foreground text-sm leading-relaxed">{profile.bio}</p>
|
|
||||||
<span class="mt-3 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors duration-200 group-hover:text-primary">
|
|
||||||
关于我
|
|
||||||
<ArrowRight class="w-3 h-3 transition-transform duration-200 group-hover:translate-x-0.5" />
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
最新文章:手机端上面就是文章列表,再列一遍没意义,所以只在 md 以上显示。
|
最新文章:手机端上面就是文章列表,再列一遍没意义,所以只在 md 以上显示。
|
||||||
@@ -109,21 +106,8 @@ const statCells = [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 站点信息:桌面 6 列一行,手机 3 列两行 */}
|
|
||||||
<div class="mt-14 pt-8 border-t border-border/50 grid grid-cols-3 gap-x-4 gap-y-6 md:grid-cols-6">
|
|
||||||
{statCells.map((cell) => (
|
|
||||||
<div>
|
|
||||||
<div class="text-xs text-muted-foreground mb-1.5">{cell.label}</div>
|
|
||||||
<div class="text-foreground font-medium tabular-nums">
|
|
||||||
<span data-stat={cell.live}>{cell.value}</span>
|
|
||||||
{cell.unit && <span class="text-xs text-muted-foreground ml-0.5">{cell.unit}</span>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Bottom */}
|
{/* Bottom */}
|
||||||
<div class="mt-10 pt-8 border-t border-border/50 grid gap-4 md:grid-cols-3">
|
<div class="mt-14 pt-8 border-t border-border/50 grid gap-4 md:grid-cols-3">
|
||||||
<p class="text-muted-foreground text-sm">
|
<p class="text-muted-foreground text-sm">
|
||||||
© {site.startDate.slice(0, 4)} {profile.name}. All rights reserved.
|
© {site.startDate.slice(0, 4)} {profile.name}. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, type ReactNode } from "react"
|
import { useState, type ReactNode } from "react"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { ArrowRight, Calendar } from "lucide-react"
|
import { Calendar } from "lucide-react"
|
||||||
import { profile } from "@/data/profile"
|
import { profile } from "@/data/profile"
|
||||||
import { ProfileContactLink } from "@/components/profile-contact-link"
|
import { ProfileContactLink } from "@/components/profile-contact-link"
|
||||||
|
|
||||||
@@ -39,29 +39,23 @@ export function Sidebar({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-full lg:w-72 shrink-0 space-y-8">
|
<aside className="w-full lg:w-72 shrink-0 space-y-8">
|
||||||
{/* Author Card —— 头像/站名/签名整块可点,跳关于页。
|
{/* Author Card —— 站名和签名两行各自可点去关于页,不做 hover 装饰。
|
||||||
注意只能包到这里:下面的社交图标本身是 <a>,<a> 不能嵌套 <a>。
|
头像不参与:整块包 <a> 会把下面的社交图标(本身是 <a>)套进去,
|
||||||
aria-label 是为了不让读屏把头像 alt + 站名 + 签名整段念成链接名。 */}
|
<a> 不能嵌套 <a>,所以只包名字 + 分隔线 + 签名这一小段。 */}
|
||||||
<div className="bg-card border border-border/50 rounded-xl p-6 text-center">
|
<div className="bg-card border border-border/50 rounded-xl p-6 text-center">
|
||||||
<a href="/about/" className="group block" aria-label={`关于 ${profile.name}`}>
|
<div className="w-24 h-24 mx-auto mb-4 rounded-full overflow-hidden border-2 border-primary/20">
|
||||||
<div className="w-24 h-24 mx-auto mb-4 rounded-full overflow-hidden border-2 border-primary/20 transition-colors duration-200 group-hover:border-primary/60">
|
|
||||||
<img
|
<img
|
||||||
src={profile.avatar}
|
src={profile.avatar}
|
||||||
alt={profile.name}
|
alt={profile.name}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-serif text-xl font-bold text-foreground mb-1 transition-colors duration-200 group-hover:text-primary">
|
<a href="/about/" aria-label={`关于 ${profile.name}`}>
|
||||||
{profile.name}
|
<h3 className="font-serif text-xl font-bold text-foreground mb-1">{profile.name}</h3>
|
||||||
</h3>
|
|
||||||
<div className="w-8 h-0.5 bg-primary mx-auto mb-3" />
|
<div className="w-8 h-0.5 bg-primary mx-auto mb-3" />
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed">{profile.bio}</p>
|
<p className="text-sm text-muted-foreground leading-relaxed">{profile.bio}</p>
|
||||||
<span className="mt-2 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors duration-200 group-hover:text-primary">
|
|
||||||
关于我
|
|
||||||
<ArrowRight className="w-3 h-3 transition-transform duration-200 group-hover:translate-x-0.5" />
|
|
||||||
</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{/* Social Links */}
|
{/* Social Links */}
|
||||||
|
|||||||
Reference in New Issue
Block a user