feat(web): 用户工作台 - 产品化壳层、内容库布局与积分入口

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ddCat
2026-09-16 22:59:45 +08:00
parent f52702b70f
commit 969e2831b2
46 changed files with 5355 additions and 944 deletions

View File

@@ -1,18 +1,16 @@
import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { getWorkspaceAntThemeConfig } from "../src/lib/app-theme";
describe("asset library header buttons", () => {
test("only restyles header buttons in light mode and uses outline tokens", () => {
test("user pages share control geometry without a light-only outline override", () => {
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
const headerButtonRule = css.match(/html:not\(\.dark\) \.library-page \.app-page-header \.ant-btn,[\s\S]*?transition: all 180ms ease-out !important;\s*}/)?.[0] || "";
const headerButtonHoverRule = css.match(/html:not\(\.dark\) \.library-page \.app-page-header \.ant-btn:hover,[\s\S]*?transform: translateY\(-1px\);\s*}/)?.[0] || "";
expect(headerButtonRule).toContain("html:not(.dark) .canvas-library-page .app-page-header .ant-btn");
expect(headerButtonRule).toContain("background: transparent !important;");
expect(headerButtonRule).toContain("color: var(--foreground) !important;");
expect(headerButtonHoverRule).toContain("background: var(--btn-outline-hover-bg) !important;");
expect(headerButtonHoverRule).toContain("color: var(--foreground) !important;");
expect(css).not.toContain("\n .library-page .app-page-header .ant-btn,\n");
const theme = getWorkspaceAntThemeConfig();
expect(theme.token?.controlHeight).toBe(38);
expect(theme.components?.Button?.borderRadius).toBe(theme.token?.borderRadius);
expect(theme.components?.Button?.defaultBorderColor).toBe("transparent");
expect(css).not.toContain("html:not(.dark) .library-page .app-page-header .ant-btn");
expect(css).not.toContain("html .assets-library-page .app-page-header .assets-header-action-buttons .ant-btn");
});
});

View File

@@ -0,0 +1,29 @@
import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
describe("asset library category sidebar", () => {
test("keeps type, business and folder filters in a left-hand nav", () => {
const page = readFileSync(resolve(import.meta.dir, "../src/pages/assets/index.tsx"), "utf8");
const css = readFileSync(resolve(import.meta.dir, "../src/styles/workspace-product.css"), "utf8");
expect(page).toContain('className="assets-collection-layout"');
expect(page).toContain('aria-label="素材分类"');
expect(page).toContain('title="素材类型"');
expect(page).toContain('title="业务分类"');
expect(page).toContain("我的分类");
expect(page).not.toContain("全部自定义分类");
expect(css).toMatch(/\.assets-collection-layout\s*\{[^}]*grid-template-columns:\s*220px minmax\(0, 1fr\)/s);
});
});
describe("wallet history pagination", () => {
test("pins ledger pagination to the history panel footer", () => {
const modal = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-wallet-modal.tsx"), "utf8");
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
expect(modal).toContain("workspace-wallet-history-scroll");
expect(modal).toContain("workspace-wallet-pagination");
expect(modal).not.toContain("wallet.total > 20");
expect(css).toMatch(/\.workspace-wallet-content\.is-history\s*\{[^}]*overflow:\s*hidden/s);
expect(css).toMatch(/\.workspace-wallet-pagination\s*\{[^}]*margin-top:\s*auto/s);
});
});

View File

@@ -0,0 +1,23 @@
import { expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
test("settings page drops the page header copy and audio preference blocks", () => {
const source = readFileSync(resolve(import.meta.dir, "../src/pages/settings/index.tsx"), "utf8");
expect(source).not.toContain("创作偏好");
expect(source).not.toContain("配置默认模型、生成参数和素材存储。");
expect(source).not.toContain("音频默认值");
expect(source).not.toContain("音频指令");
expect(source).not.toContain("默认音频指令");
expect(source).toContain("默认生图张数");
expect(source).toContain("settings-preference-heading");
});
test("wallet tabs and preference blocks keep a visible gap from neighboring surfaces", () => {
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
expect(css).toContain(".workspace-wallet-tabs {");
expect(css).toContain("margin: 12px 24px 0;");
expect(css).toContain("margin: 16px 24px 24px;");
expect(css).toContain(".settings-preference-heading { margin-bottom: var(--space-5); }");
expect(css).toContain(".app-user-workspace.settings-page .settings-preference-block {\n padding: 20px 20px 12px;");
});

View File

@@ -39,7 +39,7 @@ describe("workspace route loading", () => {
expect(router).toContain('{ path: "/create", element: <RequireAuth>{deferred(<CreatePage />)}</RequireAuth> }');
expect(router).not.toContain('path: "/home"');
expect(router).not.toContain("HomePage");
expect(navigation).toContain('{ id: "home", title: "首页", icon: Home, to: "/" }');
expect(navigation).toContain('{ ...toolItem("create", "/"), id: "home", title: "创作" }');
expect(navigation).not.toContain('to: "/create"');
expect(navigation).not.toContain('to: "/home"');
});
@@ -69,6 +69,9 @@ describe("workspace route loading", () => {
expect(layout).not.toContain("useCanvasUiStore");
expect(layout).not.toContain("CanvasDeleteProjectsDialog");
expect(canvas).toContain("deleteDialogOpen ? <Suspense");
expect(detail).toContain("project-workspace-header");
expect(detail).not.toContain("useWorkspaceTopBarExtension");
expect(detail).toContain("新建画布");
});