diff --git a/sundynix-desktop/frontend/src/shell/BottomDrawer.tsx b/sundynix-desktop/frontend/src/shell/BottomDrawer.tsx index be91343..d998fc2 100644 --- a/sundynix-desktop/frontend/src/shell/BottomDrawer.tsx +++ b/sundynix-desktop/frontend/src/shell/BottomDrawer.tsx @@ -1,8 +1,9 @@ -import { useState } from "react"; -import { ChevronDown, ChevronUp, Wrench, ShieldCheck, Check, X } from "lucide-react"; +import { useCallback, useRef, useState } from "react"; +import { ChevronDown, ChevronUp, Wrench, ShieldCheck, Check, X, Maximize2, Minimize2 } 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"; @@ -13,6 +14,35 @@ type Tab = "output" | "trace" | "tools" | "cite" | "eval"; export function BottomDrawer({ run }: { run: RunState }) { const [open, setOpen] = useState(true); const [tab, setTab] = useState("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; @@ -38,6 +68,8 @@ export function BottomDrawer({ run }: { run: RunState }) { return (
{approval && run.taskId && } + {/* 拖拽调高手柄(横跨顶边) */} + {open &&
}
{statusText} - +
+ {open && ( + + )} + +
{open && ( -
+
{tab === "output" && } {tab === "trace" && } {tab === "tools" && } @@ -123,26 +162,19 @@ function ApprovalBar({ taskId, node, title, summary }: { taskId: string; node: s // OutputView:渲染模型输出。含 ```chart 块时分段渲染(文本 + SVG 图表),否则纯文本。 function OutputView({ output }: { output: string }) { if (!output) { - return ( -
-        在编排页搭图 → 运行,模型注入画像与历史后流式作答,token 在此呈现。
-      
- ); + return
在编排页搭图 → 运行,模型注入画像与历史后流式作答,结果在此渲染(支持 Markdown 与图表)。
; } if (!hasChart(output)) { - return
{output}
; + return ; } + // 含 ```chart 块:文本段渲染 Markdown,图表段渲染 SVG,保持原顺序。 return (
{extractChartBlocks(output).map((seg, i) => seg.kind === "chart" ? ( ) : ( - seg.text.trim() && ( -
-              {seg.text}
-            
- ) + seg.text.trim() && ), )}