Compare commits

..

1 Commits

Author SHA1 Message Date
codex-bot 514e790a78 Bound review image retention and separate CI navigation budgets
creative workspace review checks / verify (pull_request) Successful in 51m4s
2026-10-31 03:21:23 +08:00
125 changed files with 116 additions and 1915 deletions
-27
View File
@@ -1,27 +0,0 @@
name: Endoleap brand checks
on:
pull_request:
branches: [main]
paths:
- 'packages/brand/**'
- 'pnpm-workspace.yaml'
- 'package.json'
- 'AGENTS.md'
- '.gitea/workflows/brand.yml'
push:
branches: [main]
paths:
- 'packages/brand/**'
- 'pnpm-workspace.yaml'
- '.gitea/workflows/brand.yml'
concurrency:
group: brand-${{ gitea.event.pull_request.number || gitea.ref }}
cancel-in-progress: true
jobs:
verify:
runs-on: ces-control
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Verify brand assets, Tailwind compilation and typed exports in Docker
run: docker build -f packages/brand/Dockerfile -t "endoleap-brand-check:${{ gitea.sha }}" .
+9 -1
View File
@@ -11,6 +11,8 @@ on:
- 'scripts/integration.sh'
- 'scripts/cleanup-integration.sh'
- 'scripts/test-integration-cleanup.py'
- 'scripts/cleanup-review-images.sh'
- 'scripts/test-review-image-cleanup.py'
concurrency:
group: creative-workspace-${{ gitea.event.pull_request.number }}
cancel-in-progress: true
@@ -25,8 +27,9 @@ jobs:
- name: Check patch formatting
run: |
git diff --check HEAD^ HEAD
bash -n scripts/integration.sh scripts/cleanup-integration.sh
bash -n scripts/integration.sh scripts/cleanup-integration.sh scripts/cleanup-review-images.sh
python3 scripts/test-integration-cleanup.py
python3 scripts/test-review-image-cleanup.py
- name: Verify Studio types, tests, build and smoke
run: docker build -f apps/studio/Dockerfile -t "creative-studio-review:${{ gitea.sha }}" .
- name: Build Wiki integration and runtime images
@@ -45,3 +48,8 @@ jobs:
env:
GITEA_RUN_ID: ${{ gitea.run_id }}
run: bash scripts/cleanup-integration.sh
- name: Remove this run disposable review image tags
if: always()
env:
REVIEW_SHA: ${{ gitea.sha }}
run: bash scripts/cleanup-review-images.sh
-4
View File
@@ -18,7 +18,3 @@ __pycache__/
*.webp
*.gif
*.avif
# Approved, versioned brand resources are package source assets.
!packages/brand/assets/**/*.png
!packages/brand/docs/logo-preview.png
-7
View File
@@ -14,10 +14,3 @@ This block is written and re-added by `next dev` — verify at `node_modules/nex
- 页面改动必须先 push,等待 ces-control 的 CI/CD 成功部署,再直接访问服务器检查效果。
- 不启动本地网页预览,不使用 localhost / 127.0.0.1 页面进行视觉验收,也不把本地预览链接交付给用户。
- 类型检查、单元测试等不提供网页预览的检查可以本地执行;完整运行检查由 Docker CI 完成。
## 啡跃 Endoleap 品牌与主题
- 共享品牌包位于 [`packages/brand`](packages/brand/README.md)。修改品牌色、主题或标志前,阅读包内的 [品牌边界](packages/brand/docs/overview.md)、[配色与交互规范](packages/brand/docs/colors.md)、[Tailwind / shadcn 接入](packages/brand/docs/integration.md) 和 [Logo 规则](packages/brand/docs/logo.md)。不在仓库根 docs 重复维护一套品牌规范。
- 四套正式主题为 home-light、home-dark、canvas-light、canvas-dark;不创建 drafts,不恢复 proposed 命名。画布 Light / Dark 背景保持中性近白 / 近黑,用户素材与作品不整体染色。
- 基础色只在 tokens/palette.json 定义,主题引用色板键;Logo 轮廓只在 tokens/geometry.json 定义。保持 CSS、类型声明、资产与清单一致,不通过图片模型重画已固定的图形。
- 本地仅运行不生成产物的轻量读取检查。品牌导出、Tailwind/TypeScript 编译和 SVG 栅格化检查必须通过已确认的 ces-control Docker CI 执行,不在本机启动预览或构建。
@@ -90,6 +90,9 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser)
);
const page = await context.newPage();
page.setDefaultTimeout(10000);
// Navigation includes document and script loading on the shared runner;
// keep action/readiness checks at 10s and the suite's overall bound unchanged.
page.setDefaultNavigationTimeout(30000);
page.on("pageerror", (error) => errors.push(error.message));
page.on("crash", () => errors.push("Browser renderer crashed"));
const pending = new Set<string>(), network: string[] = [];
@@ -97,12 +100,14 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser)
page.on("requestfinished", request => pending.delete(request.url()));
page.on("requestfailed", request => {pending.delete(request.url());network.push(new URL(request.url()).pathname+": "+request.failure()?.errorText);});
async function navigate(url: string, reload = false) {
const previousSessionReplies = sessionReplies;
const previousSessionReplies = sessionReplies, started = Date.now();
try {
const navigation = await (reload ? page.reload({waitUntil:"domcontentloaded"}) : page.goto(url,{waitUntil:"domcontentloaded"}));
assert.ok(navigation?.ok(), "Navigation returns a successful document");
const documentMs = Date.now() - started;
await page.getByText(signedIn ? "editor@example.com" : "登录你的账户",{exact:true}).first().waitFor({state:"attached"});
assert.ok(sessionReplies > previousSessionReplies, "The new document requests its account fixture and renders the resulting account state");
console.log("Workspace UI navigation timing", JSON.stringify({path:new URL(url).pathname,documentMs,accountReadyMs:Date.now()-started}));
} catch (error) {
const probeStarted=Date.now();
const server=await fetch(url,{signal:AbortSignal.timeout(3000)}).then(async response=>{await response.body?.cancel();return {status:response.status,elapsedMs:Date.now()-probeStarted}}).catch(error=>({error:error instanceof Error?error.name:"unknown",elapsedMs:Date.now()-probeStarted}));
+1 -3
View File
@@ -7,8 +7,6 @@
"dev:studio": "pnpm --filter @prompt/studio dev",
"build": "pnpm -r build",
"typecheck": "pnpm -r typecheck",
"test": "pnpm --filter @prompt/waterfall-wiki test",
"test:brand": "pnpm --filter @endoleap/brand test",
"build:brand": "pnpm --filter @endoleap/brand build"
"test": "pnpm --filter @prompt/waterfall-wiki test"
}
}
-12
View File
@@ -1,12 +0,0 @@
FROM node:24-bookworm-slim
WORKDIR /repo
RUN corepack enable && corepack prepare pnpm@11.25.0 --activate
COPY packages/brand/package.json packages/brand/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --ignore-scripts
COPY packages/brand/ ./
RUN pnpm test && pnpm build && pnpm test:tailwind && pnpm test:types
RUN apt-get update && apt-get install -y --no-install-recommends python3 python3-venv \
&& rm -rf /var/lib/apt/lists/* \
&& python3 -m venv /opt/brand-python \
&& /opt/brand-python/bin/pip install --only-binary=:all: Pillow==13.0.0 resvg-py==0.5.0
RUN /opt/brand-python/bin/python tests/assets.py
-41
View File
@@ -1,41 +0,0 @@
# 啡跃 Endoleap 品牌包
本包把已选定的「摩卡奶霜」配色、四套正式主题和固定轮廓 Logo 放在同一个 workspace 包中。它提供 Tailwind CSS v4 / shadcn/ui 的主题接口及静态图片,不安装组件,也不自动重设应用页面。
## 文档入口
- [品牌与包边界](docs/overview.md)
- [配色、组件状态与深色主题](docs/colors.md)
- [Tailwind CSS、shadcn/ui 与包导入](docs/integration.md)
- [Logo、平台图片与修改流程](docs/logo.md)
`tokens/palette.json` 是色值来源;四份主题 JSON 引用色板键;`tokens/geometry.json` 是唯一 Logo 路径来源。`src/themes.css` 是可直接导入的源样式,一致性由测试核对;`dist/` 仅在远程 CI 构建,不提交。
```css
@import "tailwindcss";
@import "@endoleap/brand/themes.css";
@import "@endoleap/brand/tailwind.css";
```
```tsx
// 在主题根节点选择正式主题;应用负责持久化和切换。
<main data-theme="canvas-dark" className="bg-background text-foreground">
<button className="bg-primary text-primary-foreground hover:bg-primary-hover">
开始创作
</button>
</main>
```
主题名:`home-light`、`home-dark`、`canvas-light`、`canvas-dark`。没有 `drafts`、`proposed` 或隐式跟随系统的规则。`.dark` 兼容默认首页深色;显式 `data-theme` 优先。使用 `dark:` 工具类时,一个文档根节点只选择一个明暗主题,不在 `.dark` 祖先下嵌套浅色 `dark:` 变体。
## 验证
可进行的本地轻量检查:`node --test packages/brand/tests/brand.test.mjs`。它只读取源码和资产,检查主题、对比度、SVG 路径及 PNG/ICO 文件头,不编译和输出产物。
完整验证在已确认的 ces-control Docker runner 执行:
```sh
docker build -f packages/brand/Dockerfile -t endoleap-brand-check .
```
包含真实 Tailwind 编译、TypeScript 导入检查、品牌导出和 72 个 PNG 与 SVG 逐像素比较。不要在本机运行该 Docker 构建或 `build` / `test:tailwind` / `test:types` / `test:assets`。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

-71
View File
@@ -1,71 +0,0 @@
{
"version": "1.2",
"brand": "啡跃 Endoleap",
"colors": {
"mocha": "#A47764",
"brown": "#49372E",
"cream": "#FFF6EF"
},
"geometry": "tokens/geometry.json",
"svg_files": [
"assets/svg/logo-light.svg",
"assets/svg/logo-dark.svg",
"assets/svg/mono-dark.svg",
"assets/svg/mono-light.svg",
"assets/svg/icon-dark.svg",
"assets/svg/icon-light.svg",
"assets/svg/app-square.svg",
"assets/svg/avatar-circle.svg"
],
"png_sizes": [
16,
24,
32,
48,
64,
128,
180,
192,
256,
512,
1024,
2048
],
"ico_sizes": [
16,
24,
32,
48,
64,
128,
256
],
"variants": {
"logo-light": {
"rim": "#A47764",
"bowl": "#49372E"
},
"logo-dark": {
"rim": "#A47764",
"bowl": "#FFF6EF"
},
"mono-dark": {
"rim": "#49372E",
"bowl": "#49372E"
},
"mono-light": {
"rim": "#FFF6EF",
"bowl": "#FFF6EF"
},
"icon-dark": {
"rim": "#A47764",
"bowl": "#FFF6EF",
"background": "#49372E"
},
"icon-light": {
"rim": "#A47764",
"bowl": "#49372E",
"background": "#FFF6EF"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

-71
View File
@@ -1,71 +0,0 @@
# 色彩与组件规范
## 基础色与背景分工
| 色彩 | HEX | 用途 |
| --- | --- | --- |
| 摩卡 | `#A47764` | `brand-mocha`,Logo 杯口与装饰 |
| 深棕 | `#49372E` | 浅底 Logo 杯腹、标准图标底 |
| 深摩卡 | `#78523F` | Light 主操作与连线 |
| 奶霜 | `#FFF6EF` | 首页 Light 底色、反白 Logo |
| 陶橙 | `#E07242` | `brand-orange`,小面积装饰,不替代状态色 |
| 浅燕麦 | `#EDE9D0` | `brand-oat`,首页轻量选中区域 |
品牌摩卡不适合在所有浅色底上当普通小字。Light 按钮使用更深的摩卡;正文和辅助文字分别使用 `foreground`、`muted-foreground`。`accent` 在 shadcn/ui 中表示交互高亮背景,因此映射到轻量 `selection`,与装饰色 `brand-mocha` 分开。
| 正式主题 | 工作背景 | 面板 | 主按钮 | 按钮文字 |
| --- | --- | --- | --- | --- |
| `home-light` | `#FFF6EF` | `#FFFCF9` | `#78523F` | `#FFFFFF` |
| `home-dark` | `#1C1816` | `#27211E` | `#D1AA92` | `#211A17` |
| `canvas-light` | `#FAFAFA` | `#FFFFFF` | `#78523F` | `#FFFFFF` |
| `canvas-dark` | `#141414` | `#202020` | `#D1AA92` | `#211A17` |
四套主题使用相同 token 契约,完整值在对应 JSON;通过 JS `getTheme(name)` 可获得解析后的只读值。JSON 引用色板键,避免在不同主题重复维护 HEX。
## 首页
导航与 Hero 使用 `background`;标题 `foreground-strong`,正文 `foreground`,说明 `muted-foreground`。演示面板和功能卡片使用 `card` / `card-foreground`。嵌套分组使用 `muted` / `muted-foreground`,不继承浅底上可能对比不足的说明色。
推荐套餐使用 `selection` 背景加文字标记;深色 CTA 区块须成对使用反白文字。陶橙仅作少量点缀,浅燕麦只用于局部区块,不给所有卡片统一染色。
## 画布
- 无限背景使用 `background`,点阵 `grid`,工具栏和侧栏 `surface`;弹层 `popover` / `popover-foreground`。
- Light / Dark 均保持中性近白 / 近黑。品牌色集中在操作、连接、焦点和选中态。
- 普通节点用 `border`;选中节点用 2px `selection-border` 和控制点。不要把节点正文、图片或用户绘图填成选中色。
- 工具选中采用 `selection` 底与 `primary` 图标;连线采用 `connector`;加号端口使用 `primary` 底和 `primary-foreground` 图标。
- 图片、视频、用户作品和导入 SVG 保留原色。深色工作区内的白色作品画板仍为白色,导出不包含界面网格或品牌背景。
## 交互状态
| 组件 | Default | Hover | Pressed / Selected |
| --- | --- | --- | --- |
| 主按钮 | `primary` | `primary-hover` | `primary-active` |
| 次按钮 | `secondary` | `secondary-hover` | `secondary-active` |
| 菜单、列表项 | `surface` | `row-hover` / `accent` | `selection` |
| 文本链接 | `link` 并加下划线 | 保持可辨认 | 不仅靠颜色表达 |
| 输入框 | `surface`、`foreground`、`input` 边界 | 强化边界 | `ring` 外轮廓 |
主、次按钮始终使用对应 `*-foreground`,不要在 hover 时遗留原文字颜色。`focus-visible` 使用 2px `ring` 与 2px 外偏移。输入错误保留 `danger` 边界、说明和错误图标;键盘焦点作为独立外轮廓继续显示。
禁用使用 `disabled-background` / `disabled-foreground`,同时提供真正的 disabled 语义并停止 hover。禁用色不用于正常说明。加载保持原按钮主题并增加文字或进度标记,不用错误色表示。
## shadcn/ui 语义对照
`card` → 默认内容面板;`popover` → 浮层;`muted` → 低强调表面;`accent` → hover/选中表面;`destructive` → 危险动作;`input` → 必须可见的控件边界;`ring` → 焦点;`sidebar-*` → 侧栏完整配对;`chart-1` 至 `chart-5` → 每个主题自己的图表色。
每种表面都有对应前景色,包含 `destructive-foreground`。`radius` 为 `0.625rem`,Tailwind 的 `rounded-sm/md/lg/xl` 按统一比例派生。
## 状态色与图表
成功、警告、错误、信息分别使用 `success`、`warning`、`danger`、`info`,并与 `*-background` 配对。同时提供文字或图标,勿单靠颜色解释。陶橙是品牌装饰色,不自动意味着警告。
同一指标保持相同系列颜色;多系列同时增加图例、标记或线型。Light 和 Dark 的 `chart-*` 分别配置,不能把浅底图表色原样搬到深底。精细图表仍需检查真实线宽、相邻色与背景。
`border`、`grid` 是低强调分隔/装饰;必要控件边界采用更清晰的 `input`。阴影使用 `shadow` token;模态遮罩使用 `scrim`,对话框与文字不随背景一起降低透明度。
## 验收范围
静态检查覆盖语义前景/背景、主按钮三态与必要控件边界。普通文字目标 ≥4.5:1,必要非文字控件目标 ≥3:1;不是整站无障碍认证。照片叠字、透明混色、图表相邻色与真实交互另验。用户素材和模板内容不属于 UI 换色范围。
依据:[W3C 文字对比度](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum)、[非文字对比度](https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast)。
-59
View File
@@ -1,59 +0,0 @@
# Tailwind CSS / shadcn/ui 接入
## Workspace 依赖
在消费应用的 `package.json` 声明 `"@endoleap/brand": "workspace:*"`,按仓库独立锁文件策略更新该应用锁文件。包为私有内部资源,无需 npm 发布、React peer dependency 或运行时主题库。
当前 Studio / Wiki Dockerfile 把单个应用复制为孤立项目;增加 workspace 依赖时,必须一并调整 Docker 构建上下文和工作目录,复制根 workspace 配置、消费应用与 `packages/brand`,使 `workspace:*` 的相对位置保持有效。不要只加依赖后仍保留孤立安装流程。本 PR 不迁移这两套应用构建。
## Tailwind CSS v4
```css
@import "tailwindcss";
@import "@endoleap/brand/themes.css";
@import "@endoleap/brand/tailwind.css";
```
`themes.css` 提供原生变量;`tailwind.css` 以 `@theme inline` 映射为 `bg-background`、`text-foreground`、`border-input`、`ring-ring` 等工具类,并声明 `.dark` / 显式 dark 主题变体。仅使用普通 CSS 时只导入前者。
```tsx
<main data-theme="canvas-dark" className="bg-background text-foreground">
<section className="bg-card text-card-foreground border border-border">
<button className="bg-primary text-primary-foreground hover:bg-primary-hover focus-visible:ring-2 focus-visible:ring-ring">
开始创作
</button>
</section>
</main>
```
在页面根节点选择 `home-light` / `home-dark` / `canvas-light` / `canvas-dark`;不要将官网背景变量继承成编辑器画板内容。`.dark` 无显式主题时回退到 `home-dark`。使用 `dark:` 工具类时保持一个根明暗上下文,不在 `.dark` 祖先下混用嵌套浅色变体;嵌套不同表面优先使用相同语义工具类。
## shadcn/ui
消费应用在自己的 `components.json` 保留 `tailwind.cssVariables: true`,`tailwind.css` 指向导入上述品牌样式的全局 CSS 文件。应用自行选择已有风格、图标库和组件路径,不把配置文件放到品牌资源包,也不运行 `init` 覆盖已有全局样式。
本包已提供 background/card/popover、各 foreground、primary/secondary/muted/accent、destructive、border/input/ring、chart-1…5、完整 sidebar 变量与 radius。`accent` 是交互表面;装饰摩卡请用 `brand-mocha` / `bg-brand-mocha`。无需在每个组件复制色值。
这表示主题兼容,不表示 shadcn 组件或动画样式已安装。组件自己的依赖、动画及 className 合并工具由应用现有架构负责。
## JS / TypeScript
```ts
import { getTheme, type ThemeName } from '@endoleap/brand/tokens';
const name: ThemeName = 'canvas-dark';
const lineColor = getTheme(name).connector;
```
CSS 与 JS 主题名称一致。ESM 使用 JSON import attributes;包提供类型声明,TypeScript 消费方需支持 JSON 模块解析。CSS 中使用主题变量,Canvas/WebGL 中使用解析值;切换主题后由渲染器重画 UI,不能修改用户文档颜色。
## 静态图片
SVG 可通过包文件路径由构建器处理。favicon、Apple Touch 与 PWA 图片需要在应用资源准备阶段复制到应用的 public 根目录,再由页面元信息引用。例如 favicon 源是 `@endoleap/brand/assets/icons/favicon.ico`。必须显式指定文件映射,不复制整个资产包到 public,也不提交人为维护的第二套图形源。
应用有 basePath 时,按应用现有部署方式确认浏览器 URL;不要把内部包路径当作公开 URL。平台 manifest、主题切换和实际网页接入不由品牌包自动注入。
## 版本与兼容范围
适配本仓库 Tailwind v4.3 与 CSS 变量式 shadcn/ui。Tailwind v3 需要另写 config 映射,本包不宣称已测试 v3。
官方依据:[Tailwind theme variables](https://tailwindcss.com/docs/theme)、[shadcn/ui theming](https://ui.shadcn.com/docs/theming)。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Some files were not shown because too many files have changed in this diff Show More