feat(create): 首页消息渲染与历史抽屉细节批 - 会话头对称/操作组悬停/输入条紧凑/气泡微调/行距, 历史行模式图标/三点菜单图标+文字/导出 Markdown/新建卡作用域修复

This commit is contained in:
maomaochong-ai committed 2026-09-06 20:33:22 +08:00
1 parent fd5ebb6893
commit 10e37d29a8
9 files changed
+265 -83

No files matched your search

+4 -7
View File
@@ -35,7 +35,7 @@ BoardUI 是面向 AI/agent 界面的 React 组件库(62+ 源码组件、400+
| BoardUI 资产 | 内容 | 本项目落点 |
|---|---|---|
| agent-log 的 reveal/连接线形态(等第二消费点:画布 TaskLog 升级时抽共享组件,参考 WorkingDots 路径) | 形态参考 | Canvas 任务运行面板(TaskLog 升级,进行中) |
| notification-center | 通知中心(含 agent 完成/失败分组) | 全局通知浮层 / 后台 |
| ~~notification-center~~ 🚫**已禁用**(2026-09-06:产品未立项、无真实推送源与聚合需求证据;现有“系统公告中心(运营广播)+ 更新日志 + 任务状态就地呈现”均非用户级任务通知,不构成同类实现;如需再立,先补需求与消费点证据,当前一律禁用) | 通知中心(含 agent 完成/失败分组) | ~~全局通知浮层 / 后台~~ |
| styles/typography.css | text-* 排版复合类体系 | 对照 `ui-design-system.mdx` 融入 globals.css(rollout §6.2 缺口) |
| utils/cx.ts(tailwind-merge) | 类名合并 | 与项目 `lib/utils.ts` 对齐补 cn() |
| AGENTS.md / .cursor/rules | AI 协作纪律(组件规则、命名、无障碍) | 供项目 AGENTS.md 参考沉淀组件纪律 |
@@ -60,10 +60,7 @@ BoardUI 最典型消费场景是「数据变化时数字平滑滚动」。已在
1. ✅ **Canvas AI 助手应用层**(已完成 2026-09-06):agent-thinking / composer-loader 形态落地于 `canvas-agent-chat-ui` 工作态与发送态;待浏览器视觉验收。
2. **Typography 复合类**:吸收 boardui 排版节奏到 globals.css 的 `@theme`(font-size/weight/leading 映射),供主界面使用。
3. **通知中心**:把 agent-log/notification-center 形态用于任务完成/失败推送浮层。
4. 每步遵循 rollout 计划阶段门:先建组件 → 单页替换样板 → 批量消费审计。
2. **Typography 复合类**:吸收 boardui 排版节奏到 globals.css 的 `@theme`(font-size/weight/leading 映射),供主界面使用。
3. **通知中心**:把 agent-log/notification-center 形态用于任务完成/失败推送浮层。
3. ~~通知中心~~:~~把 agent-log/notification-center 形态用于任务完成/失败推送浮层。~~(🚫 已禁用,见 §2.2)
4. 每步遵循 rollout 计划阶段门:先建组件 → 单页替换样板 → 批量消费审计。
## 5. 备注
@@ -93,7 +90,7 @@ BoardUI 最典型消费场景是「数据变化时数字平滑滚动」。已在
1. **C1 create 空态灵感建议卡 —— ✅ 已覆盖,无需吸收(审计修正)**:盘点子代理漏报;`CreationEmptySuggest`(index.tsx 1825)已有 hero 大卡(含 rays 光效)+ 3 张可点击网格卡(含“从参考图开始”→开素材库),点击按模式回填输入框并聚焦,能力与视觉均 ≥ boardui pro-prompt-card。结论:不新增,保留现状。
2. **C2 会话导出 —— ✅ 已实施(2026-09-06)**:历史抽屉行更多菜单新增“导出对话”(index.tsx 1160);`buildConversationExportMarkdown`(1864)按 角色/时间/模式标签/思考过程 拼 Markdown,`downloadCreationConversation` 下载 `.md`(标题净化文件名)。不做 Web Share(桌面场景下载更稳)。
3. **C3 settings 行三列配方**(源:settings-rows `220px_1fr_auto` 标签/控件/提示行):我方各设置 Pane 行式由 AntD Form 拼装、形态不一。吸收为共享行组件渐进替换。价值=一致性,成本=全套 Pane 触碰,**需用户决策是否立项**。
3. **C3 settings 行式配方 —— ✅ 已立项,试点完成(2026-09-06)**:共享组件 `SettingsRow`(components/ui/product/settings-row,左标签/说明 + 右控件 + 行分隔线,末行无线)已建;「生成偏好」Pane 由纵向 Form 改行式并验收基线 tsc 通过(6fc1d92a)。**待办:其余 Pane 批量推广前需用户浏览器验收试点**。
4. **弱候选(默认不做,留痕)**:会话列表“未读点/标记未读”(需求证据弱,我方已有选中/删除);dashboard 图表卡(recharts 已在仓内、admin 已有 analytics-panel,主界面无看板场景);pro rays 光效引擎(create 空态 hero 卡已用等价 CSS 光效,不再引 WebGL 引擎)。
### 6.3 语义/结构备注(domain 对齐)
@@ -103,4 +100,4 @@ BoardUI 最典型消费场景是「数据变化时数字平滑滚动」。已在
### 6.4 建议下一步
C3(settings 行三列配方)立项与否待用户决策——若立项:先抽共享行组件(`components/settings/`),再单 Pane 试点替换,最后批量审计,遵循 §4 门。其余候选均按上文处置。
C3(settings 行式配方)**已立项并完成试点**——待用户浏览器验收「生成偏好」后,再按 §4 门批量推广到其余 Pane(本地运行/模型/音频节点等键值型行;渠道/设备管理重型表单不强推行式)。其余候选均按上文处置。
@@ -97,3 +97,60 @@
- 每个 Phase 独立提交(`feat/fix/refactor` 前缀按仓库规范),提交前 `bunx tsc --noEmit`,改动后同步 `docs/content/docs/progress/pending-test.mdx` 验收段落(含本次删除任务通知已记录的条目)。
- 所有改动保持工作树干净;本计划文档随首轮实施一并提交。
- BoardUI 只读参照;若其视觉与本站 token(明暗自适应)冲突,以本站 token 体系为准。
## 6. 对话消息渲染逐项对照自查(BoardUI 参照)
> 本节按「消息渲染」维度(布局/对齐/气泡/富内容/状态/可达性)逐项列出现状与建议,2026-09-06 代码与 CSS 实测核对。
> 状态图例:✅已对齐|🔧微调(小改)|🛠结构性(中等)|❓待产品决策
### 6.1 布局与对齐
| 编号 | 现状(已实测) | BoardUI 参照 | 建议 | 状态 |
| --- | --- | --- | --- | --- |
| L1 | 会话列 `min(820px, 100% - 48px)` 居中 | 列表同宽居中 | 维持 | ✅ |
| L2 | 助手消息 `width: min(760px, 100%)`,行距原 `space-10`(40px) | 消息垂直间距约 20px、分组更密 | **已实施**:用户/助手消息行距统一降为 `space-8`(32px),长会话视密度更紧凑 | ✅已实施 |
| L3 | 正文列 `padding-left: space-8(32px)`(含头部 mark 对齐) | 无 mark、正文贴左 | 保留 mark 头设计(本站特色);正文/媒体/错误三线缩进统一到 32px | ✅ |
| L4 | 错误/空态行沿用旧 34px 缩进(未见 home 覆盖) | — | **已实施**:新增 home 覆盖 `max-width:720px; padding:16px 0 0 space-8`;窄屏随正文归零 | ✅已实施 |
| L5 | 媒体结果 `max-width 680`、图片 `min(320px)` flex 换行、视频 `min(680px)` | 结果区宽于正文、右缘对齐 | 对齐原则一致;核对图片 gap 与圆角是否 token 化 | 🔧 |
### 6.2 用户气泡
| 编号 | 现状(已实测) | BoardUI 参照 | 建议 | 状态 |
| --- | --- | --- | --- | --- |
| U1 | 气泡为 `copy-wrap`:半径 `r-lg/r-lg/4/r-lg`,`accent 10%` 混底 | `rounded-2xl`(四角 16px)实底 `background-primary` | 尾巴角 4px 是聊天拟物风,保留可;若想更板正可改 16/16/6/16 | ❓ |
| U2 | 气泡原无阴影(`box-shadow:none`) | `shadow-card` | **已实施**:深浅双主题 1px 柔和投影(暗 rgb(0 0 0/.18)、亮 rgb(15 23 42/.08)) | ✅已实施 |
| U3 | 宽度 `min(560px,86%)` 右对齐,内边距原 `10/14` | `max-w-[75%] px-3 py-[11px]` | **已实施**:横向 14→12px,与 boardui `px-3`≈12px 一致 | ✅已实施 |
| U4 | 元信息(你/时间/复制钮)在气泡**上方** meta 行 | 元信息在消息动作行,时间紧随 | 现布局合理;复制钮为幽灵钮 opacity .66→1 | ✅ |
| U5 | 多段/换行由 markdown 渲染 p;无逐段折叠 | 单正文段落 | 维持 | ✅ |
### 6.3 助手消息形态
| 编号 | 现状 | BoardUI 参照 | 建议 | 状态 |
| --- | --- | --- | --- | --- |
| A1 | 头部:mark 块 + 名称 + 模型 + 时间 + 状态徽标 + 变体操作(右缘) | 无头部行、消息下挂操作 | 头部信息密度高(模型/时间常驻);可评估:空闲时模型/时间降为 hover 显示,仅保留名称+状态 | ❓ |
| A2 | 操作在头部右缘(variant-action 幽灵钮) | 28px `rounded-md` 操作钮,`opacity-0`→`group-hover` 浮现,focus-within 常显 | **已实施**:`@media(hover:hover)` 内 hover/focus-within 浮现;触屏(pointer:coarse)保持常显 | ✅已实施 |
| A3 | 思考/流式中间态:pending 帧 + 思维卡片(自研 reasoning) | 独立 thinking 占位(dots/星星/彗星动效、`font-mono` 计时) | **已实施**:流式中 250ms 节流实时秒数(`font-mono tabular-nums`),结束后展示总时长 | ✅已实施 |
| A4 | 生成卡(GenerationToolCard):头部行 + 可折叠正文 | 工具卡以正文内折叠块呈现 | 核对折叠态图标方向与 aria-expanded | ✅ |
### 6.4 富内容与媒体
| 编号 | 现状 | BoardUI 参照 | 建议 | 状态 |
| --- | --- | --- | --- | --- |
| C1 | 代码块:shiki 双主题 + 流式光标(上轮已落地) | — | 复核行号默认关闭、未知语言降级策略 | ✅ |
| C2 | 待生成媒体帧:呼吸渐变 + 取消钮 | — | 与 loader 语义一致,已达标 | ✅ |
| C3 | 视频容器 `aspect-ratio:16/9` 常驻(base 层),home 仅改宽 680;`object-fit:contain` 等比留边 | — | **已核实**:容器比例稳定无闪跳风险,无需改动 | ✅已核实 |
### 6.5 可达性与状态
| 编号 | 现状 | BoardUI 参照 | 建议 | 状态 |
| --- | --- | --- | --- | --- |
| X1 | hover 浮现类动效须尊重 `prefers-reduced-motion` | 同 | A2 隐藏规则仅作用于 `hover:fine` 设备;时长走 `--motion-state`,reduced-motion 由全局规则降级——待浏览器实测 | 🔧待实测 |
| X2 | 行/钮焦点:`:focus-visible` 描边 | `focus-visible:ring-2` | 已一致 | ✅ |
| X3 | 会话列表已接 `role="log"` 与 aria-live | — | 保持 | ✅ |
### 6.6 建议执行顺序
1. ✅ **P1(微调批,已实施)**:L2 行距 32px、L4 错误行 32px、U2 深浅双主题投影、U3 内边距 12px、A2 hover/focus 浮现(触屏常显)。
2. ✅ **P2(结构性,已实施)**:A3 流式 mono 计时(250ms 节流);C3 已核实 base `16/9` 常驻无需改动。
3. ⏳ **P3(待决策,未动)**:U1 圆角风格、A1 头部信息 hover 显隐——等产品定调后实施。
4. ✅ Phase A 历史抽屉(行 hover 菜单/重命名/相对时间)代码已在册;浏览器实测待预览环境补做。
+2 -2
View File
@@ -13,7 +13,7 @@
| base | `ui/base/` | 原语 + 基础件:`buttons/`、`badges/`、`kbd/`、`segmented-control/` 等 |
| product | `ui/product/` | 跨页面模式件:`empty-state/`、`callout/`、`loading-state/`、`section-card/`、`property-row/`、`text-tooltip/` |
| fx | `ui/fx/` | 特效件(现 `aceternity/*` 归位至此命名空间,引用随用随迁,不重写) |
| application | `ui/application/` | 产品块(P3 起):agent-chat、notification-center、app-shell 等,对齐 BoardUI application |
| application | `ui/application/` | 产品块(P3 起):agent-chat、app-shell 等,对齐 BoardUI application(~~notification-center~~ 🚫已禁用,不实施) |
替换完成前 AntD 用法与皮肤仍由 `web/src/lib/app-theme.ts` 统一管理;**同一控件职能不允许两套实现并存超过一个替换周期**。
@@ -95,7 +95,7 @@ Button/Input 全量、Dialog/Modal、Drawer、Popconfirm、Tabs、Combobox/Selec
### P3(阶段 E,先立证据)
application 产品块:agent-chat(composer/history/message)、agent-thinking 指示、notification-center、app-shell、data-table——映射影策 AI 工作台场景。
application 产品块:agent-chat(composer/history/message)、agent-thinking 指示、app-shell、data-table——映射影策 AI 工作台场景(~~notification-center/通知中心~~ 🚫已禁用,不实施)。
### fx
+3 -3
View File
@@ -42,7 +42,7 @@
| 图标由调用方传任意尺寸 class | Icon 以**组件引用**传入,尺寸/颜色由宿主组件用 token 决定(`@remixicon/react`) | ✅ §8 图标契约(本项目沿用 lucide-react) |
| 动效无统一纪律 | `button-press-motion` 等工具类 + `::before` 渐变悬停交叉淡化 + `prefers-reduced-motion` | ✅ §9 动效纪律(本项目已有 motion v12) |
| 组件注释缺溯源 | 每个组件头注释标注 Figma 源节点、尺寸表、明暗差异 | ✅ §10 注释规范(引用 token 组 + 对标对象) |
| 无"agentic 界面"沉淀 | `application/agent-chat`(composer/history/message)、`agent-thinking`、`notification-center`、`app-shell`、`data-table` 等产品块 | ✅ §12 backlog 的 P3 application 层(对齐影策 AI 工作台) |
| 无"agentic 界面"沉淀 | `application/agent-chat`(composer/history/message)、`agent-thinking`、`app-shell`、`data-table` 等产品块(~~notification-center~~ 🚫已禁用,不实施) | ✅ §12 backlog 的 P3 application 层(对齐影策 AI 工作台) |
### 2.3 BoardUI 事实基线(2026-09-05 勘察)
@@ -88,7 +88,7 @@ web/src/
base/ # 原语 + 基础件:buttons/ badges/ kbd/ segmented-control/ …
product/ # 模式件:empty-state/ callout/ loading-state/ section-card/ property-row/ …
fx/ # 特效件(现 aceternity/ 归位命名空间,引用随用随迁)
application/ # 产品块(P3 起):agent-chat/ notification-center/ app-shell/ …(对齐 BoardUI application)
application/ # 产品块(P3 起):agent-chat/ app-shell/ …(对齐 BoardUI application;~~notification-center~~ 🚫已禁用,不实施)
```
导入约定:一律深路径 `@/components/ui/{base,product,fx,application}/<family>/<file>`(或族级 barrel);不建全局 barrel。
@@ -196,7 +196,7 @@ NodeTypeBadge、TextTooltip、LoadingState、SectionCard、PropertyRow、IconGro
- 验证:`tsc --noEmit` + `vite build` 通过(跳过与本次无关的 build:bridge 预构建);浏览器目验清单见 `docs/content/docs/progress/pending-test.mdx`(UI 组件同角色迁移节)。git 改动未提交。
### 阶段 E:application 产品块(P3,按需立项)
对齐 BoardUI `application/`:agent-chat(composer/history/message)、agent-thinking 指示、notification-center、app-shell、data-table 等,映射影策 AI 工作台场景(画布 AI 助手面板、生成/转写日志、通知中心)。每块立项前先有真实页面需求与 ≥2 处重复证据。
对齐 BoardUI `application/`:agent-chat(composer/history/message)、agent-thinking 指示、app-shell、data-table 等,映射影策 AI 工作台场景(画布 AI 助手面板、生成/转写日志等;~~notification-center/通知中心~~ 🚫已禁用,不实施)。每块立项前先有真实页面需求与 ≥2 处重复证据。
## 12. 组件 backlog(汇总)
@@ -128,7 +128,7 @@ export function AssetLibraryPickerModal({
});
const remoteItems = useMemo<AssetLibraryPickerItem[]>(() => (remoteQuery.data?.assets || []).filter((asset) => asset.kind !== "entity" && asset.kind !== "model").map((asset) => ({
id: asset.id, title: asset.title, category: asset.category || "other", archived: asset.status === "archived", asset,
kindLabel: asset.kind === "image" ? "图片" : asset.kind === "video" ? "视频" : asset.kind === "audio" ? "音频" : "文本", searchText: asset.tags.join(" "),
kindLabel: asset.kind === "image" ? "图片" : asset.kind === "video" ? "视频" : asset.kind === "audio" ? "音频" : "文本", searchText: (asset.tags ?? []).join(" "),
...(items.find((item) => item.id === asset.id) || { disabledReason: "此素材不适用于当前操作" }),
})), [remoteQuery.data, items]);
const effectivePagination = remoteEnabled ? { current: remotePage, pageSize: remotePageSize, total: remoteQuery.data?.total || 0, onChange: (page: number, pageSize: number) => { setRemotePage(page); setRemotePageSize(pageSize); } } : pagination;
@@ -355,6 +355,7 @@ export function AssetLibraryPickerModal({
return (
<Modal
centered
open={open}
footer={null}
title={null}
@@ -0,0 +1 @@
export { SettingsRow, type SettingsRowProps } from "./settings-row";
@@ -0,0 +1,31 @@
import type { ReactNode } from "react";
import { cn } from "@/lib/utils";
export interface SettingsRowProps {
label: string;
description?: string;
control?: ReactNode;
align?: "center" | "top";
className?: string;
controlClassName?: string;
}
/**
* SettingsRow —— 设置项行(左侧标签/说明 + 右侧控件)。
*
* 用途:设置页与偏好面板内"一行一个设置项"的排版,替代 Form.Item 的纵向大块布局。
* 行间以细分隔线区分,信息密度高、便于扫读;最后一行自动去掉分隔线。
* token:分隔线 border-foreground/10,标签 text-foreground,说明 text-foreground/55。
*/
export function SettingsRow({ label, description, control, align = "center", className, controlClassName }: SettingsRowProps) {
return (
<div className={cn("flex w-full items-center gap-4 border-b border-foreground/10 py-2.5 last:border-b-0", align === "top" && "items-start", className)}>
<div className="min-w-0 flex-1">
<span className="block text-sm font-medium text-foreground">{label}</span>
{description ? <span className="mt-0.5 block text-xs leading-4 text-foreground/55">{description}</span> : null}
</div>
{control ? <div className={cn("shrink-0", controlClassName)}>{control}</div> : null}
</div>
);
}
+50 -47
View File
@@ -1,5 +1,6 @@
import { App, Button, Form, Input, InputNumber } from "antd";
import { App, Button, Input, InputNumber } from "antd";
import { Select } from "@/components/ui/base/select";
import { SettingsRow } from "@/components/ui/product/settings-row";
import { ArrowLeft, Boxes, Bug, Cloud, MessageSquareText, MonitorUp, RadioTower, SlidersHorizontal, SquareTerminal, Workflow } from "lucide-react";
import { useEffect, useMemo, useState, type ReactNode } from "react";
import { useNavigate, useSearchParams } from "react-router";
@@ -140,13 +141,14 @@ export default function SettingsPage() {
</div>
</div>
<div className="settings-section">
<Form layout="vertical" requiredMark={false}>
<section className="settings-preference-block pb-6">
<div className="mb-4">
<h3 className="text-sm font-semibold">画布生成</h3>
<p className="mt-1 text-xs text-foreground/55">设置新建生成任务时使用的初始值,节点内仍可单独覆盖。</p>
</div>
<Form.Item label="默认生图张数" className="mb-0 max-w-xs">
<section className="settings-preference-block py-4">
<div className="mb-3">
<h3 className="text-[13px] font-medium text-foreground/60">画布生成</h3>
<p className="mt-1 text-xs text-foreground/55">设置新建生成任务时使用的初始值,节点内仍可单独覆盖。</p>
</div>
<SettingsRow
label="默认生图张数"
control={
<InputNumber
min={1}
max={15}
@@ -155,45 +157,46 @@ export default function SettingsPage() {
value={Number(config.canvasImageCount)}
onChange={(value) => updateConfig("canvasImageCount", normalizeImageCount(String(value ?? defaultConfig.canvasImageCount)))}
/>
</Form.Item>
</section>
<section className="settings-preference-block py-6">
<div className="mb-4">
<h3 className="text-sm font-semibold">音频默认值</h3>
<p className="mt-1 text-xs text-foreground/55">用于新建音频节点和未单独设置参数的生成任务。</p>
</div>
<div className="grid gap-4 md:grid-cols-3">
<Form.Item label="默认声音" className="mb-0">
<Select value={config.audioVoice} options={audioVoiceOptions} onChange={(value) => updateConfig("audioVoice", value)} />
</Form.Item>
<Form.Item label="文件格式" className="mb-0">
<Select value={config.audioFormat} options={audioFormatOptions} onChange={(value) => updateConfig("audioFormat", value)} />
</Form.Item>
<Form.Item label="语速" className="mb-0">
<InputNumber
min={0.25}
max={4}
step={0.05}
precision={2}
className="w-full"
value={Number(config.audioSpeed)}
onChange={(value) => updateConfig("audioSpeed", normalizeAudioSpeedValue(String(value ?? defaultConfig.audioSpeed)))}
/>
</Form.Item>
</div>
</section>
<section className="settings-preference-block pt-6">
<div className="mb-4">
<h3 className="text-sm font-semibold">音频指令</h3>
<p className="mt-1 text-xs text-foreground/55">在音频节点没有单独填写时使用。</p>
</div>
<div className="max-w-2xl">
<Form.Item label="默认音频指令" className="mb-0">
<Input.TextArea rows={5} value={config.audioInstructions} placeholder="例如:自然、温暖、适合旁白。" onChange={(event) => updateConfig("audioInstructions", event.target.value)} />
</Form.Item>
</div>
</section>
</Form>
}
controlClassName="w-[200px]"
/>
</section>
<section className="settings-preference-block py-4">
<div className="mb-3">
<h3 className="text-[13px] font-medium text-foreground/60">音频默认值</h3>
<p className="mt-1 text-xs text-foreground/55">用于新建音频节点和未单独设置参数的生成任务。</p>
</div>
<SettingsRow label="默认声音" control={<Select value={config.audioVoice} options={audioVoiceOptions} onChange={(value) => updateConfig("audioVoice", value)} />} controlClassName="w-[200px]" />
<SettingsRow label="文件格式" control={<Select value={config.audioFormat} options={audioFormatOptions} onChange={(value) => updateConfig("audioFormat", value)} />} controlClassName="w-[200px]" />
<SettingsRow
label="语速"
description="音频朗读速度(0.25–4)。"
control={
<InputNumber
min={0.25}
max={4}
step={0.05}
precision={2}
className="w-full"
value={Number(config.audioSpeed)}
onChange={(value) => updateConfig("audioSpeed", normalizeAudioSpeedValue(String(value ?? defaultConfig.audioSpeed)))}
/>
}
controlClassName="w-[200px]"
/>
</section>
<section className="settings-preference-block py-4">
<div className="mb-3">
<h3 className="text-[13px] font-medium text-foreground/60">音频指令</h3>
<p className="mt-1 text-xs text-foreground/55">在音频节点没有单独填写时使用。</p>
</div>
<SettingsRow
label="默认音频指令"
align="top"
control={<Input.TextArea rows={5} value={config.audioInstructions} placeholder="例如:自然、温暖、适合旁白。" onChange={(event) => updateConfig("audioInstructions", event.target.value)} />}
controlClassName="w-full max-w-[480px]"
/>
</section>
</div>
</SettingsPane>
),
+115 -23
View File
@@ -10260,6 +10260,15 @@ html:not(.dark) .creation-chat-reference:hover:not(:disabled) { background: rgba
color: var(--creation-text) !important;
}
.creation-chat-control[aria-pressed="true"],
.creation-chat-control[aria-pressed="true"]:hover {
background: rgba(6, 182, 212, .16) !important;
color: #4dd6ea !important;
}
.creation-chat-control[aria-pressed="true"] > svg { color: #4dd6ea !important; }
.creation-chat-control[aria-pressed="true"]:disabled,
.creation-chat-control[aria-pressed="true"]:disabled:hover { background: rgba(6, 182, 212, .1) !important; color: #4dd6ea !important; opacity: .42 !important; }
.creation-chat-control > svg { width: 14px; height: 14px; }
.creation-chat-control > svg:last-child { width: 12px; height: 12px; color: var(--creation-faint); }
.creation-chat-composer .creation-model-picker.canvas-composer-model-picker { width: min(180px, 30vw) !important; justify-content: flex-start; }
@@ -10271,6 +10280,18 @@ html:not(.dark) .creation-chat-control.is-mode,
html:not(.dark) .creation-chat-control:hover,
html:not(.dark) .creation-chat-composer .creation-model-picker.canvas-composer-model-picker:hover { background: rgba(29, 33, 37, .06) !important; color: var(--creation-text) !important; }
.creation-chat-control:disabled {
opacity: .42 !important;
cursor: not-allowed;
background: transparent !important;
color: var(--creation-muted) !important;
transform: none !important;
}
html:not(.dark) .creation-chat-control:disabled { background: transparent !important; color: var(--creation-muted) !important; }
html:not(.dark) .creation-chat-control[aria-pressed="true"],
html:not(.dark) .creation-chat-control[aria-pressed="true"]:hover { background: rgba(6, 182, 212, .13) !important; color: #0e7490 !important; }
html:not(.dark) .creation-chat-control[aria-pressed="true"] > svg { color: #0e7490 !important; }
.creation-control-popover-surface,
.creation-model-picker-surface {
overflow: hidden;
@@ -12953,12 +12974,26 @@ html:not(.dark) .creation-history-drawer-root {
.creation-history-list > li { position: relative; min-width: 0; }
.creation-history-row { position: relative; display: flex; min-width: 0; align-items: center; border-radius: var(--r-sm); transition: background-color 150ms ease; }
.creation-history-row:hover { background: var(--creation-history-hover); }
.creation-history-row .creation-history-item-main { display: flex; min-width: 0; flex: 1; flex-direction: column; align-items: flex-start; justify-content: center; gap: 3px; border: 0; border-radius: var(--r-sm); background: transparent; padding: 8px 62px 8px 12px; color: var(--creation-history-text); text-align: left; }
.creation-history-row .creation-history-item-main { display: flex; min-width: 0; flex: 1; flex-direction: row; align-items: center; justify-content: flex-start; gap: 12px; border: 0; border-radius: var(--r-sm); background: transparent; padding: 8px 62px 8px 12px; color: var(--creation-history-text); text-align: left; }
.creation-history-row .creation-history-item-main:hover { background: transparent; }
.creation-history-row .creation-history-item-main:focus-visible { outline: 2px solid color-mix(in srgb, var(--creation-history-accent) 68%, transparent); outline-offset: -2px; }
.creation-history-list > li.is-active .creation-history-row { background: color-mix(in srgb, var(--creation-history-accent) 9%, var(--creation-history-surface)); }
.creation-history-list > li.is-active .creation-history-row:hover { background: color-mix(in srgb, var(--creation-history-accent) 14%, var(--creation-history-surface)); }
.creation-history-item-heading { width: 100%; overflow: hidden; font-size: var(--fs-label); font-weight: 650; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; }
.creation-history-item-text { display: flex; min-width: 0; flex: 1; flex-direction: column; align-items: flex-start; justify-content: center; gap: 3px; }
.creation-history-item-icon {
display: grid;
width: 34px;
height: 34px;
flex: 0 0 auto;
place-items: center;
border-radius: 99px;
background: color-mix(in srgb, var(--creation-history-accent) 16%, transparent);
color: var(--creation-history-accent);
transition: background-color 150ms ease, color 150ms ease;
}
.creation-history-item-icon svg { width: 16px; height: 16px; }
.creation-history-list > li.is-active .creation-history-item-icon { background: color-mix(in srgb, var(--creation-history-accent) 24%, transparent); color: var(--creation-history-accent); }
.creation-history-snippet { display: flex; width: 100%; min-width: 0; align-items: baseline; gap: 6px; overflow: hidden; color: color-mix(in srgb, var(--creation-history-muted) 88%, transparent); font-size: var(--fs-micro); line-height: 1.45; }
.creation-history-snippet em { flex: 0 0 auto; color: color-mix(in srgb, var(--creation-history-muted) 80%, transparent); font-size: var(--fs-micro); font-style: normal; font-weight: 600; }
.creation-history-snippet span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -12980,6 +13015,8 @@ html:not(.dark) .creation-history-drawer-root {
.creation-history-empty { display: grid; min-height: 180px; place-items: center; color: var(--creation-history-muted); font-size: var(--fs-label); }
.creation-history-menu-overlay .ant-dropdown-menu { border-radius: var(--r-md); padding: 4px; min-width: 168px; }
.creation-history-menu-overlay .ant-dropdown-menu .ant-dropdown-menu-item { border-radius: 6px; }
.creation-history-menu-overlay .ant-dropdown-menu-item-icon { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; }
.creation-history-menu-overlay .ant-dropdown-menu-item-icon svg { display: block; width: 14px; height: 14px; }
@media (pointer: coarse) {
.creation-history-more { opacity: 1; }
.creation-history-row:hover .creation-history-time-slot { opacity: 1; }
@@ -15562,8 +15599,8 @@ html.dark .ai-message-codeblock-pre .shiki span { color: var(--shiki-dark) !impo
max-width: none;
flex-direction: column;
align-items: flex-end;
gap: var(--space-2);
margin: 0 0 var(--space-10) auto;
gap: var(--space-3);
margin: 0 0 var(--space-8) auto;
border-radius: 0;
background: transparent;
padding: 0;
@@ -15580,15 +15617,44 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
color: var(--creation-faint);
font-size: var(--fs-label);
}
.creation-home .creation-user-avatar {
display: grid;
width: 26px;
height: 26px;
flex: 0 0 26px;
place-items: center;
overflow: hidden;
border: 0;
border-radius: 50%;
background: rgba(255, 255, 255, .08);
color: var(--creation-muted);
}
.creation-home .creation-user-avatar svg { width: 15px; height: 15px; }
.creation-home .creation-user-avatar img { width: 100%; height: 100%; object-fit: cover; }
.creation-home .creation-user-message-meta strong {
color: var(--creation-text);
font-size: var(--fs-body);
font-weight: 620;
white-space: nowrap;
}
html:not(.dark) .creation-home .creation-user-avatar { background: rgba(15, 23, 42, .07); color: var(--creation-faint); }
.creation-home .creation-user-message-meta time,
.creation-home .creation-message-heading time { color: var(--creation-faint); font-size: var(--fs-micro); }
.creation-home .creation-user-message-copy {
.creation-home .creation-user-message-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 2px;
margin-top: 6px;
transition: opacity var(--motion-state) ease;
}
.creation-home .creation-user-message-actions button {
display: grid;
width: var(--space-5);
height: var(--space-5);
flex: 0 0 var(--space-5);
place-items: center;
border: 0;
border-radius: var(--r-xs);
@@ -15599,23 +15665,27 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
opacity: .66;
transition: background-color var(--motion-state) ease, color var(--motion-state) ease, opacity var(--motion-state) ease;
}
.creation-home .creation-user-message-copy:hover {
.creation-home .creation-user-message-actions button svg { width: 15px; height: 15px; }
.creation-home .creation-user-message-actions button:hover {
background: var(--creation-surface-hover);
color: var(--creation-text);
opacity: 1;
}
.creation-home .creation-user-message-copy:focus-visible { outline: 2px solid var(--creation-accent); outline-offset: 1px; }
.creation-home .creation-user-message-copy svg { width: var(--space-3); height: var(--space-3); }
.creation-home .creation-user-message-actions button svg { width: var(--space-3); height: var(--space-3); }
.creation-home .creation-user-message-actions button:focus-visible { outline: 2px solid var(--creation-accent); outline-offset: 1px; }
@media (hover: hover) and (pointer: fine) {
.creation-home .creation-user-message:not(:hover):not(:focus-within) .creation-user-message-actions { opacity: 0; }
}
.creation-home .creation-user-message-copy-wrap {
width: fit-content;
max-width: 100%;
border-radius: var(--r-lg) var(--r-lg) 4px var(--r-lg);
background: color-mix(in srgb, var(--creation-accent) 10%, var(--creation-surface));
padding: 10px 14px;
padding: 10px 12px;
box-shadow: 0 1px 2px 0 rgb(0 0 0 / .18);
}
html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0 1px 2px 0 rgb(15 23 42 / .08); }
.creation-home .creation-user-message-copy-wrap p {
margin: 0;
@@ -15630,7 +15700,7 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
.creation-home .creation-assistant-message {
width: min(760px, 100%);
max-width: none;
margin: 0 0 var(--space-10);
margin: 0 0 var(--space-8);
background: transparent;
}
@@ -15661,12 +15731,32 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
.creation-home .creation-message-variant-action:hover { background: var(--creation-surface-hover); color: var(--creation-text); }
.creation-home .creation-message-variant-action:focus-visible { outline: 2px solid var(--creation-accent); outline-offset: 1px; }
.creation-home .creation-message-variant-action svg { width: var(--space-3); height: var(--space-3); }
@media (hover: hover) and (pointer: fine) {
.creation-home .creation-assistant-message:not(:hover):not(:focus-within) .creation-message-variant-action { opacity: 0; }
.creation-home .creation-message-variant-action { transition: opacity var(--motion-state) ease, background-color var(--motion-state) ease, color var(--motion-state) ease; }
}
.creation-home .creation-message-content {
max-width: 720px;
padding: var(--space-3) 0 0 var(--space-8);
}
.creation-home .creation-message-error {
max-width: 720px;
padding: 16px 0 0 var(--space-8);
}
.creation-home .creation-message-reasoning-wrap {
max-width: 720px;
padding: var(--space-3) 0 0 var(--space-8);
}
.creation-home .creation-message-reasoning-wrap > div { margin-bottom: 0; }
.creation-home .creation-thread-composer .creation-chat-writing-surface { min-height: 0; }
.creation-home .creation-thread-composer .creation-chat-editor textarea { min-height: 44px; }
.creation-home .creation-thread-composer .creation-reference-panel { margin-bottom: var(--space-1); }
.creation-home .creation-thread-composer .creation-reference-track-wrapper { min-height: 40px; }
.creation-home .creation-thread-composer .creation-reference-track.is-empty { padding-top: 0; padding-bottom: 0; }
.creation-home .creation-media-pending {
position: relative;
display: grid;
@@ -15811,6 +15901,8 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
.creation-home .creation-thread-stage { padding-top: var(--space-5); }
.creation-home .creation-user-message { width: 92%; max-width: none; }
.creation-home .creation-message-content,
.creation-home .creation-message-error,
.creation-home .creation-message-reasoning-wrap,
.creation-home .creation-media-result { padding-left: 0; }
.creation-home .creation-media-pending { width: min(var(--creation-media-pending-max-width), 100%); margin-left: 0; }
.creation-home .creation-media-error { width: 100%; margin-left: 0; }
@@ -15978,7 +16070,7 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
/* —— 创建页历史抽屉:新建置顶卡 + 时间分组(吸收 boardui agent-chat-history)—— */
.creation-home .creation-history-new {
.creation-history-new {
display: flex;
width: calc(100% - 4px);
align-items: center;
@@ -15993,9 +16085,9 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
cursor: pointer;
transition: background-color 150ms ease, border-color 150ms ease, transform 150ms ease;
}
.creation-home .creation-history-new:hover { border-color: color-mix(in srgb, var(--creation-history-accent) 74%, var(--creation-history-line)); background: color-mix(in srgb, var(--creation-history-accent) 10%, transparent); }
.creation-home .creation-history-new:focus-visible { outline: 2px solid color-mix(in srgb, var(--creation-history-accent) 70%, transparent); outline-offset: 1px; }
.creation-home .creation-history-new-icon {
.creation-history-new:hover { border-color: color-mix(in srgb, var(--creation-history-accent) 74%, var(--creation-history-line)); background: color-mix(in srgb, var(--creation-history-accent) 10%, transparent); }
.creation-history-new:focus-visible { outline: 2px solid color-mix(in srgb, var(--creation-history-accent) 70%, transparent); outline-offset: 1px; }
.creation-history-new-icon {
display: grid;
width: 34px;
height: 34px;
@@ -16005,12 +16097,12 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
background: color-mix(in srgb, var(--creation-history-accent) 16%, transparent);
color: var(--creation-history-accent);
}
.creation-home .creation-history-new-icon svg { width: 16px; height: 16px; }
.creation-home .creation-history-new-copy { display: flex; min-width: 0; flex-direction: column; gap: 1px; }
.creation-home .creation-history-new-copy strong { font-size: var(--fs-label); font-weight: 650; }
.creation-home .creation-history-new-copy small { overflow: hidden; color: var(--creation-history-muted); font-size: var(--fs-micro); text-overflow: ellipsis; white-space: nowrap; }
.creation-home .creation-history-group-head { position: sticky; z-index: 1; top: 0; margin-top: 4px; padding: 10px 4px 5px; background: linear-gradient(to bottom, var(--creation-history-bg) 78%, transparent); }
.creation-home .creation-history-group-head h4 {
.creation-history-new-icon svg { width: 16px; height: 16px; }
.creation-history-new-copy { display: flex; min-width: 0; flex-direction: column; gap: 1px; }
.creation-history-new-copy strong { font-size: var(--fs-label); font-weight: 650; }
.creation-history-new-copy small { overflow: hidden; color: var(--creation-history-muted); font-size: var(--fs-micro); text-overflow: ellipsis; white-space: nowrap; }
.creation-history-group-head { position: sticky; z-index: 1; top: 0; margin-top: 4px; padding: 10px 4px 5px; background: linear-gradient(to bottom, var(--creation-history-bg) 78%, transparent); }
.creation-history-group-head h4 {
display: flex;
align-items: baseline;
gap: 6px;
@@ -16020,4 +16112,4 @@ html:not(.dark) .creation-home .creation-user-message { background: transparent;
font-weight: 640;
letter-spacing: .04em;
}
.creation-home .creation-history-group-head h4::after { content: ""; flex: 1; height: 1px; background: var(--creation-history-line); transform: translateY(-2px); }
.creation-history-group-head h4::after { content: ""; flex: 1; height: 1px; background: var(--creation-history-line); transform: translateY(-2px); }