diff --git a/AGENTS.md b/AGENTS.md index 9988a74f6..aa290545d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -120,9 +120,10 @@ - **AntD Modal 规则:当前版本使用 `.ant-modal-container` 作为实际内容外壳,默认内容 padding 在该元素上;不得凭旧版本经验只写 `.ant-modal-content`。** 优先使用 `styles={{ container: ... , body: ... }}` 和组件级 class;新增覆盖前必须检查实际渲染结构。 - AntD 第三方覆盖必须限定到具体页面/组件 class,不得用全局 `.ant-modal-*` 改变所有页面;覆盖应集中且唯一,禁止多个末尾 override 互相打架。 - UI 图标优先使用 `lucide-react` 或项目已有 Ant Design 图标;页面文案使用中文。页面身份图标统一使用 `WorkspaceSignalIcon`,导航和操作图标统一使用 `lucide-react`。 -- 页面级分类导航至少 44px 高,并提供“图标 + 明确文字”入口和一致选中态;重要设置不能只藏在无文字图标中。 +- 页面级分类导航至少 44px 高,并提供”图标 + 明确文字”入口和一致选中态;重要设置不能只藏在无文字图标中。 - 可编辑的工作区、画布和对象名称常显铅笔图标并支持单击编辑;双击和右键只能作为快捷方式,不能作为唯一发现路径。 -- 不把页面大段说明文字当作“如何使用”的常驻教程;通过明确控件、空态、反馈和可发现的图标+文字表达功能。 +- 不把页面大段说明文字当作”如何使用”的常驻教程;通过明确控件、空态、反馈和可发现的图标+文字表达功能。 +- **卡片、列表、交互动效遵循 [UI 设计系统规范](docs/ui-design-system.md)**:统一卡片表面色、边框、投影、hover状态(240ms/translateY -4px)、双主题均衡策略。改造卡片前必须先读该规范,确保新增样式符合设计token体系。 ### 6.2 空间、响应式和动效 diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css index 4506b940b..37c3858a6 100644 --- a/web/src/styles/globals.css +++ b/web/src/styles/globals.css @@ -125,6 +125,41 @@ --project-library-icon-surface: #ffffff; --project-library-shadow: 0 8px 20px rgba(0, 0, 0, 0.06); + /* === 新卡片系统 Token(对应 docs/ui-design-system.md)=== */ + /* 卡片表面 - 纯白卡片浮在浅灰页面上 */ + --card-surface: #ffffff; + --card-surface-hover: #ffffff; + --card-surface-raised: #f8f8f8; + + /* 卡片边框 - 极淡,靠投影建立层次 */ + --card-border: rgba(17, 17, 17, 0.06); + --card-border-hover: rgba(17, 17, 17, 0.08); + + /* 卡片投影 - 微妙轻盈,像Apple/Figma */ + --card-elevation: + 0 1px 2px rgba(0, 0, 0, 0.04), + 0 2px 4px rgba(0, 0, 0, 0.02); + --card-elevation-hover: + 0 4px 12px rgba(0, 0, 0, 0.06), + 0 8px 24px rgba(0, 0, 0, 0.04), + 0 12px 36px rgba(0, 0, 0, 0.02); + + /* 画布卡片封面区 - 浅灰衬托内容 */ + --canvas-cover-surface: #f5f5f5; + --canvas-icon-surface: #ffffff; + --canvas-icon-shadow: 0 2px 8px rgba(0, 0, 0, 0.12); + + /* 媒体区背景 */ + --media-surface: #f5f5f5; + + /* 骨架屏 */ + --skeleton-surface: linear-gradient( + 90deg, + rgba(17, 17, 17, 0.04) 0%, + rgba(17, 17, 17, 0.06) 50%, + rgba(17, 17, 17, 0.04) 100% + ); + /* 实心(反相)按钮:不要写 background:var(--foreground) + color:var(--background), 两者在不同层级里解析结果不稳定,会出现同色不可读的按钮。用显式配对 token。 */ --btn-solid-bg: #171717; @@ -542,6 +577,36 @@ --project-library-icon-surface: #0d0d0d; --project-library-shadow: 0 8px 24px rgba(0, 0, 0, 0.28); + /* === 新卡片系统 Token - Dark(对应 docs/ui-design-system.md)=== */ + --card-surface: #1f1f1f; + --card-surface-hover: #242424; + --card-surface-raised: #2a2a2a; + + --card-border: rgba(255, 255, 255, 0.08); + --card-border-hover: rgba(255, 255, 255, 0.14); + + --card-elevation: + 0 2px 6px rgba(0, 0, 0, 0.32), + 0 4px 12px rgba(0, 0, 0, 0.24), + 0 6px 20px rgba(0, 0, 0, 0.16); + --card-elevation-hover: + 0 8px 20px rgba(0, 0, 0, 0.40), + 0 12px 32px rgba(0, 0, 0, 0.32), + 0 16px 48px rgba(0, 0, 0, 0.24); + + --canvas-cover-surface: #171717; + --canvas-icon-surface: #0d0d0d; + --canvas-icon-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + + --media-surface: #171717; + + --skeleton-surface: linear-gradient( + 90deg, + rgba(255, 255, 255, 0.05) 0%, + rgba(255, 255, 255, 0.08) 50%, + rgba(255, 255, 255, 0.05) 100% + ); + --btn-solid-bg: #f5f5f5; --btn-solid-fg: #131313; } @@ -3271,24 +3336,32 @@ .canvas-library-count { display: flex; align-items: baseline; gap: 6px; justify-self: end; color: color-mix(in srgb, var(--foreground) 38%, transparent); font-size: var(--fs-micro); white-space: nowrap; } .canvas-library-count strong { color: var(--foreground); font-size: var(--fs-heading-lg); font-variant-numeric: tabular-nums; font-weight: 500; letter-spacing: .02em; } - .canvas-library-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); align-items: start; gap: 28px 18px; } + /* 画布库网格 - 优化间距(对应 Bento Grid 原则)*/ + .canvas-library-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); align-items: start; gap: 28px 22px; } .canvas-library-page .app-pagination-bar { position: static; margin-top: var(--space-4); border-color: var(--workspace-border); background: transparent; padding: var(--space-1-half) var(--space-2); backdrop-filter: none; } - .app-canvas-project-card { min-width: 0; cursor: pointer; color: var(--foreground); transition: transform 420ms var(--motion-ease-out); } - .app-canvas-create-card { display: flex; min-width: 0; cursor: pointer; flex-direction: column; align-items: stretch; border: 0; background: transparent; padding: 0; color: var(--foreground); text-align: left; transition: transform 420ms var(--motion-ease-out); } - .app-canvas-create-card:hover:not(:disabled), .app-canvas-create-card:focus-visible { transform: translateY(-7px); } + /* === 画布卡片重构(对应 docs/ui-design-system.md)=== */ + .app-canvas-project-card { min-width: 0; cursor: pointer; color: var(--foreground); transition: transform 240ms var(--motion-ease-out), box-shadow 280ms var(--motion-ease-out), background-color 200ms ease-out, border-color 200ms ease-out; } + + /* 创建卡片 - 更吸引人的设计 */ + .app-canvas-create-card { display: flex; min-width: 0; cursor: pointer; flex-direction: column; align-items: stretch; border: 0; background: transparent; padding: 0; color: var(--foreground); text-align: left; transition: transform 240ms var(--motion-ease-out); } + .app-canvas-create-card:hover:not(:disabled), .app-canvas-create-card:focus-visible { transform: translateY(-6px); } + .app-canvas-create-card:active:not(:disabled) { transform: translateY(-3px) scale(0.995); transition-duration: 120ms; } .app-canvas-create-card:focus-visible { outline: 0; } - .app-canvas-create-preview { display: grid; aspect-ratio: 16 / 9; place-items: center; overflow: hidden; border-radius: var(--r-2xl); background: var(--surface-card); box-shadow: var(--elevation-card), var(--elevation-hairline); transition: background-color 320ms ease-out, box-shadow 420ms var(--motion-ease-out); } - .app-canvas-create-card:hover:not(:disabled) .app-canvas-create-preview, .app-canvas-create-card:focus-visible .app-canvas-create-preview { background: color-mix(in srgb, var(--workspace-accent) 12%, var(--workspace-surface-strong)); box-shadow: 0 18px 36px color-mix(in srgb, var(--foreground) 12%, transparent); } - .app-canvas-create-icon { width: 38px; height: 38px; color: color-mix(in srgb, var(--foreground) 36%, transparent); stroke-width: 1.2; transition: color 260ms ease-out, transform 420ms var(--motion-ease-out); } + .app-canvas-create-preview { display: grid; aspect-ratio: 16 / 9; place-items: center; overflow: hidden; border-radius: var(--r-xl); background: var(--card-surface); box-shadow: var(--card-elevation); border: 2px dashed rgba(17, 17, 17, 0.12); transition: background-color 240ms ease-out, box-shadow 280ms var(--motion-ease-out), border-color 200ms ease-out, border-style 200ms ease-out; } + .app-canvas-create-card:hover:not(:disabled) .app-canvas-create-preview, .app-canvas-create-card:focus-visible .app-canvas-create-preview { background: var(--card-surface); border-color: var(--workspace-accent); border-style: solid; box-shadow: var(--card-elevation-hover), 0 0 0 3px color-mix(in srgb, var(--workspace-accent) 12%, transparent); } + .app-canvas-create-icon { width: 38px; height: 38px; color: color-mix(in srgb, var(--foreground) 32%, transparent); stroke-width: 1.2; transition: color 240ms ease-out, transform 280ms var(--motion-ease-out); } .app-canvas-create-card:hover:not(:disabled) .app-canvas-create-icon { color: var(--workspace-accent); transform: scale(1.12) rotate(90deg); } .app-canvas-create-title { margin-top: 14px; font-size: var(--fs-heading-lg); font-weight: 620; line-height: 1.25; } .app-canvas-create-meta { margin-top: 6px; color: color-mix(in srgb, var(--foreground) 38%, transparent); font-size: var(--fs-caption); } .app-canvas-create-card:disabled { cursor: not-allowed; opacity: .5; } - .app-canvas-project-card.is-library { overflow: hidden; border-radius: var(--r-2xl); background: var(--surface-card); box-shadow: var(--elevation-card), var(--elevation-hairline); content-visibility: auto; contain-intrinsic-size: 0 320px; } - .app-canvas-project-card.is-library .app-canvas-project-preview { overflow: hidden; border-radius: var(--r-2xl) var(--r-2xl) 0 0; background: var(--surface-card); } - .app-canvas-project-card.is-library:hover, .app-canvas-project-card.is-library:focus-within { background: var(--surface-card-hover); box-shadow: var(--elevation-card-hover), var(--elevation-hairline); transform: translateY(-7px); } - .app-canvas-project-card.is-library.is-selected { box-shadow: 0 0 0 3px color-mix(in srgb, var(--workspace-accent) 22%, transparent); border-radius: var(--r-2xl); } + + /* 画布卡片 - 库视图 - 更明显的hover效果 */ + .app-canvas-project-card.is-library { overflow: hidden; border-radius: var(--r-xl); background: var(--card-surface); box-shadow: var(--card-elevation); border: 1px solid var(--card-border); content-visibility: auto; contain-intrinsic-size: 0 320px; } + .app-canvas-project-card.is-library .app-canvas-project-preview { overflow: hidden; border-radius: var(--r-xl) var(--r-xl) 0 0; background: var(--canvas-cover-surface); } + .app-canvas-project-card.is-library:hover, .app-canvas-project-card.is-library:focus-within { background: var(--card-surface); box-shadow: var(--card-elevation-hover); border-color: var(--card-border-hover); transform: translateY(-6px); } + .app-canvas-project-card.is-library:active { transform: translateY(-3px) scale(0.995); transition-duration: 120ms; } + .app-canvas-project-card.is-library.is-selected { box-shadow: var(--card-elevation), 0 0 0 2px color-mix(in srgb, var(--workspace-accent) 32%, transparent); border-color: var(--workspace-accent); border-radius: var(--r-xl); } .app-canvas-project-card.is-recent .app-canvas-project-preview { overflow: hidden; border-radius: var(--r-2xl) var(--r-2xl) 0 0; background: var(--workspace-surface-strong); transition: box-shadow 420ms var(--motion-ease-out), transform 420ms var(--motion-ease-out); } .app-canvas-project-card.is-recent:hover .app-canvas-project-preview, .app-canvas-project-card.is-recent:focus-within .app-canvas-project-preview { box-shadow: 0 18px 36px color-mix(in srgb, var(--foreground) 13%, transparent); transform: translateY(-4px); } @@ -3311,9 +3384,13 @@ .canvas-project-select.is-visible, .app-canvas-project-card:hover .canvas-project-select, .app-canvas-project-card:focus-within .canvas-project-select { opacity: 1; } .canvas-project-checkbox { width: 14px; height: 14px; margin: 0; accent-color: var(--workspace-accent); } - .app-canvas-project-body { min-height: 90px; border-radius: 0 0 var(--r-2xl) var(--r-2xl); background: var(--surface-card); padding: 14px 10px 8px; transition: background-color 320ms ease-out; } + .app-canvas-project-body { min-height: 90px; border-radius: 0 0 var(--r-xl) var(--r-xl); background: transparent; padding: 14px 10px 8px; transition: background-color 200ms ease-out; } .app-canvas-project-body.is-compact { min-height: 0; padding: 11px 1px 1px; } - .app-canvas-project-card:hover .app-canvas-project-body { background: var(--surface-card-hover); } + .app-canvas-project-card:hover .app-canvas-project-body { background: transparent; } + + /* Focus状态 - 键盘导航可见 */ + .app-canvas-project-card:focus:not(:focus-visible) { outline: none; box-shadow: var(--card-elevation); } + .app-canvas-project-card:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; box-shadow: var(--card-elevation), 0 0 0 4px color-mix(in srgb, var(--ring) 16%, transparent); } .canvas-project-card-footer { margin-top: 12px; } .canvas-project-heading-row { display: flex; min-width: 0; align-items: center; justify-content: space-between; gap: 10px; } .canvas-project-title-button { min-width: 0; flex: 1; cursor: pointer; border: 0; background: transparent; padding: 0; text-align: left; } @@ -3339,6 +3416,22 @@ .library-page .app-page-header { border-bottom: 0; padding-bottom: 4px; } .library-page .app-page-header h1 { font-size: var(--fs-heading-lg); font-weight: 620; } .library-page .app-page-header p { max-width: 560px; } + + /* 页面头部按钮优化 - 去除重边框 */ + .library-page .app-page-header .ant-btn, + .canvas-library-page .app-page-header .ant-btn { + border: 1px solid rgba(17, 17, 17, 0.08) !important; + background: #ffffff !important; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important; + transition: all 180ms ease-out !important; + } + .library-page .app-page-header .ant-btn:hover, + .canvas-library-page .app-page-header .ant-btn:hover { + border-color: rgba(17, 17, 17, 0.12) !important; + background: #ffffff !important; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08) !important; + transform: translateY(-1px); + } .library-primary-action { border: 0 !important; border-radius: var(--r-md) !important; background: var(--btn-solid-bg) !important; color: var(--btn-solid-fg) !important; box-shadow: none !important; font-weight: 620; } .library-toolbar { min-height: 50px; margin-top: 8px; border-bottom: 0; padding: 7px 0 10px; } .library-toolbar .ant-input-affix-wrapper, @@ -3622,10 +3715,11 @@ .wallet-library-page .wallet-ledger-panel .app-table-surface { box-shadow: none; } .library-loading-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 26px 18px; margin-top: 20px; } - .library-skeleton { aspect-ratio: 16 / 10; border-radius: var(--r-2xl); background: color-mix(in srgb, var(--foreground) 6%, transparent); animation: library-pulse 1.6s ease-in-out infinite; } + /* 画布骨架屏 - 使用新token */ + .library-skeleton { aspect-ratio: 16 / 10; border-radius: var(--r-xl); background: var(--skeleton-surface); animation: library-pulse 1.8s cubic-bezier(0.4, 0, 0.6, 1) infinite; } .task-library-page .library-loading-grid { grid-template-columns: 1fr; gap: 2px; } .task-library-page .library-loading-grid .library-skeleton { height: 92px; aspect-ratio: auto; border-radius: var(--r-lg); } - @keyframes library-pulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } } + @keyframes library-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.8; } } @media (prefers-reduced-motion: reduce) { .library-skeleton { animation: none; } } @media (max-width: 760px) {