This commit is contained in:
z.ai committed 2026-10-08 11:09:37 +08:00
1 parent c1541b80df
commit b4c7908029
97 files changed
+12403 -154

No files matched your search

+107
View File
@@ -0,0 +1,107 @@
import { Link } from "@/i18n/navigation";
import { getTranslations } from "next-intl/server";
import { Mail, Rss, SquareArrowOutUpRight } from "lucide-react";
import { siteConfig } from "@/lib/site-config";
/**
* 社交链接图标。
*
* 注意:lucide-react v1.x 已移除品牌图标(Github / Twitter 等),
* 因此这里使用通用图标,由 `label` 文本承载具体含义——
* 图标仅作装饰(aria-hidden),可访问性不依赖它。
*/
const SOCIAL_ICONS = {
github: SquareArrowOutUpRight,
twitter: Rss,
mail: Mail,
} as const;
/**
* 站点页脚。
*
* DESIGN.md 的 footer-region:白底上一道 hairline 顶边,多列分组,
* 分栏标题用 body-sm-medium 深色,链接用 body-sm 灰色。
*/
export async function SiteFooter() {
const t = await getTranslations("Footer");
const tNav = await getTranslations("Nav");
const year = new Date().getFullYear();
return (
<footer className="border-t border-hairline bg-canvas">
<div className="mx-auto w-full max-w-[1280px] px-lg py-section sm:px-xxl">
<div className="grid grid-cols-1 gap-xxl sm:grid-cols-2 lg:grid-cols-4">
{/* 品牌列 */}
<div className="flex flex-col gap-sm lg:col-span-2">
<div className="flex items-center gap-xs text-body-md font-semibold text-ink">
<span
aria-hidden="true"
className="grid size-7 place-items-center rounded-md bg-primary font-mono text-caption font-semibold text-brand-green"
>
&gt;_
</span>
{siteConfig.name}
</div>
<p className="max-w-[360px] text-body-sm text-steel">
{siteConfig.description}
</p>
</div>
{/* 导航列 */}
<nav aria-label={t("navigation")} className="flex flex-col gap-xs">
<h2 className="mb-xs text-body-sm font-medium text-ink">
{t("navigation")}
</h2>
<Link
href="/"
className="py-xxs text-body-sm text-steel transition-colors duration-150 hover:text-ink"
>
{tNav("home")}
</Link>
<Link
href="/about"
className="py-xxs text-body-sm text-steel transition-colors duration-150 hover:text-ink"
>
{tNav("about")}
</Link>
</nav>
{/* 社交列 */}
<div className="flex flex-col gap-xs">
<h2 className="mb-xs text-body-sm font-medium text-ink">
{t("elsewhere")}
</h2>
<ul className="flex flex-col gap-xxs">
{siteConfig.social.map((item) => {
const Icon = SOCIAL_ICONS[item.icon];
return (
<li key={item.label}>
<a
href={item.href}
target={item.href.startsWith("mailto:") ? undefined : "_blank"}
rel="noopener noreferrer"
className="inline-flex items-center gap-xs py-xxs text-body-sm text-steel transition-colors duration-150 hover:text-ink"
>
<Icon className="size-4" aria-hidden="true" />
{item.label}
</a>
</li>
);
})}
</ul>
</div>
</div>
<div className="mt-xxl flex flex-col gap-xs border-t border-hairline-soft pt-lg text-caption text-steel sm:flex-row sm:items-center sm:justify-between">
<p>
© {year} {siteConfig.name}. {t("rights")}
</p>
<p className="font-mono">{t("builtWith")}</p>
</div>
</div>
</footer>
);
}