Revert "feat(desktop): 底部抽屉可拖拽调高/最大化 + 输出渲染 Markdown"
This reverts commit 429b04d64a.
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { ChevronDown, ChevronUp, Wrench, ShieldCheck, Check, X, Maximize2, Minimize2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { ChevronDown, ChevronUp, Wrench, ShieldCheck, Check, X } from "lucide-react";
|
||||
import { deriveNodes, pendingApproval, type RunState } from "../lib/run";
|
||||
import { ExecTrace } from "../components/ExecTrace";
|
||||
import { ChartView } from "../components/ChartView";
|
||||
import { Markdown } from "../components/Markdown";
|
||||
import { extractChartBlocks, hasChart } from "../lib/chartspec";
|
||||
import { approveTask } from "../lib/api";
|
||||
import { Tabs, Badge, cn, type TabDef } from "../ui";
|
||||
@@ -14,35 +13,6 @@ type Tab = "output" | "trace" | "tools" | "cite" | "eval";
|
||||
export function BottomDrawer({ run }: { run: RunState }) {
|
||||
const [open, setOpen] = useState(true);
|
||||
const [tab, setTab] = useState<Tab>("output");
|
||||
const [height, setHeight] = useState(240); // 可拖拽调节的抽屉高度
|
||||
const prevH = useRef(240);
|
||||
|
||||
// 拖拽顶边调高:监听 window,高度 = 视口高 - 鼠标 Y,夹在 [140, 85vh]。
|
||||
const startResize = useCallback(() => {
|
||||
const onMove = (e: MouseEvent) => {
|
||||
const h = Math.min(window.innerHeight * 0.85, Math.max(140, window.innerHeight - e.clientY));
|
||||
setOpen(true);
|
||||
setHeight(h);
|
||||
};
|
||||
const onUp = () => {
|
||||
window.removeEventListener("mousemove", onMove);
|
||||
window.removeEventListener("mouseup", onUp);
|
||||
document.body.style.userSelect = "";
|
||||
};
|
||||
document.body.style.userSelect = "none";
|
||||
window.addEventListener("mousemove", onMove);
|
||||
window.addEventListener("mouseup", onUp);
|
||||
}, []);
|
||||
|
||||
const maximized = height >= window.innerHeight * 0.8;
|
||||
const toggleMax = () => {
|
||||
if (maximized) setHeight(prevH.current || 240);
|
||||
else {
|
||||
prevH.current = height;
|
||||
setHeight(Math.round(window.innerHeight * 0.82));
|
||||
}
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const nodes = deriveNodes(run.exec);
|
||||
const toolCount = nodes.filter((n) => n.kind === "tool").length;
|
||||
@@ -68,8 +38,6 @@ export function BottomDrawer({ run }: { run: RunState }) {
|
||||
return (
|
||||
<div className="shrink-0 border-t border-line bg-ink-900">
|
||||
{approval && run.taskId && <ApprovalBar taskId={run.taskId} node={approval.node} title={approval.title} summary={approval.summary} />}
|
||||
{/* 拖拽调高手柄(横跨顶边) */}
|
||||
{open && <div onMouseDown={startResize} className="h-1 cursor-ns-resize bg-transparent hover:bg-brand/40 transition" title="拖动调整高度" />}
|
||||
<div className="flex items-center border-b border-line px-2">
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
@@ -80,20 +48,13 @@ export function BottomDrawer({ run }: { run: RunState }) {
|
||||
}}
|
||||
/>
|
||||
<span className={cn("ml-2 text-[11px]", statusCls)}>{statusText}</span>
|
||||
<div className="ml-auto flex items-center">
|
||||
{open && (
|
||||
<button onClick={toggleMax} className="flex items-center px-2 py-2 text-slate-500 hover:text-slate-300" title={maximized ? "还原" : "最大化"}>
|
||||
{maximized ? <Minimize2 className="h-3.5 w-3.5" /> : <Maximize2 className="h-3.5 w-3.5" />}
|
||||
</button>
|
||||
)}
|
||||
<button onClick={() => setOpen((o) => !o)} className="flex items-center gap-1 px-2 py-2 text-xs text-slate-500 hover:text-slate-300">
|
||||
{open ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronUp className="h-3.5 w-3.5" />}
|
||||
{open ? "收起" : "展开"}
|
||||
</button>
|
||||
</div>
|
||||
<button onClick={() => setOpen((o) => !o)} className="ml-auto flex items-center gap-1 px-2 py-2 text-xs text-slate-500 hover:text-slate-300">
|
||||
{open ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronUp className="h-3.5 w-3.5" />}
|
||||
{open ? "收起" : "展开"}
|
||||
</button>
|
||||
</div>
|
||||
{open && (
|
||||
<div className="overflow-auto p-3 text-xs" style={{ height }}>
|
||||
<div className="h-44 overflow-auto p-3 text-xs">
|
||||
{tab === "output" && <OutputView output={run.output} />}
|
||||
{tab === "trace" && <ExecTrace events={run.exec} phase={run.phase} />}
|
||||
{tab === "tools" && <ToolCalls run={run} />}
|
||||
@@ -162,19 +123,26 @@ function ApprovalBar({ taskId, node, title, summary }: { taskId: string; node: s
|
||||
// OutputView:渲染模型输出。含 ```chart 块时分段渲染(文本 + SVG 图表),否则纯文本。
|
||||
function OutputView({ output }: { output: string }) {
|
||||
if (!output) {
|
||||
return <div className="text-xs leading-relaxed text-slate-500">在编排页搭图 → 运行,模型注入画像与历史后流式作答,结果在此渲染(支持 Markdown 与图表)。</div>;
|
||||
return (
|
||||
<pre className="whitespace-pre-wrap font-mono leading-relaxed text-emerald-300">
|
||||
在编排页搭图 → 运行,模型注入画像与历史后流式作答,token 在此呈现。
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
if (!hasChart(output)) {
|
||||
return <Markdown text={output} className="text-[13px]" />;
|
||||
return <pre className="whitespace-pre-wrap font-mono leading-relaxed text-emerald-300">{output}</pre>;
|
||||
}
|
||||
// 含 ```chart 块:文本段渲染 Markdown,图表段渲染 SVG,保持原顺序。
|
||||
return (
|
||||
<div>
|
||||
{extractChartBlocks(output).map((seg, i) =>
|
||||
seg.kind === "chart" ? (
|
||||
<ChartView key={i} spec={seg.spec} />
|
||||
) : (
|
||||
seg.text.trim() && <Markdown key={i} text={seg.text} className="text-[13px]" />
|
||||
seg.text.trim() && (
|
||||
<pre key={i} className="whitespace-pre-wrap font-mono leading-relaxed text-emerald-300">
|
||||
{seg.text}
|
||||
</pre>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user