Files
jiang13-forum/frontend/src/components/SiteFooter.tsx
freefire 44eed97fe0 feat: 首页 Go SSR 与 React hydrate 同构,消壳层与帖行闪动
补齐侧栏/右栏图标与徽章、鉴权种子、StaticFeedList,并修正嵌套 a 与标题徽章对齐。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 07:07:38 +08:00

93 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useSiteBranding } from '../hooks/useSiteBranding';
import { useMediaQuery } from '../hooks/useTheme';
import { Link } from 'react-router-dom';
import { useSitePages } from '../hooks/useSitePages';
import { pagePath } from '../utils/permalink';
import { useForumLimits } from '../hooks/useForumLimits';
function FooterSep() {
return <span className="site-footer__sep" aria-hidden>·</span>;
}
/** 站点页脚:版权、友链/展柜入口、单页、备案号(结构与 Go writeSSRFooter 对齐) */
export default function SiteFooter() {
const { branding } = useSiteBranding();
const { footerPages } = useSitePages();
const { limits } = useForumLimits();
const year = new Date().getFullYear();
const icp = branding.icp_beian?.trim() || '';
const icpURL = branding.icp_beian_url?.trim() || 'https://beian.miit.gov.cn/';
const showFriendLinks = limits.footer_show_friend_links !== false;
const showShowcase = !!limits.footer_show_showcase;
const navItems: React.ReactNode[] = [];
if (showFriendLinks) {
navItems.push(
<span key="links" className="site-footer__friend">
<Link to="/links"></Link>
</span>,
);
}
if (showShowcase) {
navItems.push(
<span key="showcase" className="site-footer__friend">
<Link to="/showcase"></Link>
</span>,
);
}
for (const p of footerPages) {
navItems.push(
<span key={p.slug} className="site-footer__friend">
<Link to={pagePath(p.slug, limits)}>{p.title}</Link>
</span>,
);
}
if (icp) {
navItems.push(
<a
key="icp"
href={icpURL}
target="_blank"
rel="noopener noreferrer"
className="site-footer__icp"
>
{icp}
</a>,
);
}
return (
<footer className="site-footer">
<div className="site-footer__inner">
<div className="site-footer__meta">
<span className="site-footer__copy">
© {year} {branding.name}
</span>
{branding.slogan?.trim() && (
<>
<FooterSep />
<span className="site-footer__slogan">{branding.slogan.trim()}</span>
</>
)}
</div>
<nav className="site-footer__nav" aria-label="站点链接">
{navItems.flatMap((node, i) =>
i === 0 ? [node] : [<FooterSep key={`sep-${i}`} />, node],
)}
</nav>
</div>
</footer>
);
}
/**
* 手机端随内容滚动的页脚(放在 .page-wrap / .post-list-scroll 末尾)。
* 桌面端返回 null由 MainLayout 壳层贴底页脚负责。
*/
export function InFlowSiteFooter() {
const isMobile = useMediaQuery('(max-width: 768px)');
if (!isMobile) return null;
return <SiteFooter />;
}