架构¶
技术栈¶
层级 |
技术 |
|---|---|
框架 |
Next.js 15 (App Router) |
UI 库 |
React 19 |
语言 |
TypeScript 5.7 |
设计系统 |
IBM Carbon Design System ( |
样式 |
SCSS + Carbon 令牌 |
Markdown |
react-markdown + remark-gfm + remark-math |
数学公式渲染 |
KaTeX (rehype-katex) |
图表 |
Mermaid.js |
测试 |
Vitest + React Testing Library + jsdom |
CMS |
Strapi v5 (无头模式) |
项目结构¶
www/
├── public/ Static assets (fonts, images)
│ ├── fonts/ Custom typeface (SyriusSans)
│ └── images/ Homepage assets, blog placeholder
├── scripts/ Seed and mock scripts
│ ├── mock-strapi.mjs Mock Strapi v5 server
│ ├── seed-blog-articles.mjs Seed 9 articles to real Strapi
│ ├── seed-blog-content.mjs Article content definitions
│ └── seed-blog-edge-cases.mjs 11 edge-case test articles
├── src/
│ ├── app/ Next.js App Router pages
│ │ ├── [locale]/ Locale-scoped routes
│ │ │ ├── blog/ Blog listing, detail, filters
│ │ │ ├── gallery/ Gallery listing, detail
│ │ │ └── [slug]/ CMS-driven dynamic pages
│ │ ├── robots.ts SEO robots.txt
│ │ └── sitemap.ts Dynamic sitemap generator
│ ├── components/ React components
│ │ ├── homepage/ Static homepage fallback
│ │ └── sections/ CMS section renderers
│ ├── lib/ Core utilities
│ │ ├── strapi.ts Server-side Strapi API client
│ │ ├── types.ts TypeScript interfaces
│ │ ├── i18n.ts Locale config + translations
│ │ └── consoleUrl.ts Runtime console/stargate URL derivation
│ ├── styles/ SCSS stylesheets
│ │ ├── _tokens.scss Carbon Design imports
│ │ ├── globals.scss Root styles and themes
│ │ ├── layout.scss Layout components
│ │ ├── homepage.scss Homepage styles
│ │ └── sections.scss Page section styles
│ ├── middleware.ts Locale routing middleware
│ └── __tests__/ Vitest unit tests
└── docs/ This documentation (Sphinx)
路由¶
所有路由均带有语言前缀。src/middleware.ts 中的中间件执行以下逻辑:
对
/_next、/api、/fonts或静态文件的请求直接放行如果路径的第一段是有效的语言代码(
en、zh-CN、ja),则请求直接放行否则,从
Accept-Language请求头中检测用户的首选语言,并将用户重定向到/{locale}{path}
路由映射¶
路由 |
描述 |
|---|---|
|
首页(CMS 内容或静态回退页面) |
|
博客列表(分页,每页 5 篇) |
|
文章详情页 |
|
分类视图(该分类下的所有文章) |
|
标签筛选(分页,每页 5 篇) |
|
图库列表(分页,每页 12 项) |
|
图库合集详情 |
|
CMS 驱动的动态页面 |
组件¶
布局组件¶
Navbar --- Header with logo, nav links, theme toggle, locale switcher, StarGate admin sign-in link, login button, mobile hamburger menu. The admin link (
adminUrl) points tostargate.{domain}and is derived at runtime from the current hostname (seeconsoleUrl.tsbelow), so it automatically resolves to the correct partition (.aior.com).Footer --- 3 accordion sections (Platform, Services, Company), legal links, copyright. The "Services" section includes a "My Account" link (to StartPoint) and an "Admin" link (to StarGate), both using runtime-derived URLs.
ThemeProvider --- Dark/light mode context (
white/g100Carbon themes). Persists the user's choice to a cross-subdomain cookie (fg-theme, scoped to.flexgalaxy.aior.flexgalaxy.com) so the preference carries over to console apps. Falls back tolocalStorageand thenprefers-color-schememedia query.LocaleSwitcher --- Language dropdown preserving current path. On mount and on every language switch it writes a cross-subdomain cookie (
fg-lang) so other apps on the same base domain can pick up the preferred locale.CookieConsent --- GDPR 横幅,提供必要/性能/广告 Cookie 开关
内容组件¶
ArticleCard --- 博客预览卡片,包含封面图、分类链接、标题、摘要和标签。通过
::after伪元素覆盖层实现整张卡片可点击RichMarkdown --- Markdown 渲染器,支持 GFM、KaTeX 数学公式、原始 HTML 和 Mermaid 图表
MermaidBlock --- 延迟加载 Mermaid 库,使用 Carbon 蓝色主题渲染 SVG,出错时回退显示原始代码
CategoryArticleViewer --- 分类页面布局,包含侧边栏文章列表、文章内容区域和目录侧边栏
Pagination --- 上一页/下一页按钮及页码指示器
ErrorState --- 将 HTTP 状态码映射为本地化错误页面
CMS 区块组件¶
SectionRenderer 负责分发 Strapi 动态区域组件:
|
组件 |
|---|---|
|
HeroSection |
|
FeatureGridSection |
|
RichTextSection |
|
CallToActionSection |
|
ImageGallerySection |
样式¶
所有样式均使用 SCSS 编写,并通过 _tokens.scss 导入 IBM Carbon Design 令牌。定义了以下四个响应式断点:
令牌 |
宽度 |
|---|---|
|
320px |
|
672px |
|
1056px |
|
1584px |
主题切换通过 <html> 元素上的 data-carbon-theme 属性以纯 CSS 方式驱动,在 white``(浅色)和 ``g100``(深色)Carbon 主题之间切换。所有颜色均引用 CSS 自定义属性(例如 ``var(--cds-text-primary))。
Runtime URL Derivation¶
External URLs (Console, StarGate) are derived at runtime from the
browser's current hostname, not from build-time environment variables.
This is implemented in src/lib/consoleUrl.ts via the
useConsoleUrls() React hook.
The hook inspects window.location.hostname to determine:
Base domain --- the last two segments of the hostname (e.g.,
flexgalaxy.aiorflexgalaxy.com)Environment prefix ---
dev-if the hostname starts withdev-, empty otherwise
It then constructs:
startUrl=https://{prefix}console.{baseDomain}/start/signupUrl=https://{prefix}console.{baseDomain}/start/?register=trueadminUrl=https://{prefix}stargate.{baseDomain}
This means the same build artifact works on both .ai (international) and
.com (China) deployments without rebuild. The NEXT_PUBLIC_START_URL
and NEXT_PUBLIC_SIGNUP_URL environment variables serve only as SSR
fallbacks (used during server-side rendering before hydration).