Files
pangolin/web/website/src/layouts/Site.astro
T
wangjia f37f1f3b59
ci-pangolin / Lint — shellcheck (pull_request) Successful in 10s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 29s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 32s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 21s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 24s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 21s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 10s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 8s
ci-pangolin / Go — build + test (pull_request) Successful in 10s
Deploy Site / deploy-site (push) Successful in 2m33s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m33s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Successful in 19s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 13m16s
feat(web): 修语言下拉漂移(class 化)+ 主页登录态用户中心按钮 + 用户中心返回主页
#1 官网语言下拉漂移:根因=官网 CSP 无 unsafe-inline,Header.jsx 下拉全用内联
style= 被浏览器拦→菜单飘视口右边。修:搬进 website.css 的 .langwrap/.langsel
/.langmenu/.langmenu a(全走 var(--token),right:0 锚按钮下方,min-width 160
加宽),Header.jsx 删净内联 style。

#2 主页登录态右上角「用户中心」按钮:Header.jsx 读同源 localStorage
'pg_uc_refresh',有则 .linklogin 位显「用户中心」(→ /user/)、无则「Log in」。
i18n nav.center 6 语言。

#3 用户中心「返回主页」按钮:UserCenter.tsx 顶栏加 <a href="/">(home 图标),
i18n backHome 6 语言。

顺带堵同源闸漏洞:check-l1-sync ③ 原只匹配带引号图标键('refresh-cw'),漏了
裸标识符键(home),导致新加的 home 未被校验就通过。修解析器匹配裸键;并按
ds-flow 把 home 登记进 design/prototype/icons.js。同源闸复跑绿(裸键现全受检)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:16:13 +08:00

99 lines
3.7 KiB
Plaintext
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.
---
/**
* Site.astro — 官网整页布局(构建期单显一种语言)。
* 两条路由复用:/ → lang="zh"/en/ → lang="en"(铁律 6 单显不并排)。
*
* 样式来源顺序(全部自托管,无第三方 CDN):
* @fontsource/* → 自托管字体 @font-face(替代原型的 Google Fonts CDN
* tokens.gen.css → 由 design/colors_and_type.css 生成(唯一令牌真相源)
* website.css → 逐字迁自 ui_kits/website
* site-extra.css → 仅承载「原型内联 style= → class」的等价工具类
*/
import '@fontsource/sora/500.css';
import '@fontsource/sora/600.css';
import '@fontsource/sora/700.css';
import '@fontsource/manrope/400.css';
import '@fontsource/manrope/500.css';
import '@fontsource/manrope/600.css';
import '@fontsource/manrope/700.css';
import '@fontsource/noto-sans-sc/400.css';
import '@fontsource/noto-sans-sc/500.css';
import '@fontsource/noto-sans-sc/700.css';
import '@fontsource/jetbrains-mono/400.css';
import '@fontsource/jetbrains-mono/500.css';
import '../styles/tokens.gen.css';
import '../styles/website.css';
import '../styles/site-extra.css';
import { createT, type Lang } from '../i18n/strings';
import Header from '../components/Header.jsx';
import AnnouncementBar from '../components/AnnouncementBar.jsx';
import Hero from '../components/Hero.astro';
import Features from '../components/Features.astro';
import WhySignup from '../components/WhySignup.astro';
import Pricing from '../components/Pricing.astro';
import Download from '../components/Download.astro';
import Docs from '../components/Docs.astro';
// Blog 区暂隐藏(占位内容未就绪);有真实文章后恢复 import + <Blog/> + 导航/页脚链接。
import CtaBand from '../components/CtaBand.astro';
import Footer from '../components/Footer.astro';
interface Props { lang: Lang }
const { lang } = Astro.props;
const t = createT(lang);
// 语言 → <html lang> / og:locale / 路由前缀(默认 en = /,其余 /<lang>/)。
const HTML_LANG: Record<Lang, string> = { zh: 'zh-CN', en: 'en', ja: 'ja', ko: 'ko', ru: 'ru', es: 'es' };
const OG_LOCALE: Record<Lang, string> = { zh: 'zh_CN', en: 'en_US', ja: 'ja_JP', ko: 'ko_KR', ru: 'ru_RU', es: 'es_ES' };
const ALL_LANGS: Lang[] = ['en', 'zh', 'ja', 'ko', 'ru', 'es'];
const langPath = (l: Lang) => (l === 'en' ? '/' : `/${l}/`);
const headerT = {
product: t('nav.product'),
pricing: t('nav.pricing'),
download: t('nav.download'),
docs: t('nav.docs'),
blog: t('nav.blog'),
login: t('nav.login'),
center: t('nav.center'),
get: t('nav.get'),
suBtn: t('su.btn'),
};
---
<!doctype html>
<html lang={HTML_LANG[lang]}>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{t('meta.title')}</title>
<meta name="description" content={t('meta.desc')} />
<meta name="robots" content="index,follow" />
<link rel="canonical" href={new URL(langPath(lang), Astro.site).href} />
{ALL_LANGS.map((l) => (
<link rel="alternate" hreflang={HTML_LANG[l]} href={new URL(langPath(l), Astro.site).href} />
))}
<link rel="alternate" hreflang="x-default" href={new URL('/', Astro.site).href} />
<meta name="theme-color" content="#B96A3D" />
<meta property="og:type" content="website" />
<meta property="og:title" content={t('meta.title')} />
<meta property="og:description" content={t('meta.desc')} />
<meta property="og:locale" content={OG_LOCALE[lang]} />
</head>
<body>
<AnnouncementBar client:idle text={t('ann.txt')} cta={t('ann.cta')} />
<Header client:load lang={lang} t={headerT} />
<a id="top"></a>
<Hero t={t} />
<Features t={t} />
<WhySignup t={t} />
<Pricing t={t} lang={lang} />
<Download t={t} />
<Docs t={t} />
<CtaBand t={t} />
<Footer t={t} />
</body>
</html>