在新建作品流程中暴露转述进料,并加上产物栏与清空对话。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+202
-64
@@ -8,6 +8,7 @@ import {
|
||||
renderQuestionsCard,
|
||||
} from "./questions-ui.js";
|
||||
import { displayWorkerLabel, formatWorkerDisplayTitle, isFlowPlanReview, reviewComposerCopy } from "./display-labels.js";
|
||||
import { formatBodyHtml } from "./markdown.js";
|
||||
import {
|
||||
PRESENT_SHELL_IDS,
|
||||
parsePresentDoc,
|
||||
@@ -32,6 +33,7 @@ const MSG_CLASS = {
|
||||
orchestrator_thinking: "agent",
|
||||
orchestrator_prompt: "agent",
|
||||
orchestrator_assessment: "agent",
|
||||
dictate_reply: "agent",
|
||||
worker_running: "skill",
|
||||
worker_output: "skill",
|
||||
worker_questions: "questions",
|
||||
@@ -45,6 +47,7 @@ const MSG_LABEL = {
|
||||
orchestrator_thinking: "编排器 · 思考",
|
||||
orchestrator_prompt: "编排器",
|
||||
orchestrator_assessment: "编排器 · 内容评价",
|
||||
dictate_reply: "转述整理",
|
||||
worker_running: "执行单元",
|
||||
worker_output: "执行单元",
|
||||
worker_questions: "提问",
|
||||
@@ -96,6 +99,11 @@ export function isCreationCloserDone(view) {
|
||||
}
|
||||
|
||||
export function canOfferSaveProduct(view) {
|
||||
if (!view || isPlayView(view)) return false;
|
||||
if (view.creationMode === "dictate") {
|
||||
const products = view.dictateProducts;
|
||||
return Array.isArray(products) && products.length > 0;
|
||||
}
|
||||
return isCreationSealedWaiting(view) || isCreationCloserDone(view);
|
||||
}
|
||||
|
||||
@@ -490,7 +498,7 @@ function cancelInlineEdit(card) {
|
||||
card.querySelector(".msg-foot")?.removeAttribute("hidden");
|
||||
const editing = card.querySelector(".msg-body-editing");
|
||||
if (editing) {
|
||||
editing.outerHTML = `<div class="msg-body">${esc(original)}</div>`;
|
||||
editing.outerHTML = `<div class="msg-body">${formatBodyHtml(original)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,19 +697,34 @@ export function renderSkillPicker(_view, _onPick) {
|
||||
let activeRailTab = "books";
|
||||
/** 用户手动展开侧栏后,在本会话保持展开,直到再点收起 */
|
||||
let railUserExpanded = false;
|
||||
/** 创作验收右侧「此前对话」:默认收起,把宽度留给产物 */
|
||||
/** 创作右侧栏:history=此前对话;products=转述产物 */
|
||||
let coordRailMode = "history";
|
||||
/** 创作验收右侧栏:默认收起(对话);转述看产物时默认展开 */
|
||||
let coordRailCollapsed = true;
|
||||
|
||||
function syncCoordRailChrome() {
|
||||
const rail = document.getElementById("coord-rail");
|
||||
const toggle = document.getElementById("btn-coord-toggle");
|
||||
const toggleLabel = document.getElementById("coord-rail-toggle-label");
|
||||
const title = document.getElementById("coord-rail-title");
|
||||
const products = coordRailMode === "products";
|
||||
document.body.classList.toggle("coord-rail-collapsed", coordRailCollapsed);
|
||||
document.body.dataset.coordRailMode = coordRailMode;
|
||||
if (toggleLabel) toggleLabel.textContent = products ? "产物" : "对话";
|
||||
if (title) title.textContent = products ? "已持久化" : "此前对话";
|
||||
if (toggle) {
|
||||
toggle.setAttribute("aria-expanded", coordRailCollapsed ? "false" : "true");
|
||||
toggle.title = coordRailCollapsed ? "展开此前对话" : "收起此前对话";
|
||||
toggle.title = coordRailCollapsed
|
||||
? products
|
||||
? "展开产物"
|
||||
: "展开此前对话"
|
||||
: products
|
||||
? "收起产物"
|
||||
: "收起此前对话";
|
||||
}
|
||||
if (rail) {
|
||||
rail.dataset.collapsed = coordRailCollapsed ? "1" : "0";
|
||||
rail.setAttribute("aria-label", products ? "已持久化产物" : "此前对话");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4668,10 +4691,12 @@ function getRollbackMessageId(messages, messageId) {
|
||||
return messageIndex >= 0 ? messages[messageIndex + 1]?.id ?? null : null;
|
||||
}
|
||||
|
||||
/** @returns {"speak"|"answer"|"review"|"busy"|null} */
|
||||
/** @returns {"speak"|"answer"|"review"|"busy"|"dictate"|null} */
|
||||
function resolveDesignSurface(view, loading) {
|
||||
if (isPlayView(view)) return null;
|
||||
if (view.phase === "done") return null;
|
||||
// 转述:主面始终是对话流;右侧才是产物
|
||||
if (view.creationMode === "dictate") return "dictate";
|
||||
const busy = Boolean(loading || (view.phase === "running" && !view.waitingReason));
|
||||
if (busy) return "busy";
|
||||
if (view.phase === "error") return "speak";
|
||||
@@ -4850,7 +4875,11 @@ function renderSpeakWorkspace(view) {
|
||||
if (canOfferSaveProduct(view)) {
|
||||
title = "可以落档了";
|
||||
hint = view.hasProduct
|
||||
? "产物已拆出,可开玩;创作流程还在,补节点或再保存一份新定稿。"
|
||||
? view.creationMode === "dictate"
|
||||
? "产物已拆出,可开玩;创作对话还在,可继续改产物或再保存一份新定稿。"
|
||||
: "产物已拆出,可开玩;创作流程还在,补节点或再保存一份新定稿。"
|
||||
: view.creationMode === "dictate"
|
||||
? "保存后创作对话仍在;拆出的产物可以单独开玩、存档。"
|
||||
: "保存后创作流程仍在;拆出的产物可以单独开玩、存档。";
|
||||
} else if (wr?.kind === "pick_creation_step" || isFlowPlanReview(view)) {
|
||||
title = "选要做的节点";
|
||||
@@ -4890,14 +4919,30 @@ function renderSpeakWorkspace(view) {
|
||||
? proposedOutputCopy(view.proposedNextStep)
|
||||
: view.focus?.detail || "确认执行,或在底栏说明意见。";
|
||||
} else if (wr?.kind === "input") {
|
||||
if (isPlayView(view)) {
|
||||
title = "继续游玩";
|
||||
hint =
|
||||
view.hints?.[0] ||
|
||||
wr.message ||
|
||||
"描述本轮行动、对话或想说的话;由游玩管线推进。";
|
||||
} else if (view.creationMode === "dictate") {
|
||||
title = "转述整理";
|
||||
hint =
|
||||
view.hints?.[0] ||
|
||||
wr.message ||
|
||||
"直接说体验与设定;右侧「已持久化」会列出 Agent 写入的内容。";
|
||||
} else {
|
||||
title = "继续说";
|
||||
hint = view.hints?.[0] || wr.message || "直接输入你的想法或补充。";
|
||||
}
|
||||
} else if (view.uiPrompt && !hasUserMessages(view)) {
|
||||
title = "描述你想创作什么";
|
||||
hint = String(view.uiPrompt).trim().slice(0, 280);
|
||||
}
|
||||
const recipe =
|
||||
view.selectedRecipe?.name && !hasUserMessages(view)
|
||||
view.selectedRecipe?.name &&
|
||||
!isPlayView(view) &&
|
||||
(view.creationMode === "dictate" || !hasUserMessages(view))
|
||||
? `<p class="workspace-intent-meta">配方:${esc(view.selectedRecipe.name)}</p>`
|
||||
: "";
|
||||
const intake =
|
||||
@@ -4931,7 +4976,11 @@ function renderSpeakWorkspace(view) {
|
||||
flowInteractive
|
||||
? workspaceViewSwitchHtml("flow")
|
||||
: `<span class="workspace-surface-kicker">${
|
||||
canOfferSaveProduct(view) ? "落档" : "说话"
|
||||
view.creationMode === "dictate"
|
||||
? "转述"
|
||||
: canOfferSaveProduct(view)
|
||||
? "落档"
|
||||
: "说话"
|
||||
}</span>`
|
||||
}
|
||||
</div>
|
||||
@@ -4945,14 +4994,53 @@ function renderSpeakWorkspace(view) {
|
||||
</section>`;
|
||||
}
|
||||
|
||||
function renderAnswerWorkspaceShell(view) {
|
||||
return `<section class="workspace-answer" id="workspace-answer-slot">
|
||||
<header class="workspace-answer-head workspace-answer-head--slim">
|
||||
${leaveStepControlHtml(view)}
|
||||
<span class="workspace-surface-kicker">答题</span>
|
||||
<p class="workspace-answer-hint">点字母选中,文案可改;点卡片展开,点顶条收起。</p>
|
||||
</header>
|
||||
</section>`;
|
||||
/** 转述式:产物列表(右侧栏) */
|
||||
function renderDictateProductsList(view) {
|
||||
const items = Array.isArray(view.dictateProducts) ? view.dictateProducts : [];
|
||||
if (!items.length) {
|
||||
return `<p class="coord-empty">尚无写入。Agent 落盘产物后会出现在这里。</p>`;
|
||||
}
|
||||
return `<div class="dictate-products-list">${items
|
||||
.map((p) => {
|
||||
const tag = String(p.tag ?? "").trim();
|
||||
const content = String(p.content ?? "");
|
||||
const preview = content.replace(/\s+/g, " ").trim().slice(0, 72);
|
||||
return `<details class="dictate-product dictate-product--rail" open>
|
||||
<summary>
|
||||
<span class="dictate-product-tag">${esc(tag)}${
|
||||
p.order != null && Number.isFinite(Number(p.order))
|
||||
? ` · ${Number(p.order)}`
|
||||
: ""
|
||||
}</span>
|
||||
<span class="dictate-product-preview">${esc(preview)}${
|
||||
content.length > 72 ? "…" : ""
|
||||
}</span>
|
||||
</summary>
|
||||
<div class="dictate-product-body">${formatBodyHtml(content)}</div>
|
||||
</details>`;
|
||||
})
|
||||
.join("")}</div>`;
|
||||
}
|
||||
|
||||
function fillCoordRailProducts(view) {
|
||||
const coordRail = document.getElementById("coord-rail");
|
||||
const drawerBody = document.getElementById("coord-drawer-body");
|
||||
const drawerCount = document.getElementById("coord-drawer-count");
|
||||
if (!coordRail) return;
|
||||
const items = Array.isArray(view.dictateProducts) ? view.dictateProducts : [];
|
||||
if (coordRailMode !== "products") {
|
||||
coordRailMode = "products";
|
||||
coordRailCollapsed = false;
|
||||
}
|
||||
coordRail.hidden = false;
|
||||
if (drawerBody) drawerBody.innerHTML = renderDictateProductsList(view);
|
||||
if (drawerCount) {
|
||||
drawerCount.textContent = String(items.length);
|
||||
drawerCount.title = items.length
|
||||
? `已持久化 ${items.length} 项`
|
||||
: "尚无产物";
|
||||
}
|
||||
syncCoordRailChrome();
|
||||
}
|
||||
|
||||
function fillCoordRail(visible, view, handlers) {
|
||||
@@ -4960,6 +5048,18 @@ function fillCoordRail(visible, view, handlers) {
|
||||
const drawerBody = document.getElementById("coord-drawer-body");
|
||||
const drawerCount = document.getElementById("coord-drawer-count");
|
||||
if (!coordRail) return;
|
||||
|
||||
// 转述产物栏只在创作层;游玩层与配方开玩一样走回合历史
|
||||
if (view.creationMode === "dictate" && !isPlayView(view)) {
|
||||
fillCoordRailProducts(view);
|
||||
return;
|
||||
}
|
||||
|
||||
if (coordRailMode !== "history") {
|
||||
coordRailMode = "history";
|
||||
coordRailCollapsed = true;
|
||||
}
|
||||
|
||||
const visibleIds = new Set(visible.map((message) => message.id));
|
||||
const history = (view.messages ?? []).filter((message) => {
|
||||
if (isReviewSidecarQuestionStub(message)) return false;
|
||||
@@ -4967,7 +5067,6 @@ function fillCoordRail(visible, view, handlers) {
|
||||
});
|
||||
const traceCount = history.filter((message) => message.contextTrace).length;
|
||||
const packs = groupCoordTurnPacks(history);
|
||||
// 侧栏是回看档案:打开先看最近一轮,往下才是更早的对话
|
||||
const ordered = [...packs].reverse();
|
||||
const hiddenIds = new Set(
|
||||
history.filter((message) => !visibleIds.has(message.id)).map((message) => message.id),
|
||||
@@ -5105,6 +5204,39 @@ export function renderMessageFeed(view, loading, handlers = {}) {
|
||||
|
||||
if (!stage) return;
|
||||
|
||||
// 转述:主柱对话流;右侧已持久化;stage 仅一行条
|
||||
if (surface === "dictate") {
|
||||
stage.hidden = false;
|
||||
const recipeName = view.selectedRecipe?.name
|
||||
? esc(view.selectedRecipe.name)
|
||||
: "";
|
||||
stage.innerHTML = recipeName
|
||||
? `<header class="dictate-stage-bar"><span class="workspace-surface-kicker">转述</span><span class="dictate-stage-recipe">配方 · ${recipeName}</span></header>`
|
||||
: `<header class="dictate-stage-bar"><span class="workspace-surface-kicker">转述</span></header>`;
|
||||
if (panelFeed) ensureQuestionsHostIn(panelFeed);
|
||||
appendMessagesToFeed(feed, visible, view, handlers, activeQuestions, {
|
||||
emptyText:
|
||||
"直接说你想要的体验与设定。我会整理进右侧产物,并在回复里跟你确认、建议补充。",
|
||||
loading,
|
||||
});
|
||||
if (loading) {
|
||||
const pending = document.createElement("article");
|
||||
pending.className = "msg agent msg-assistant-row msg-pending";
|
||||
pending.id = "msg-live-pending";
|
||||
const live = view.liveStream;
|
||||
const label = live?.label ?? view.focus?.action ?? "整理中";
|
||||
pending.innerHTML = `
|
||||
<div class="msg-bubble">
|
||||
<header class="msg-head"><span class="msg-tag">${esc(label)}</span><span class="msg-live-indicator">流式输出中</span>${renderRetryRunButton()}</header>
|
||||
<div class="msg-body msg-live-body">${renderLiveStreamBody(live, view)}</div>
|
||||
</div>`;
|
||||
feed.appendChild(pending);
|
||||
wireRetryRun(pending, handlers);
|
||||
}
|
||||
feed.scrollTop = feed.scrollHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface === "busy" || loading) {
|
||||
stage.hidden = false;
|
||||
const live = view.liveStream;
|
||||
@@ -5158,29 +5290,63 @@ export function renderMessageFeed(view, loading, handlers = {}) {
|
||||
return;
|
||||
}
|
||||
|
||||
// —— 游玩:保持原对话流 ——
|
||||
if (!visible.length && !loading) {
|
||||
const p = document.createElement("p");
|
||||
p.className = "empty";
|
||||
if (isPlayView(view)) {
|
||||
p.textContent = "开场已就绪。在下方说你要做什么。";
|
||||
} else if (view.uiPrompt) {
|
||||
const recipeLine = view.selectedRecipe?.name
|
||||
// —— 游玩 / 转述对话流 ——
|
||||
appendMessagesToFeed(feed, visible, view, handlers, activeQuestions, {
|
||||
emptyText: isPlayView(view)
|
||||
? "开场已就绪。在下方说你要做什么。"
|
||||
: view.uiPrompt
|
||||
? `${view.uiPrompt}${
|
||||
view.selectedRecipe?.name
|
||||
? `\n\n已选配方:${view.selectedRecipe.name}`
|
||||
: view.recipes?.length
|
||||
? "\n\n(请先在新建作品时选定配方)"
|
||||
: "";
|
||||
p.textContent = `${view.uiPrompt}${recipeLine}`;
|
||||
p.classList.add("empty-intake");
|
||||
} else if (view.waitingReason?.kind === "worker_questions") {
|
||||
p.textContent = "在下方回答提问。";
|
||||
} else if (intake) {
|
||||
p.textContent = "在下方描述你想创作什么;Agent 会收成 Worker 集供你验收。";
|
||||
} else {
|
||||
p.textContent = "在下方继续对话。";
|
||||
: ""
|
||||
}`
|
||||
: view.waitingReason?.kind === "worker_questions"
|
||||
? "在下方回答提问。"
|
||||
: intake
|
||||
? "在下方描述你想创作什么;Agent 会收成 Worker 集供你验收。"
|
||||
: "在下方继续对话。",
|
||||
loading,
|
||||
emptyClass: isPlayView(view) ? "empty" : "empty empty-intake",
|
||||
});
|
||||
|
||||
if (reviewingNow && view.reviewArtifact && !loading && stage && !isPlayView(view)) {
|
||||
const hasHungAsk = Boolean(activeQuestions?.questions?.length);
|
||||
mountReviewWorkspace(stage, view, handlers, {
|
||||
hideAskSidecar: hasHungAsk,
|
||||
mountAskCard: hasHungAsk,
|
||||
});
|
||||
}
|
||||
p.classList.add("empty-intake");
|
||||
|
||||
if (loading) {
|
||||
const pending = document.createElement("article");
|
||||
pending.className = "msg agent msg-assistant-row msg-pending";
|
||||
pending.id = "msg-live-pending";
|
||||
const live = view.liveStream;
|
||||
const label = live?.label ?? view.focus?.action ?? "处理中";
|
||||
pending.innerHTML = `
|
||||
<div class="msg-bubble">
|
||||
<header class="msg-head"><span class="msg-tag">${esc(label)}</span><span class="msg-live-indicator">流式输出中</span>${renderRetryRunButton()}</header>
|
||||
<div class="msg-body msg-live-body">${renderLiveStreamBody(live, view)}</div>
|
||||
</div>`;
|
||||
feed.appendChild(pending);
|
||||
wireRetryRun(pending, handlers);
|
||||
}
|
||||
|
||||
feed.scrollTop = feed.scrollHeight;
|
||||
if (stage && !stage.hidden) stage.scrollTop = 0;
|
||||
}
|
||||
|
||||
function appendMessagesToFeed(feed, visible, view, handlers, activeQuestions, opts = {}) {
|
||||
const loading = Boolean(opts.loading);
|
||||
if (!visible.length && !loading) {
|
||||
const p = document.createElement("p");
|
||||
p.className = opts.emptyClass || "empty empty-intake";
|
||||
p.textContent = opts.emptyText || "在下方继续对话。";
|
||||
feed.appendChild(p);
|
||||
wireMessageFeedActions(feed, handlers);
|
||||
wireMessageContextMenu(feed, handlers);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5217,8 +5383,7 @@ export function renderMessageFeed(view, loading, handlers = {}) {
|
||||
card.dataset.originalText = body;
|
||||
|
||||
const questionsActive = kind === "worker_questions" && Boolean(activeQuestions);
|
||||
const showThinking =
|
||||
!isUser && msg.thinking && isPlayView(view);
|
||||
const showThinking = !isUser && msg.thinking && isPlayView(view);
|
||||
const innerBody = questionsActive
|
||||
? `<p class="msg-q-index">${esc(body)}</p>`
|
||||
: kind === "worker_questions"
|
||||
@@ -5227,7 +5392,7 @@ export function renderMessageFeed(view, loading, handlers = {}) {
|
||||
? formatPlayPresentHtml(body, view)
|
||||
: kind === "worker_output"
|
||||
? formatArtifactBodyHtml(body)
|
||||
: esc(body);
|
||||
: formatBodyHtml(body);
|
||||
|
||||
const process = !isUser && isPlayProcessMessage(msg, view);
|
||||
const playFinal = !isUser && isPlayFinalReply(msg, view);
|
||||
@@ -5255,35 +5420,8 @@ export function renderMessageFeed(view, loading, handlers = {}) {
|
||||
}
|
||||
feed.appendChild(card);
|
||||
}
|
||||
|
||||
wireMessageFeedActions(feed, handlers);
|
||||
wireMessageContextMenu(feed, handlers);
|
||||
|
||||
if (reviewingNow && view.reviewArtifact && !loading && stage && !isPlayView(view)) {
|
||||
const hasHungAsk = Boolean(activeQuestions?.questions?.length);
|
||||
mountReviewWorkspace(stage, view, handlers, {
|
||||
hideAskSidecar: hasHungAsk,
|
||||
mountAskCard: hasHungAsk,
|
||||
});
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
const pending = document.createElement("article");
|
||||
pending.className = "msg agent msg-assistant-row msg-pending";
|
||||
pending.id = "msg-live-pending";
|
||||
const live = view.liveStream;
|
||||
const label = live?.label ?? view.focus?.action ?? "处理中";
|
||||
pending.innerHTML = `
|
||||
<div class="msg-bubble">
|
||||
<header class="msg-head"><span class="msg-tag">${esc(label)}</span><span class="msg-live-indicator">流式输出中</span>${renderRetryRunButton()}</header>
|
||||
<div class="msg-body msg-live-body">${renderLiveStreamBody(live, view)}</div>
|
||||
</div>`;
|
||||
feed.appendChild(pending);
|
||||
wireRetryRun(pending, handlers);
|
||||
}
|
||||
|
||||
feed.scrollTop = feed.scrollHeight;
|
||||
if (stage && !stage.hidden) stage.scrollTop = 0;
|
||||
}
|
||||
|
||||
/** 轮询时仅更新流式 pending 卡片,避免整页重绘;不自动滚到底,保持用户当前阅读位置 */
|
||||
|
||||
+183
-25
@@ -27,6 +27,11 @@ import {
|
||||
themeById,
|
||||
chromeById,
|
||||
} from "./theme.js";
|
||||
import {
|
||||
applyMarkdownRender,
|
||||
initMarkdownRender,
|
||||
isMarkdownRenderEnabled,
|
||||
} from "./markdown.js";
|
||||
|
||||
let sessionId = null;
|
||||
let activeBookId = null;
|
||||
@@ -124,7 +129,9 @@ function resolveUserTask(view, loading) {
|
||||
label: "可保存",
|
||||
title: "落档产物",
|
||||
hint: view.hasProduct
|
||||
? "可再保存一份新定稿,或用已有产物开玩。补节点仍点图。"
|
||||
? "可再保存一份新定稿,或用已有产物开玩。"
|
||||
: view.creationMode === "dictate"
|
||||
? "点「保存定稿」拆出产物。创作对话还在,之后用产物开玩。"
|
||||
: "点「保存定稿」拆出产物。创作流程还在,之后用产物开玩。",
|
||||
};
|
||||
}
|
||||
@@ -565,6 +572,43 @@ function composerInputShell(spec, { textareaHtml, trailing = "" } = {}) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function composerMoreMenuHtml() {
|
||||
const on = isMarkdownRenderEnabled();
|
||||
return `<details class="more-menu composer-more-menu" id="composer-more-menu">
|
||||
<summary class="btn-sm more-menu-sum" title="更多选项" aria-label="更多选项">
|
||||
<span class="hamburger-icon" aria-hidden="true"></span>
|
||||
</summary>
|
||||
<div class="more-menu-panel composer-more-panel" role="menu">
|
||||
<div class="more-menu-label">显示</div>
|
||||
<button
|
||||
type="button"
|
||||
class="more-menu-item more-toggle-item${on ? " is-active" : ""}"
|
||||
data-toggle-markdown
|
||||
role="menuitemcheckbox"
|
||||
aria-checked="${on ? "true" : "false"}"
|
||||
>
|
||||
<span class="more-theme-copy">
|
||||
<span class="more-theme-name">Markdown 渲染</span>
|
||||
<span class="more-theme-desc">消息与产物按 Markdown 显示</span>
|
||||
</span>
|
||||
<span class="more-toggle-mark" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</details>`;
|
||||
}
|
||||
|
||||
function composerFormHtml(shell) {
|
||||
return `<form class="composer-form" id="composer-form">${composerMoreMenuHtml()}${shell}</form>`;
|
||||
}
|
||||
|
||||
function syncMarkdownMenuUi() {
|
||||
const mdOn = isMarkdownRenderEnabled();
|
||||
document.querySelectorAll("[data-toggle-markdown]").forEach((btn) => {
|
||||
btn.classList.toggle("is-active", mdOn);
|
||||
btn.setAttribute("aria-checked", mdOn ? "true" : "false");
|
||||
});
|
||||
}
|
||||
|
||||
function syncThemeMenuUi() {
|
||||
const colorId = document.documentElement.getAttribute("data-color-theme") || getStoredColorTheme();
|
||||
const chromeId =
|
||||
@@ -584,6 +628,7 @@ function syncThemeMenuUi() {
|
||||
document.querySelectorAll("[data-present-chrome].more-theme-item").forEach((btn) => {
|
||||
btn.classList.toggle("is-active", btn.getAttribute("data-present-chrome") === chromeMeta.id);
|
||||
});
|
||||
syncMarkdownMenuUi();
|
||||
}
|
||||
|
||||
function stashComposerDraftFromDom() {
|
||||
@@ -652,7 +697,7 @@ function renderComposer(view, loading) {
|
||||
<button type="button" class="btn composer-btn-icon" data-act="retry_run" title="重roll" aria-label="重roll">🔄</button>`,
|
||||
},
|
||||
);
|
||||
root.innerHTML = `<form class="composer-form" id="composer-form">${shell}</form>`;
|
||||
root.innerHTML = composerFormHtml(shell);
|
||||
root.querySelector("#composer-form")?.addEventListener("submit", (e) => e.preventDefault());
|
||||
root.querySelector("[data-act=abort_run]")?.addEventListener("click", () => abortRun());
|
||||
root.querySelector("[data-act=retry_run]")?.addEventListener("click", () => retryRun());
|
||||
@@ -682,7 +727,7 @@ function renderComposer(view, loading) {
|
||||
root.innerHTML = `
|
||||
${intakePanel}
|
||||
${confirm}
|
||||
<form class="composer-form" id="composer-form">${shell}</form>`;
|
||||
${composerFormHtml(shell)}`;
|
||||
wireComposerForm();
|
||||
root.querySelector("[data-act=confirm_intake]")?.addEventListener("click", () => runAction("confirm_intake"));
|
||||
applyPendingComposerDraft();
|
||||
@@ -843,7 +888,7 @@ function renderComposer(view, loading) {
|
||||
textareaHtml: `<textarea id="composer-input" rows="1" placeholder="${esc(spec.placeholder)}"></textarea>`,
|
||||
trailing: `${saveProduct}${enterPlay}<button type="submit" class="${sendCls}" data-act="pick-replan" disabled title="写下意见后再发;点图上节点即确认并进入">${esc(spec.submitLabel || "发送")}</button>`,
|
||||
});
|
||||
root.innerHTML = `<form class="composer-form" id="composer-form">${shell}</form>`;
|
||||
root.innerHTML = composerFormHtml(shell);
|
||||
wireComposerForm({ requiresText: true });
|
||||
root.querySelector("[data-act=save-product]")?.addEventListener("click", () => {
|
||||
void saveCurrentInstance();
|
||||
@@ -866,14 +911,28 @@ function renderComposer(view, loading) {
|
||||
: spec.acceptAction.title || spec.acceptAction.label
|
||||
)}" ${spec.acceptAction.disabled ? "disabled" : ""}>${esc(spec.acceptAction.label)}</button>`
|
||||
: "";
|
||||
const clearDictate =
|
||||
view?.creationMode === "dictate" && !isPlayView(view)
|
||||
? `<button type="button" class="btn" data-act="clear-dictate" title="清空对话,保留产物">清空对话</button>`
|
||||
: "";
|
||||
const saveProduct = canOfferSaveProduct(view)
|
||||
? `<button type="button" class="btn btn-primary" data-act="save-product">保存定稿</button>`
|
||||
: "";
|
||||
const enterPlay = canOfferEnterPlay(view)
|
||||
? `<button type="button" class="btn${
|
||||
canOfferSaveProduct(view) ? "" : " btn-primary"
|
||||
}" data-act="enter-play">${
|
||||
view.hasProduct ? "用产物开玩" : "开玩"
|
||||
}</button>`
|
||||
: "";
|
||||
const submitLabel = spec.submitLabel || "发送";
|
||||
const sendIsPrimary = !acceptOnEmpty;
|
||||
const sendIsPrimary = !acceptOnEmpty && !saveProduct && !enterPlay;
|
||||
const placeholder = acceptOnEmpty
|
||||
? `${spec.placeholder || "修改意见…"}(${spec.emptyEnterHint || "空 Enter=确认"})`
|
||||
: spec.placeholder;
|
||||
const shell = composerInputShell(spec, {
|
||||
textareaHtml: `<textarea id="composer-input" rows="1" placeholder="${esc(placeholder)}"></textarea>`,
|
||||
trailing: `<button type="button" class="btn composer-btn${
|
||||
trailing: `${clearDictate}${saveProduct}${enterPlay}<button type="button" class="btn composer-btn${
|
||||
sendIsPrimary ? " btn-primary" : ""
|
||||
}" data-act="revise" title="${esc(
|
||||
acceptOnEmpty
|
||||
@@ -881,9 +940,18 @@ function renderComposer(view, loading) {
|
||||
: "Enter 发送"
|
||||
)}">${esc(submitLabel)}</button>${acceptBtn}`,
|
||||
});
|
||||
root.innerHTML = `<form class="composer-form" id="composer-form">${shell}</form>`;
|
||||
root.innerHTML = composerFormHtml(shell);
|
||||
wireComposerForm({ acceptOnEmpty });
|
||||
root.querySelector("[data-act=accept]")?.addEventListener("click", () => runAction("accept"));
|
||||
root.querySelector("[data-act=clear-dictate]")?.addEventListener("click", () => {
|
||||
void clearDictateDialogue();
|
||||
});
|
||||
root.querySelector("[data-act=save-product]")?.addEventListener("click", () => {
|
||||
void saveCurrentInstance();
|
||||
});
|
||||
root.querySelector("[data-act=enter-play]")?.addEventListener("click", () => {
|
||||
enterPlayNow();
|
||||
});
|
||||
applyPendingComposerDraft();
|
||||
}
|
||||
|
||||
@@ -1964,6 +2032,23 @@ async function abortRun() {
|
||||
}
|
||||
}
|
||||
|
||||
async function clearDictateDialogue() {
|
||||
if (!sessionId) return;
|
||||
if (!confirm("清空对话?产物会保留。")) return;
|
||||
const seq = beginUiRequest();
|
||||
try {
|
||||
const view = await api(
|
||||
`/api/sessions/${encodeURIComponent(sessionId)}/dictate/clear-dialogue`,
|
||||
{ method: "POST", body: "{}" },
|
||||
);
|
||||
if (isStaleUiRequest(seq)) return;
|
||||
renderSession(view, false);
|
||||
} catch (err) {
|
||||
if (isStaleUiRequest(seq)) return;
|
||||
alert(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function startLivePoll() {
|
||||
stopLivePoll();
|
||||
if (!sessionId) return;
|
||||
@@ -2350,38 +2435,90 @@ function openNewBookDialog() {
|
||||
async function populateDirectorSelect() {
|
||||
const sel = $("select-director");
|
||||
const desc = $("director-desc");
|
||||
const modeSel = $("select-creation-mode");
|
||||
const modeDesc = $("creation-mode-desc");
|
||||
const fieldDirector = $("field-director");
|
||||
let recipeDirectors = [];
|
||||
let dictateDirectors = [];
|
||||
|
||||
const fillOptions = (list) => {
|
||||
if (!sel) return;
|
||||
try {
|
||||
const data = await api("/api/directors");
|
||||
const directors = data.directors ?? [];
|
||||
sel.innerHTML = "";
|
||||
if (!directors.length) {
|
||||
if (!list.length) {
|
||||
sel.innerHTML = `<option value="">暂无配方</option>`;
|
||||
if (desc) {
|
||||
desc.hidden = false;
|
||||
desc.textContent = "尚未配置配方选项(recipes/catalog.yaml)。";
|
||||
}
|
||||
sel.required = false;
|
||||
return;
|
||||
}
|
||||
for (const d of directors) {
|
||||
for (const d of list) {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = d.id;
|
||||
opt.textContent = displaySkillPackLabel(d.id) || d.name || d.id;
|
||||
opt.textContent = d.name || d.id;
|
||||
if (d.declaration) opt.dataset.declaration = d.declaration;
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
const preferred =
|
||||
directors.find((d) => d.id === "world-simulator") ?? directors[0];
|
||||
sel.value = preferred.id;
|
||||
sel.value = list[0].id;
|
||||
sel.required = true;
|
||||
};
|
||||
|
||||
const syncDesc = () => {
|
||||
const cur = directors.find((d) => d.id === sel.value);
|
||||
if (desc) {
|
||||
if (!sel || !desc) return;
|
||||
if (!modeSel?.value) {
|
||||
desc.hidden = true;
|
||||
desc.textContent = "";
|
||||
return;
|
||||
}
|
||||
const list =
|
||||
modeSel.value === "dictate" ? dictateDirectors : recipeDirectors;
|
||||
const cur = list.find((d) => d.id === sel.value);
|
||||
const text = (cur?.declaration ?? "").trim();
|
||||
desc.hidden = !text;
|
||||
desc.textContent = text;
|
||||
}
|
||||
};
|
||||
sel.onchange = syncDesc;
|
||||
|
||||
const syncMode = () => {
|
||||
const mode = modeSel?.value?.trim() || "";
|
||||
if (!mode) {
|
||||
if (fieldDirector) fieldDirector.hidden = true;
|
||||
if (modeDesc) modeDesc.hidden = true;
|
||||
if (desc) desc.hidden = true;
|
||||
if (sel) {
|
||||
sel.innerHTML = `<option value="">请先选择进料方式</option>`;
|
||||
sel.required = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const dictate = mode === "dictate";
|
||||
if (fieldDirector) fieldDirector.hidden = false;
|
||||
fillOptions(dictate ? dictateDirectors : recipeDirectors);
|
||||
if (modeDesc) {
|
||||
modeDesc.hidden = false;
|
||||
modeDesc.textContent = dictate
|
||||
? "转述整理:直接对话写入产物;下方为转述专用配方。"
|
||||
: "节点流程:按配方预置起点走工作流计划;下方为节点流程配方。";
|
||||
}
|
||||
syncDesc();
|
||||
};
|
||||
|
||||
if (modeSel && !modeSel.dataset.bound) {
|
||||
modeSel.dataset.bound = "1";
|
||||
modeSel.addEventListener("change", syncMode);
|
||||
}
|
||||
if (sel && !sel.dataset.boundDesc) {
|
||||
sel.dataset.boundDesc = "1";
|
||||
sel.addEventListener("change", syncDesc);
|
||||
}
|
||||
if (!sel) return;
|
||||
try {
|
||||
const data = await api("/api/directors");
|
||||
recipeDirectors = data.recipeDirectors ?? data.directors ?? [];
|
||||
dictateDirectors = data.dictateDirectors ?? [];
|
||||
// 打开对话框时重置为「先选进料」
|
||||
if (modeSel) {
|
||||
modeSel.value = "";
|
||||
const placeholder = [...modeSel.options].find((o) => !o.value);
|
||||
if (placeholder) placeholder.selected = true;
|
||||
}
|
||||
syncMode();
|
||||
} catch (err) {
|
||||
sel.innerHTML = `<option value="">加载失败</option>`;
|
||||
if (desc) {
|
||||
@@ -2393,7 +2530,12 @@ async function populateDirectorSelect() {
|
||||
|
||||
async function createBook() {
|
||||
const title = $("input-book-title").value.trim() || "未命名作品";
|
||||
const creationMode = $("select-creation-mode")?.value?.trim() || "";
|
||||
const recipeId = $("select-director")?.value?.trim();
|
||||
if (creationMode !== "recipe" && creationMode !== "dictate") {
|
||||
alert("请先选择进料方式");
|
||||
return;
|
||||
}
|
||||
if (!recipeId) {
|
||||
alert("请选择配方");
|
||||
return;
|
||||
@@ -2407,6 +2549,7 @@ async function createBook() {
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
orchestratorId,
|
||||
creationMode,
|
||||
recipeId,
|
||||
}),
|
||||
});
|
||||
@@ -2493,7 +2636,11 @@ function defaultArchiveLabel() {
|
||||
|
||||
async function saveCurrentInstance() {
|
||||
if (!activeBookId || (!lastView?.playReady && !canOfferSaveProduct(lastView))) {
|
||||
return alert("须先完成收口或验收 Worker 集");
|
||||
return alert(
|
||||
lastView?.creationMode === "dictate"
|
||||
? "请先让 Agent 写入至少一项产物,再保存定稿"
|
||||
: "须先完成收口或验收 Worker 集",
|
||||
);
|
||||
}
|
||||
const label = prompt("落档名称", defaultArchiveLabel());
|
||||
if (!label?.trim()) return;
|
||||
@@ -2699,6 +2846,16 @@ $("theme-menu")?.addEventListener("click", (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
$("composer")?.addEventListener("click", (e) => {
|
||||
const menu = e.target.closest("#composer-more-menu");
|
||||
const mdBtn = e.target.closest("[data-toggle-markdown]");
|
||||
if (!mdBtn || !menu?.contains(mdBtn)) return;
|
||||
e.preventDefault();
|
||||
applyMarkdownRender(!isMarkdownRenderEnabled());
|
||||
syncMarkdownMenuUi();
|
||||
if (lastView && sessionId) renderSession(lastView, false);
|
||||
});
|
||||
|
||||
window.addEventListener("wa:session-updated", (e) => {
|
||||
const view = e.detail;
|
||||
if (!view?.id || isCatalogNav() || !sessionId) return;
|
||||
@@ -2719,6 +2876,7 @@ document.addEventListener("click", (e) => {
|
||||
async function init() {
|
||||
initColorTheme();
|
||||
initPresentChrome();
|
||||
initMarkdownRender();
|
||||
syncThemeMenuUi();
|
||||
try {
|
||||
void populateDirectorSelect();
|
||||
|
||||
+17
-8
@@ -160,21 +160,21 @@
|
||||
</div>
|
||||
<div id="questions-card-host" class="questions-card-host" hidden></div>
|
||||
</section>
|
||||
<aside id="coord-rail" class="coord-rail" hidden aria-label="此前对话">
|
||||
<aside id="coord-rail" class="coord-rail" hidden aria-label="侧栏">
|
||||
<button
|
||||
type="button"
|
||||
class="coord-rail-toggle"
|
||||
id="btn-coord-toggle"
|
||||
aria-expanded="false"
|
||||
title="展开 / 收起此前对话"
|
||||
title="展开 / 收起侧栏"
|
||||
>
|
||||
<span class="coord-rail-toggle-label">对话</span>
|
||||
<span class="coord-rail-toggle-label" id="coord-rail-toggle-label">对话</span>
|
||||
<span id="coord-drawer-count" class="coord-drawer-count"></span>
|
||||
</button>
|
||||
<div class="coord-rail-panel">
|
||||
<header class="coord-rail-head">
|
||||
<span class="coord-rail-title">此前对话</span>
|
||||
<button type="button" class="btn-sm coord-rail-collapse" id="btn-coord-collapse" title="收起" aria-label="收起此前对话">›</button>
|
||||
<span class="coord-rail-title" id="coord-rail-title">此前对话</span>
|
||||
<button type="button" class="btn-sm coord-rail-collapse" id="btn-coord-collapse" title="收起" aria-label="收起侧栏">›</button>
|
||||
</header>
|
||||
<div id="coord-drawer-body" class="coord-drawer-body"></div>
|
||||
</div>
|
||||
@@ -192,11 +192,20 @@
|
||||
<dialog id="dialog-new-book" class="dialog">
|
||||
<form method="dialog" id="form-new-book">
|
||||
<h2>新建作品</h2>
|
||||
<p class="dialog-desc">选择配方,再起名。配方是本局方法起点,之后按对话谈成工作流计划与运行规格(可调味)。</p>
|
||||
<p class="dialog-desc">先选进料方式,再选对应配方(两套目录互不共享)。</p>
|
||||
<label class="field">
|
||||
进料方式
|
||||
<select id="select-creation-mode" required>
|
||||
<option value="" selected disabled>请选择…</option>
|
||||
<option value="recipe">节点流程</option>
|
||||
<option value="dictate">转述整理(对话直填)</option>
|
||||
</select>
|
||||
</label>
|
||||
<p class="dialog-desc" id="creation-mode-desc" hidden></p>
|
||||
<label class="field" id="field-director" hidden>
|
||||
配方
|
||||
<select id="select-director" required>
|
||||
<option value="">加载中…</option>
|
||||
<select id="select-director">
|
||||
<option value="">请先选择进料方式</option>
|
||||
</select>
|
||||
</label>
|
||||
<p class="dialog-desc" id="director-desc" hidden></p>
|
||||
|
||||
+411
-59
@@ -1,7 +1,7 @@
|
||||
/* Functional layout â agent-first, no production-line chrome */
|
||||
/* Functional layout â agent-first, no production-line chrome */
|
||||
|
||||
:root {
|
||||
/* Default = modern;实际以色主题 data-color-theme 为准 */
|
||||
/* Default = modernï¼å®é
以è²ä¸»é¢ data-color-theme 为å */
|
||||
--bg: #f8f8f8;
|
||||
--surface: #fff;
|
||||
--border: #e0e0e0;
|
||||
@@ -29,7 +29,7 @@
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* 仿纸暖黄(护眼)*/
|
||||
/* 仿纸æé»ï¼æ¤ç¼ï¼*/
|
||||
html[data-color-theme="paper"] {
|
||||
--bg: #f5ecd7;
|
||||
--surface: #fbf8f2;
|
||||
@@ -41,7 +41,7 @@ html[data-color-theme="paper"] {
|
||||
--shadow: 0 8px 24px rgba(62, 58, 53, 0.1);
|
||||
}
|
||||
|
||||
/* 现代清爽 */
|
||||
/* ç°ä»£æ¸
ç½ */
|
||||
html[data-color-theme="modern"] {
|
||||
--bg: #f8f8f8;
|
||||
--surface: #fff;
|
||||
@@ -53,7 +53,7 @@ html[data-color-theme="modern"] {
|
||||
--shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 夜间暗色 */
|
||||
/* å¤é´æè² */
|
||||
html[data-color-theme="dark"] {
|
||||
--bg: #1e1e1e;
|
||||
--surface: #2d2d30;
|
||||
@@ -65,7 +65,7 @@ html[data-color-theme="dark"] {
|
||||
--shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
/* 豆沙绿 */
|
||||
/* è±æ²ç»¿ */
|
||||
html[data-color-theme="green"] {
|
||||
--bg: #dce5d9;
|
||||
--surface: #f4f9f2;
|
||||
@@ -82,7 +82,7 @@ html {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* å¼åä½å缩è¿å·¦ä¾§æ */
|
||||
/* å¼ÂÃ¥ÂÂä½ÂÃ¥ÂÂ缩è¿Â左侧栠*/
|
||||
body.rail-collapsed {
|
||||
--books-w: var(--books-w-collapsed);
|
||||
}
|
||||
@@ -91,7 +91,7 @@ body.rail-collapsed {
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden; /* æµè§å¨å±æ°¸ä¸åºç°é¡µé¢æ»å¨æ¡ */
|
||||
overflow: hidden; /* æµÂè§Âå¨å±Âæ°¸ä¸Âåºç°页颿»Âå¨æÂ¡ */
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
@@ -311,8 +311,8 @@ body[data-nav-level="root"] .burst-badge { display: none; }
|
||||
.rail-tab-panel[hidden] { display: none !important; }
|
||||
|
||||
body.rail-collapsed .panel-rail { align-items: stretch; }
|
||||
/* composer æå
容èªéåºï¼ä¸é´åºåæå©ä½é«åº¦ï¼æ´é¡µéå¨è§å£å
*/
|
||||
/* panel-main:上=悬停遮盖 chrome;下=工作区(左中右在 main-body / head 内) */
|
||||
/* composer æÂÂÃ¥ÂÂ
容èªéÂÂåºÂï¼Âä¸Âé´åºåÂÂæÂÂå©ä½Âé«Â度ï¼ÂæÂ´é¡µéÂÂå¨è§Âå£åÂÂ
*/
|
||||
/* panel-mainï¼ä¸=æ¬åé®ç chromeï¼ä¸=å·¥ä½åºï¼å·¦ä¸å³å¨ main-body / head å
ï¼ */
|
||||
.panel-main {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr);
|
||||
@@ -332,7 +332,7 @@ body.rail-collapsed .panel-rail { align-items: stretch; }
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 顶缘热区 + 遮盖条:不占文档流,悬停/聚焦才展开 */
|
||||
/* é¡¶ç¼çåº + é®çæ¡ï¼ä¸å ææ¡£æµï¼æ¬å/èç¦æå±å¼ */
|
||||
.main-chrome {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -425,7 +425,7 @@ body.rail-collapsed .panel-rail { align-items: stretch; }
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
/* 触控无悬停:顶缘仍可点开,聚焦后保持 */
|
||||
/* è§¦æ§æ æ¬åï¼é¡¶ç¼ä»å¯ç¹å¼ï¼èç¦åä¿æ */
|
||||
.main-chrome {
|
||||
height: 12px;
|
||||
}
|
||||
@@ -453,7 +453,7 @@ body.design-workspace.coord-rail-collapsed .main-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 验收态:协调流收窄,产物占主工作面 */
|
||||
/* éªæ¶æï¼åè°æµæ¶çªï¼äº§ç©å 主工ä½é¢ */
|
||||
.workspace-stage {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
@@ -546,7 +546,7 @@ body.design-workspace.coord-rail-collapsed .main-body {
|
||||
}
|
||||
.workspace-raw-body { margin-top: 8px; }
|
||||
|
||||
/* 创作伪 0 层:右侧协调栏(横向折叠,不占主柱高度) */
|
||||
/* åä½ä¼ª 0 å±ï¼å³ä¾§åè°æ ï¼æ¨ªåæå ï¼ä¸å 主æ±é«åº¦ï¼ */
|
||||
.coord-rail {
|
||||
display: none;
|
||||
min-width: 0;
|
||||
@@ -560,6 +560,9 @@ body.design-workspace .coord-rail:not([hidden]) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.coord-rail-toggle {
|
||||
flex: 0 0 var(--coord-w-collapsed, 40px);
|
||||
@@ -646,8 +649,10 @@ body:not(.coord-rail-collapsed) .coord-rail-toggle {
|
||||
}
|
||||
.coord-drawer-body {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -895,7 +900,7 @@ body.is-reviewing .msg-bubble {
|
||||
max-width: 92%;
|
||||
}
|
||||
|
||||
/* 创作伪 0 层:产物铺满主柱,对话退居右侧栏 */
|
||||
/* åä½ä¼ª 0 å±ï¼äº§ç©éºæ»¡ä¸»æ±ï¼å¯¹è¯éå±
å³ä¾§æ */
|
||||
body.design-workspace .message-feed {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -909,7 +914,7 @@ body.design-workspace .workspace-stage {
|
||||
min-height: 0;
|
||||
}
|
||||
body.design-workspace[data-design-surface="answer"] .workspace-stage {
|
||||
overflow: hidden; /* 滚动只在询问卡内,避免 stage↔card 双滚 */
|
||||
overflow: hidden; /* æ»å¨åªå¨è¯¢é®å¡å
ï¼é¿å
stageâcard åæ» */
|
||||
}
|
||||
body.design-workspace .workspace-review {
|
||||
max-width: none;
|
||||
@@ -1075,7 +1080,7 @@ body.design-workspace[data-design-surface="answer"] .questions-card-host {
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
/* 答题/验收工作面已是 surface,询问不再套圆角卡片 */
|
||||
/* çé¢/éªæ¶å·¥ä½é¢å·²æ¯ surfaceï¼è¯¢é®ä¸åå¥åè§å¡ç */
|
||||
body.design-workspace[data-design-surface="answer"] .questions-card-host.is-open:not([hidden]),
|
||||
.workspace-review-ask .questions-card-host.is-open:not([hidden]) {
|
||||
margin: 0;
|
||||
@@ -1102,6 +1107,46 @@ body.design-workspace[data-design-surface="answer"] .qcard-pager,
|
||||
.workspace-review-ask .qcard-pager {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* 转述:主柱对话;stage 一行条;右侧已持久化(栏内上下滚、正文换行) */
|
||||
body.design-workspace[data-design-surface="dictate"] .message-feed {
|
||||
display: flex !important;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
body.design-workspace[data-design-surface="dictate"] .workspace-stage {
|
||||
order: -1;
|
||||
flex: 0 0 auto;
|
||||
overflow: visible;
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
|
||||
border-top: none;
|
||||
}
|
||||
body.design-workspace[data-design-surface="dictate"] {
|
||||
--coord-w: clamp(300px, 28vw, 380px);
|
||||
}
|
||||
body.design-workspace[data-design-surface="dictate"] .panel-feed {
|
||||
overflow: hidden;
|
||||
}
|
||||
.dictate-stage-bar {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 10px;
|
||||
padding: 8px var(--workspace-pad-x, 24px);
|
||||
margin: 0;
|
||||
}
|
||||
.dictate-stage-bar .workspace-surface-kicker {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.dictate-stage-recipe {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
body.design-workspace[data-design-surface="dictate"] .workspace-surface-kicker {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
body.design-workspace[data-design-surface="speak"] .workspace-surface-kicker {
|
||||
color: var(--accent);
|
||||
}
|
||||
@@ -1116,7 +1161,7 @@ body.design-workspace[data-design-surface="review"][data-review-kind="opening"]
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* 挂载追问嵌在产物验收面下方:与产物同宽,随主柱动态适应 */
|
||||
/* æè½½è¿½é®åµå¨äº§ç©éªæ¶é¢ä¸æ¹ï¼ä¸äº§ç©å宽ï¼é主æ±å¨æéåº */
|
||||
.workspace-review-ask {
|
||||
flex: 0 0 auto;
|
||||
margin-top: 0;
|
||||
@@ -1878,7 +1923,7 @@ body.design-workspace .flow-step[data-run="done"] .flow-name {
|
||||
.panel-head-actions { display: flex; gap: 4px; align-items: center; }
|
||||
.btn-sm.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
/* Books — breadcrumb + list */
|
||||
/* Books â breadcrumb + list */
|
||||
.path-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -2126,7 +2171,7 @@ body.design-workspace .flow-step[data-run="done"] .flow-name {
|
||||
}
|
||||
.sidebar-empty { padding: 12px; color: var(--muted); font-size: 13px; text-align: center; }
|
||||
|
||||
/* Skill picker â primary action when starting */
|
||||
/* Skill picker â primary action when starting */
|
||||
.skill-picker {
|
||||
padding: 16px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
@@ -2144,7 +2189,7 @@ body.design-workspace .flow-step[data-run="done"] .flow-name {
|
||||
.skill-card-desc { font-size: 12px; color: var(--muted); line-height: 1.4; }
|
||||
.skill-card-tag { font-size: 11px; color: var(--accent); margin-top: 6px; }
|
||||
|
||||
/* Feed â SillyTavern å¼å¯¹è¯æ°æ³¡ */
|
||||
/* Feed â SillyTavern å¼Â对è¯Âæ°Â泡 */
|
||||
.message-feed {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
@@ -2356,11 +2401,11 @@ body.rail-collapsed .message-feed {
|
||||
}
|
||||
.msg-play-process > summary::-webkit-details-marker { display: none; }
|
||||
.msg-play-process > summary::before {
|
||||
content: "▸";
|
||||
content: "â¸";
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.msg-play-process[open] > summary::before { content: "▾"; }
|
||||
.msg-play-process[open] > summary::before { content: "â¾"; }
|
||||
.msg-play-process .msg-tag {
|
||||
font-weight: 600;
|
||||
color: var(--muted);
|
||||
@@ -2492,7 +2537,7 @@ body.rail-collapsed .message-feed {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
/* 主对话验收卡(旧):保留选择器以免历史类名失效 */
|
||||
/* 主对è¯éªæ¶å¡ï¼æ§ï¼ï¼ä¿çéæ©å¨ä»¥å
åå²ç±»å失æ */
|
||||
.msg-review {
|
||||
align-self: stretch;
|
||||
width: 100%;
|
||||
@@ -2529,7 +2574,7 @@ body.rail-collapsed .message-feed {
|
||||
.msg-review .ws-focus-hint { margin-bottom: 0; font-size: 11px; }
|
||||
.msg-review .review-worker-set { margin: 0 0 6px; }
|
||||
|
||||
/* 顶栏主题菜单:色主题 + 选壳 */
|
||||
/* é¡¶æ 主é¢èåï¼è²ä¸»é¢ + é壳 */
|
||||
.more-menu {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@@ -2628,6 +2673,119 @@ body.rail-collapsed .message-feed {
|
||||
background: var(--accent-soft);
|
||||
color: var(--accent);
|
||||
}
|
||||
.more-toggle-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.more-toggle-item .more-theme-copy {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
.more-toggle-mark {
|
||||
flex: 0 0 auto;
|
||||
width: 1.1em;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.more-toggle-mark::before {
|
||||
content: "";
|
||||
}
|
||||
.more-toggle-item.is-active {
|
||||
background: var(--accent-soft);
|
||||
color: var(--accent);
|
||||
}
|
||||
.more-toggle-item.is-active .more-toggle-mark::before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Markdown body (optional render) */
|
||||
.msg-body .md-p,
|
||||
.dictate-product-body .md-p,
|
||||
.present-region-body .md-p {
|
||||
margin: 0 0 0.55em;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.msg-body .md-p:last-child,
|
||||
.dictate-product-body .md-p:last-child,
|
||||
.present-region-body .md-p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.msg-body .md-h,
|
||||
.dictate-product-body .md-h,
|
||||
.present-region-body .md-h {
|
||||
margin: 0.7em 0 0.35em;
|
||||
font-weight: 650;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.msg-body .md-h:first-child,
|
||||
.dictate-product-body .md-h:first-child,
|
||||
.present-region-body .md-h:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.msg-body h1.md-h { font-size: 1.25em; }
|
||||
.msg-body h2.md-h { font-size: 1.15em; }
|
||||
.msg-body h3.md-h,
|
||||
.msg-body h4.md-h,
|
||||
.msg-body h5.md-h,
|
||||
.msg-body h6.md-h { font-size: 1.05em; }
|
||||
.msg-body .md-ul,
|
||||
.msg-body .md-ol,
|
||||
.dictate-product-body .md-ul,
|
||||
.dictate-product-body .md-ol,
|
||||
.present-region-body .md-ul,
|
||||
.present-region-body .md-ol {
|
||||
margin: 0.35em 0 0.55em;
|
||||
padding-left: 1.35em;
|
||||
}
|
||||
.msg-body .md-quote,
|
||||
.dictate-product-body .md-quote,
|
||||
.present-region-body .md-quote {
|
||||
margin: 0.45em 0;
|
||||
padding: 0.15em 0 0.15em 0.75em;
|
||||
border-left: 3px solid color-mix(in srgb, var(--accent) 45%, var(--border));
|
||||
color: var(--muted);
|
||||
}
|
||||
.msg-body .md-pre,
|
||||
.dictate-product-body .md-pre,
|
||||
.present-region-body .md-pre {
|
||||
margin: 0.45em 0;
|
||||
padding: 8px 10px;
|
||||
overflow-x: auto;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border);
|
||||
background: color-mix(in srgb, var(--bg) 80%, var(--surface));
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.msg-body .md-code,
|
||||
.dictate-product-body .md-code,
|
||||
.present-region-body .md-code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 0.92em;
|
||||
padding: 0.05em 0.35em;
|
||||
border-radius: 4px;
|
||||
background: color-mix(in srgb, var(--bg) 70%, var(--surface));
|
||||
}
|
||||
.msg-body .md-a,
|
||||
.dictate-product-body .md-a,
|
||||
.present-region-body .md-a {
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.msg-body .md-hr,
|
||||
.dictate-product-body .md-hr,
|
||||
.present-region-body .md-hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border);
|
||||
margin: 0.75em 0;
|
||||
}
|
||||
|
||||
.more-theme-icon {
|
||||
flex: 0 0 auto;
|
||||
width: 1.25em;
|
||||
@@ -2656,7 +2814,7 @@ body.rail-collapsed .message-feed {
|
||||
color: color-mix(in srgb, var(--accent) 70%, var(--muted));
|
||||
}
|
||||
|
||||
/* 提问索引气泡:决策在下方询问卡 */
|
||||
/* æé®ç´¢å¼æ°æ³¡ï¼å³çå¨ä¸æ¹è¯¢é®å¡ */
|
||||
.msg-bubble-index {
|
||||
width: auto;
|
||||
max-width: 70%;
|
||||
@@ -2680,7 +2838,7 @@ body.rail-collapsed .message-feed {
|
||||
.msg-q-list li { margin: 0.35rem 0; }
|
||||
.msg-q-lead { margin: 0; line-height: 1.55; font-size: 14px; }
|
||||
|
||||
/* 游玩:终稿铺满阅读区;字号跟正文阅读走,不跟创作验收的大字稿走 */
|
||||
/* 游ç©ï¼ç»ç¨¿éºæ»¡é
读åºï¼åå·è·æ£æé
读走ï¼ä¸è·åä½éªæ¶ç大å稿走 */
|
||||
body[data-lifecycle="play"] .message-feed {
|
||||
padding: 10px 12px 16px;
|
||||
gap: 10px;
|
||||
@@ -2741,7 +2899,7 @@ body[data-lifecycle="play"] .msg-play-final .present-shell--chat_monitor .presen
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 产物紧凑卡:横向主轴,预览一行 */
|
||||
/* 产ç©ç´§åå¡ï¼æ¨ªå主轴ï¼é¢è§ä¸è¡ */
|
||||
.artifact-compact-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -2754,7 +2912,7 @@ body[data-lifecycle="play"] .msg-play-final .present-shell--chat_monitor .presen
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 验收扁平:一条 meta,正文直接读,不套 details/预览摘要 */
|
||||
/* éªæ¶æå¹³ï¼ä¸æ¡ metaï¼æ£æç´æ¥è¯»ï¼ä¸å¥ details/é¢è§æè¦ */
|
||||
.artifact-flat-review {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -2845,8 +3003,8 @@ body.design-workspace .artifact-flat-review {
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
.artifact-compact-toggle::before { content: "å±å¼"; }
|
||||
.artifact-compact[open] .artifact-compact-toggle::before { content: "æ¶èµ·"; }
|
||||
.artifact-compact-toggle::before { content: "å±Âå¼Â"; }
|
||||
.artifact-compact[open] .artifact-compact-toggle::before { content: "æÂ¶èµ·"; }
|
||||
.artifact-compact-preview {
|
||||
margin: 0;
|
||||
font-family: var(--font-read);
|
||||
@@ -2902,7 +3060,7 @@ body.design-workspace .artifact-flat-review {
|
||||
}
|
||||
.ws-focus-body .artifact-compact-list { margin: 0; }
|
||||
|
||||
/* 展开区:mosaic / 瓷砖网格 */
|
||||
/* å±å¼åºï¼mosaic / ç·ç ç½æ ¼ */
|
||||
.af-mosaic {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -2914,7 +3072,7 @@ body.design-workspace .af-mosaic {
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
|
||||
}
|
||||
|
||||
/* 美学验收:左契约 / 右诊断 */
|
||||
/* ç¾å¦éªæ¶ï¼å·¦å¥çº¦ / å³è¯æ */
|
||||
.af-split {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -2997,7 +3155,7 @@ body.design-workspace .af-mosaic {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 美学卡:阅读层级 — 内核最大,范式次之,右栏更密更沉 */
|
||||
/* ç¾å¦å¡ï¼é
读å±çº§ â å
æ ¸æå¤§ï¼è弿¬¡ä¹ï¼å³æ æ´å¯æ´æ² */
|
||||
.af-split--aesthetics .af-split-product {
|
||||
gap: 22px;
|
||||
}
|
||||
@@ -3084,7 +3242,7 @@ body.design-workspace .af-mosaic {
|
||||
}
|
||||
}
|
||||
|
||||
/* 旧布局类名保留,避免残留引用崩样式 */
|
||||
/* æ§å¸å±ç±»åä¿çï¼é¿å
æ®çå¼ç¨å´©æ ·å¼ */
|
||||
.af-review-stack,
|
||||
.af-review-layout {
|
||||
display: flex;
|
||||
@@ -3355,7 +3513,7 @@ body.design-workspace .af-mosaic {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 行内完备度 / 评分 */
|
||||
/* è¡å
å®å¤åº¦ / è¯å */
|
||||
.pct-inline {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
@@ -3386,14 +3544,14 @@ body.design-workspace .af-mosaic {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
/* æè½ä¸ç¨æ£æå¡ */
|
||||
/* æÂÂè½ä¸Âç¨æÂ£æÂÂå¡ */
|
||||
.skill-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
/* 美学纲领:主栏契约 / 辅栏诊断(无第二层盒子) */
|
||||
/* ç¾å¦çº²é¢ï¼ä¸»æ å¥çº¦ / è¾
æ è¯æï¼æ 第äºå±çåï¼ */
|
||||
.skill-view.skill-view-aesthetics {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.55fr) minmax(15.5rem, 0.88fr);
|
||||
@@ -4061,7 +4219,7 @@ body.design-workspace .af-mosaic {
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent, #2a6) 20%, transparent);
|
||||
}
|
||||
|
||||
/* 询问卡:对话流里 host 即卡片;创作工作面上剥壳,见上方 flatten 规则 */
|
||||
/* 询é®å¡ï¼å¯¹è¯æµé host å³å¡çï¼åä½å·¥ä½é¢ä¸å¥å£³ï¼è§ä¸æ¹ flatten è§å */
|
||||
.questions-card-host {
|
||||
--qcard-max: 48vh;
|
||||
flex: 0 1 auto;
|
||||
@@ -4145,7 +4303,7 @@ body.design-workspace .af-mosaic {
|
||||
.questions-card-host.is-collapsed .qcard-float {
|
||||
display: none;
|
||||
}
|
||||
/* 悬浮控件层:不占文档流高度 */
|
||||
/* æ¬æµ®æ§ä»¶å±ï¼ä¸å ææ¡£æµé«åº¦ */
|
||||
.qcard-float {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -4331,7 +4489,7 @@ body.design-workspace .af-mosaic {
|
||||
}
|
||||
.ws-slot-chip.ws-slot-on { background: var(--accent-soft); border-color: transparent; }
|
||||
.ws-slot-chip.ws-slot-off { opacity: 0.55; text-decoration: line-through; }
|
||||
/* 产ç©ç»æåå±ç¤º â å¯¹é½ qcard / flow-step / ws-badge */
|
||||
/* 产ç©ç»ÂæÂÂÃ¥ÂÂå±Â示 â 对齠qcard / flow-step / ws-badge */
|
||||
.artifact-friendly { display: flex; flex-direction: column; gap: 10px; }
|
||||
.artifact-list { margin: 0; padding-left: 18px; line-height: 1.5; }
|
||||
.artifact-hero {
|
||||
@@ -4431,7 +4589,7 @@ body.design-workspace .af-mosaic {
|
||||
.artifact-kv-row.complex .artifact-kv-key { margin-bottom: 2px; }
|
||||
.artifact-kv-val { min-width: 0; font-size: 13px; line-height: 1.45; }
|
||||
|
||||
/* 自适应定义行:够宽并排,不够整组折行——同行规则,不按字数抽签 */
|
||||
/* èªéåºå®ä¹è¡ï¼å¤å®½å¹¶æï¼ä¸å¤æ´ç»æè¡ââåè¡è§åï¼ä¸æåæ°æ½ç¾ */
|
||||
.af-def-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -4488,7 +4646,7 @@ body.design-workspace .af-mosaic {
|
||||
flex-basis: 14rem;
|
||||
}
|
||||
|
||||
/* ç¾åæ¯è¿åº¦æ¡ */
|
||||
/* ç¾åÂÂæ¯Âè¿Â度æÂ¡ */
|
||||
.pct-meter {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -4626,7 +4784,7 @@ body.design-workspace .af-mosaic {
|
||||
.artifact-raw > summary:hover { color: var(--text); }
|
||||
.artifact-raw .json-pretty { margin-top: 6px; max-height: min(40vh, 360px); }
|
||||
|
||||
/* 指针 tag / 扁平面包屑:一行路径 + 不起眼原文 */
|
||||
/* æé tag / æå¹³é¢å
å±ï¼ä¸è¡è·¯å¾ + ä¸èµ·ç¼åæ */
|
||||
.artifact-crumb {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -4895,7 +5053,7 @@ body.design-workspace .af-mosaic {
|
||||
.timeline-item { padding: 6px 0; border-bottom: 1px solid var(--border); }
|
||||
.timeline-empty { color: var(--muted); }
|
||||
|
||||
/* Composer — emoji 更多在左 / 输入 / 发送;菜单向上弹出不被裁切 */
|
||||
/* Composer — 左汉堡 / 输入 / 发送;菜单向上弹出不被裁切 */
|
||||
.composer {
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 6px var(--workspace-pad-x, 16px) 8px;
|
||||
@@ -4910,6 +5068,9 @@ body.design-workspace .af-mosaic {
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
.composer:has(.composer-more-menu[open]) {
|
||||
z-index: 120;
|
||||
}
|
||||
.composer > .status {
|
||||
flex: 0 0 auto;
|
||||
align-self: center;
|
||||
@@ -4924,9 +5085,16 @@ body.design-workspace .af-mosaic {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
max-height: min(50vh, 420px);
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
/* 唯一描边:输入 + 操作同框 */
|
||||
#composer-main:has(.composer-more-menu[open]) {
|
||||
overflow: visible;
|
||||
}
|
||||
.main-stack:has(.composer-more-menu[open]) {
|
||||
overflow: visible;
|
||||
}
|
||||
/* å¯ä¸æè¾¹ï¼è¾å
¥ + æä½åæ¡ */
|
||||
.composer-input-shell {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
@@ -5043,14 +5211,48 @@ body.design-workspace .af-mosaic {
|
||||
.composer-hint { margin: 0 0 8px; font-size: 12px; color: var(--muted); }
|
||||
.composer-form {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
gap: 8px;
|
||||
align-items: flex-end;
|
||||
min-height: 0;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.composer-form .composer-input-shell {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.composer-more-menu {
|
||||
align-self: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.composer-more-menu[open] {
|
||||
z-index: 130;
|
||||
}
|
||||
.composer-more-menu .more-menu-sum {
|
||||
height: var(--composer-control-h);
|
||||
min-height: var(--composer-control-h);
|
||||
min-width: var(--composer-control-h);
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.composer-more-menu .more-menu-sum:hover {
|
||||
color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
.composer-more-menu .more-menu-panel {
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: auto;
|
||||
bottom: calc(100% + 6px);
|
||||
min-width: 220px;
|
||||
z-index: 140;
|
||||
}
|
||||
.composer-shell-actions > .btn,
|
||||
.composer-shell-actions > .btn-primary,
|
||||
@@ -5080,7 +5282,7 @@ body.design-workspace .af-mosaic {
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
/* 验收态:主按钮承接原「批阅」语义 */
|
||||
/* éªæ¶æï¼ä¸»æé®æ¿æ¥åãæ¹é
ãè¯ä¹ */
|
||||
.composer-btn-review {
|
||||
background: #15803d;
|
||||
border-color: #15803d;
|
||||
@@ -5163,9 +5365,9 @@ body.design-workspace .af-mosaic {
|
||||
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
|
||||
.dialog-head-row { display: flex; justify-content: space-between; align-items: center; }
|
||||
|
||||
/* —— 游玩呈现壳 present.v1 ——
|
||||
* 主工作面 = body(随 1000~2000 字撑高)。
|
||||
* 视觉:少盒子、少渐变;层级靠字号/间距/对比,不靠装饰抢注意力。
|
||||
/* ââ æ¸¸ç©åç°å£³ present.v1 ââ
|
||||
* 主工ä½é¢ = bodyï¼é 1000ï½2000 åæé«ï¼ã
|
||||
* è§è§ï¼å°çåãå°æ¸åï¼å±çº§é åå·/é´è·/对æ¯ï¼ä¸é è£
é¥°æ¢æ³¨æåã
|
||||
*/
|
||||
.present-shell {
|
||||
white-space: normal;
|
||||
@@ -5235,7 +5437,7 @@ body.design-workspace .af-mosaic {
|
||||
.present-region-body > p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/* P0:正文舞台 —— 随字数伸展(1000~2000 靠外层滚动,不塞进小框) */
|
||||
/* P0ï¼æ£æèå° ââ é忰伏å±ï¼1000ï½2000 é å¤å±æ»å¨ï¼ä¸å¡è¿å°æ¡ï¼ */
|
||||
.present-stage {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
@@ -5264,7 +5466,7 @@ body.design-workspace .af-mosaic {
|
||||
line-height: 1.7;
|
||||
max-width: none;
|
||||
}
|
||||
/* 双栏:侧栏钉住,正文再长也能对照 */
|
||||
/* åæ ï¼ä¾§æ éä½ï¼æ£æåé¿ä¹è½å¯¹ç
§ */
|
||||
.present-board-side,
|
||||
.present-split-side,
|
||||
.present-reader-aside {
|
||||
@@ -5274,7 +5476,7 @@ body.design-workspace .af-mosaic {
|
||||
max-height: calc(100dvh - 3rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
/* P2:监控芯片 */
|
||||
/* P2ï¼çæ§è¯ç */
|
||||
.present-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -5316,7 +5518,7 @@ body.design-workspace .af-mosaic {
|
||||
letter-spacing: 0.01em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
/* P1:行动 */
|
||||
/* P1ï¼è¡å¨ */
|
||||
.present-action-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -5340,7 +5542,7 @@ body.design-workspace .af-mosaic {
|
||||
line-height: 1.45;
|
||||
font-size: 13px;
|
||||
}
|
||||
/* —— 各壳布局(结构差在同时可见关系;不靠渐变区分) —— */
|
||||
/* ââ å壳å¸å±ï¼ç»æå·®å¨åæ¶å¯è§å
³ç³»ï¼ä¸é æ¸ååºåï¼ ââ */
|
||||
.present-shell--chat_monitor {
|
||||
--present-accent: #0369a1;
|
||||
}
|
||||
@@ -5582,3 +5784,153 @@ body.design-workspace .af-mosaic {
|
||||
min-width: 4.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* תÊöÕûÀí£ºÒѳ־û¯²úÎïչʾ */
|
||||
.dictate-products {
|
||||
margin-top: 14px;
|
||||
border: 1px solid var(--border, #d8d4cc);
|
||||
background: var(--surface-2, #f7f5f1);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
.dictate-products-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.dictate-products-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted, #6b6560);
|
||||
}
|
||||
.dictate-products-count {
|
||||
font-size: 12px;
|
||||
color: var(--muted, #6b6560);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.dictate-products-empty {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: var(--muted, #6b6560);
|
||||
line-height: 1.45;
|
||||
}
|
||||
.dictate-products-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.dictate-product {
|
||||
border: 1px solid var(--border, #e2ddd4);
|
||||
background: var(--surface, #fff);
|
||||
}
|
||||
.dictate-product > summary {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(7rem, 11rem) 1fr;
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
.dictate-product > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.dictate-product-tag {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--fg, #1c1917);
|
||||
word-break: break-all;
|
||||
}
|
||||
.dictate-product-preview {
|
||||
font-size: 12px;
|
||||
color: var(--muted, #6b6560);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
.dictate-product-body {
|
||||
margin: 0;
|
||||
padding: 0 10px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
max-height: 240px;
|
||||
overflow: auto;
|
||||
color: var(--fg, #1c1917);
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* 转述:右侧栏产物列表 — 只上下滚,长文换行不横滑 */
|
||||
.dictate-product--rail {
|
||||
border: 1px solid var(--border, #e2ddd4);
|
||||
background: var(--surface, #fff);
|
||||
margin-bottom: 6px;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dictate-product--rail > summary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
min-width: 0;
|
||||
}
|
||||
.dictate-product--rail > summary::-webkit-details-marker { display: none; }
|
||||
.dictate-product--rail .dictate-product-tag {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
word-break: break-all;
|
||||
}
|
||||
.dictate-product--rail .dictate-product-preview {
|
||||
font-size: 12px;
|
||||
color: var(--muted, #6b6560);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
.dictate-product--rail .dictate-product-body {
|
||||
margin: 0;
|
||||
padding: 0 10px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
font-family: inherit;
|
||||
color: var(--fg, #1c1917);
|
||||
}
|
||||
.dictate-products-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
body[data-coord-rail-mode="products"] .coord-drawer-body {
|
||||
padding: 8px 10px 12px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
body[data-coord-rail-mode="products"] .coord-rail,
|
||||
body[data-coord-rail-mode="products"] .coord-rail-panel {
|
||||
min-width: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user