Initial commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
谢宇宁
2026-10-27 16:23:48 +07:00
co-authored by Claude Opus 5.5
commit 8cdbfee08f
345 changed files with 20773 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
import type { PageHead } from '../seo';
import { JSON_LD_ATTRIBUTE, serializeStructuredData } from '../structured-data';
/** Update the existing SSR tags and remove stale/duplicate tags after SPA navigation. */
export function applyPageHead(head:PageHead,doc:Document=document):void {
doc.title=head.title;
function tag(selector:string,element:'meta'|'link',attributes:Record<string,string>,value:string|undefined){
const matches=Array.from(doc.head.querySelectorAll(selector));
const node=matches.shift();matches.forEach(item=>item.remove());
if(!value){node?.remove();return;}
const target=node||doc.createElement(element);
for(const [name,content] of Object.entries(attributes))target.setAttribute(name,content);
target.setAttribute(element==='meta'?'content':'href',value);
if(!node)doc.head.appendChild(target);
}
const meta=(name:string,value:string|undefined)=>tag(`meta[name="${name}"]`,'meta',{name},value);
const og=(property:string,value:string|undefined)=>tag(`meta[property="${property}"]`,'meta',{property},value);
const link=(rel:string,value:string|undefined)=>tag(`link[rel="${rel}"]`,'link',{rel},value);
meta('description',head.description);meta('keywords',head.keywords.join(','));meta('application-name',head.siteName);
meta('robots',head.robots);meta('googlebot',head.robots);
link('canonical',head.canonical);link('prev',head.previous);link('next',head.next);
og('og:locale','zh_CN');og('og:type',head.type);og('og:site_name',head.siteName);
og('og:title',head.title);og('og:description',head.description);og('og:url',head.canonical);og('og:image',head.image||undefined);
og('og:image:width',head.image?'1200':undefined);og('og:image:height',head.image?'630':undefined);og('og:image:alt',head.image?head.siteName:undefined);
meta('twitter:card','summary_large_image');meta('twitter:title',head.title);meta('twitter:description',head.description);
meta('twitter:image',head.image||undefined);meta('twitter:image:alt',head.image?head.siteName:undefined);
const selector=`script[${JSON_LD_ATTRIBUTE}]`;
const scripts=[...new Set([...doc.head.querySelectorAll(selector),...doc.querySelectorAll(selector)])];
const script=scripts.shift();scripts.forEach(item=>item.remove());
if(!head.jsonLd){script?.remove();return;}
const target=script||doc.createElement('script');
target.setAttribute('id','site-json-ld');target.setAttribute('type','application/ld+json');target.setAttribute(JSON_LD_ATTRIBUTE,'');
target.textContent=serializeStructuredData(head.jsonLd);
if(!script)doc.head.appendChild(target);
}