feat(admin): 官网落地页融进 admin —— / 是官网、/admin 是运维后台

用户要 agent.sundynix.cn/ 打开是营销官网、/admin 是后台,且只用一个前端。
把 sundynix-site/web 的营销落地页融进 sundynix-admin 这一个 Vite 工程(不挂两份 embed):

- 拷官网到 src/site/:home(hero/功能/架构/快速上手/下载)+layout(header/footer)
  +terminal-demo/logo/reveal 等 + content/site.ts(文案本就是本产品)。去掉博客/posts/埋点/RSS
  (营销 only,零后端改动);use-release 改纯静态版本号。public/ 加 brand logo+favicon。
- Tailwind v4→v3 对齐:site 的 ink/ground/accent/term 等 token 加进 tailwind.config(var 引用)
  + :root/.dark 变量+keyframes 进 index.css;bg-ground/85 用 color-mix 还原。admin 自身用默认
  gray/violet 调色板,不冲突;landing 的 bg-ground 只作用在 SiteLayout 容器、不改 body。
- 路由重构:App.tsx 换 BrowserRouter —— / 官网(公开)、/admin/* 后台(AdminGate 内做 me/Login/AppShell)。
  routes.tsx path 改相对、AppShell 链接加 /admin 前缀。@ 别名指向 src/site。
- gateway/Dockerfile/nginx 零改动:单份 dist 挂根 + NoRoute SPA 兜底已支持 BrowserRouter 深链。

验证:tsc + vite build(Tailwind 编译过)+ vitest 41 过;gateway 二进制冒烟打真 serve——
/ 返回官网 index.html、/admin 与 /admin/tasks SPA 兜底 200、/brand/*.webp 200、/api/v1 走 API 401;
dist 里确认落地页文案已进 bundle。(注:MCP 浏览器当前断开,视觉渲染待部署后线上看。)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-18 17:36:43 +08:00
parent 373167b705
commit 6de1b3f6b2
36 changed files with 1143 additions and 32 deletions
@@ -0,0 +1,54 @@
import { Fragment } from 'react'
import { ARCH_LAYERS } from '@/content/site'
import { SectionLabel } from '@/components/section-label'
import { Reveal } from '@/components/reveal'
export function Architecture() {
return (
<section
id="architecture"
className="border-t border-hairline px-6 py-16 lg:px-10"
>
<div className="mx-auto max-w-6xl">
<Reveal>
<div className="mx-auto mb-9 max-w-[560px] text-center">
<SectionLabel>ARCHITECTURE</SectionLabel>
<h2 className="text-balance text-[26px] font-[650] tracking-[-0.02em]">
线
</h2>
<p className="mt-2.5 text-[15px] text-ink-2">
Monolith FirstMorph B
</p>
</div>
</Reveal>
<Reveal delay={120} className="mx-auto max-w-[760px]">
{ARCH_LAYERS.map((layer, i) => (
<Fragment key={layer.id}>
{/* NATS 总线插在 L2 和 L4 之间 */}
{i === 2 && (
<div className="mb-2.5 flex items-center justify-center gap-3.5 rounded-[10px] border border-dashed border-accent bg-accent-soft px-5 py-3 font-mono text-xs tracking-[0.1em] text-accent-ink">
NATS JETSTREAM · sundynix.*
</div>
)}
<div className="mb-2.5 grid grid-cols-1 items-center gap-1 rounded-[10px] border border-hairline bg-surface px-5 py-3.5 sm:grid-cols-[120px_1fr_auto] sm:gap-5">
<span className="font-mono text-[11px] tracking-[0.14em] text-ink-3">
{layer.id}
</span>
<span className="text-sm font-medium">
{layer.name}{' '}
<span className="text-[13px] font-normal text-ink-2">
{layer.detail}
</span>
</span>
<span className="font-mono text-[11.5px] text-accent-ink">
{layer.tech}
</span>
</div>
</Fragment>
))}
</Reveal>
</div>
</section>
)
}