移除旧版 HTML 模板与兼容层,并完善私信、举报、媒体存储与 SEO。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,21 +4,53 @@ import type { SiteBranding } from '../api/types';
|
||||
|
||||
export const DEFAULT_BRANDING: SiteBranding = {
|
||||
name: '姜十三论坛',
|
||||
name_en: 'Jiang13 Forum',
|
||||
slogan: '拾三一隅,自在交流',
|
||||
description: '',
|
||||
keywords: '',
|
||||
logo_mark: '姜',
|
||||
logo: '',
|
||||
favicon: '',
|
||||
og_image: '',
|
||||
icp_beian: '',
|
||||
icp_beian_url: 'https://beian.miit.gov.cn/',
|
||||
friend_links: [],
|
||||
};
|
||||
|
||||
let cached: SiteBranding | null = null;
|
||||
declare global {
|
||||
interface Window {
|
||||
/** 服务端注入的首屏品牌配置(见 embed_static SPA HTML) */
|
||||
__J13_BRANDING__?: Partial<SiteBranding>;
|
||||
}
|
||||
}
|
||||
|
||||
/** SEO / 首页展示用简介:优先 description,其次 slogan */
|
||||
export function siteMetaDescription(brand: SiteBranding): string {
|
||||
const d = brand.description?.trim() ?? '';
|
||||
if (d) return d;
|
||||
return brand.slogan?.trim() ?? '';
|
||||
}
|
||||
|
||||
/** 从服务端注入的 boot 数据同步初始化,避免首屏闪默认站名 */
|
||||
function readBootBranding(): SiteBranding | null {
|
||||
try {
|
||||
const boot = window.__J13_BRANDING__;
|
||||
if (!boot || typeof boot !== 'object') return null;
|
||||
const name = typeof boot.name === 'string' ? boot.name.trim() : '';
|
||||
if (!name) return null;
|
||||
return { ...DEFAULT_BRANDING, ...boot, name };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let cached: SiteBranding | null = readBootBranding();
|
||||
let inflight: Promise<SiteBranding> | null = null;
|
||||
let cacheEpoch = 0;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
function fetchBranding(): Promise<SiteBranding> {
|
||||
if (cached) return Promise.resolve(cached);
|
||||
if (inflight) return inflight;
|
||||
// 有 boot/缓存时首屏已可用;仍请求 API 以同步最新配置
|
||||
inflight = api.siteBranding()
|
||||
.then(b => {
|
||||
cached = { ...DEFAULT_BRANDING, ...b };
|
||||
@@ -37,8 +69,11 @@ export function formatDocumentTitle(brand: SiteBranding): string {
|
||||
}
|
||||
|
||||
function applyDocumentBrand(brand: SiteBranding) {
|
||||
const title = formatDocumentTitle(brand);
|
||||
if (document.title !== title) document.title = title;
|
||||
// 页面级 SEO hook 已接管标题时,勿覆盖
|
||||
if (!document.documentElement.hasAttribute('data-j13-seo')) {
|
||||
const title = formatDocumentTitle(brand);
|
||||
if (document.title !== title) document.title = title;
|
||||
}
|
||||
|
||||
let link = document.querySelector<HTMLLinkElement>('link[rel="icon"]');
|
||||
if (brand.favicon) {
|
||||
@@ -53,6 +88,11 @@ function applyDocumentBrand(brand: SiteBranding) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 同步读取已缓存的品牌配置(供 SEO 等非 hook 场景) */
|
||||
export function getCachedSiteBranding(): SiteBranding {
|
||||
return cached ?? DEFAULT_BRANDING;
|
||||
}
|
||||
|
||||
/** 获取站点品牌配置(名称、Logo 等) */
|
||||
export function useSiteBranding() {
|
||||
const [branding, setBranding] = useState<SiteBranding>(cached ?? DEFAULT_BRANDING);
|
||||
|
||||
Reference in New Issue
Block a user