diff --git a/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx b/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx index e36087c8..2338e457 100644 --- a/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx +++ b/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx @@ -138,6 +138,7 @@ export function AgentDetailPanel({ disabled, defaultCollapsed, showRecentChats, + compactAppearanceActions, }: { agent: Agent | null | undefined; agentName: string; @@ -147,6 +148,8 @@ export function AgentDetailPanel({ defaultCollapsed?: boolean; /** 在面板底部展示「有关此智能体的最近对话」(仅智能体问答页开启,任务工作区不展示)。 */ showRecentChats?: boolean; + /** 简洁模式下挂在右上角收起/展开按钮左侧的外观控件。 */ + compactAppearanceActions?: ReactNode; }) { const router = useRouter(); const [collapsed, setCollapsed] = useState(defaultCollapsed ?? false); @@ -830,6 +833,7 @@ export function AgentDetailPanel({ 智能体信息
{headerActions} + {compactAppearanceActions} {collapseButton}
@@ -841,17 +845,20 @@ export function AgentDetailPanel({ <> {/* ── Desktop (lg+): inline aside, collapsible to a rail ───────────── */} {collapsed ? ( -
- - - +
+
+ {compactAppearanceActions} + + + +
) : (
+ + {!hideAdvancedFields && ( <>
diff --git a/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx b/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx index 684d341d..5aef92ea 100644 --- a/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx +++ b/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { ChevronsDown, CloudUpload, PanelRightClose, Pause, Play, Plus, RotateCcw, Settings2, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; @@ -73,11 +73,13 @@ export function AIWritingPanel({ initialNotebookId, initialDocumentIds, studioToken, + headerActionsBeforeCollapse, }: { hideAdvancedFields?: boolean; initialNotebookId?: number; initialDocumentIds?: number[]; studioToken?: string; + headerActionsBeforeCollapse?: ReactNode; } = {}) { const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); @@ -429,6 +431,7 @@ export function AIWritingPanel({ onRename={rename} onRefresh={refresh} /> + {headerActionsBeforeCollapse} {/* 收起写作配置:仅在 idle 配置阶段、表单展开时出现(与 AIWritingPage 的整块收起联动) */} {writingForm && isIdle && !isHistoryMode && writingForm.formExpanded && (
)}
-
-
- -
- - setTemplateSearch(event.target.value)} - placeholder="搜索写作模板..." - className="h-8 w-full rounded-lg border border-slate-200 bg-slate-50/80 pl-8 pr-3 text-[12px] text-slate-600 outline-none transition focus:border-blue-200 focus:bg-white focus:ring-2 focus:ring-blue-100" - /> -
-
- - {templates.length === 0 ? ( -

- 暂无研究模板,点击标题配置 -

- ) : filteredTemplates.length === 0 ? ( -

- 暂无匹配模板 -

- ) : ( -
- {filteredTemplates.map((tpl, index) => { - const visual = getTemplateVisual(tpl, index); - const Icon = visual.Icon; - return ( - - ); - })} -
- )} -
- -
+

笔记本 diff --git a/frontend-web/src/open-canvas/components/ai-writing/ResearchTemplatesPanel.tsx b/frontend-web/src/open-canvas/components/ai-writing/ResearchTemplatesPanel.tsx new file mode 100644 index 00000000..ee101605 --- /dev/null +++ b/frontend-web/src/open-canvas/components/ai-writing/ResearchTemplatesPanel.tsx @@ -0,0 +1,238 @@ +"use client"; + +import { + BarChart3, + BookOpen, + Globe2, + Newspaper, + Search, + Settings2, + SlidersHorizontal, + Sparkles, + TrendingUp, +} from "lucide-react"; +import type { LucideIcon } from "lucide-react"; +import { useEffect, useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import { cn } from "@/lib/utils"; + +import type { ResearchTemplate } from "../../api/ai-writing-research-templates"; +import { useAIWriting } from "../../contexts/AIWritingContext"; +import { useWritingForm } from "../../contexts/WritingFormContext"; +import { useResearchTemplates } from "../../hooks/useResearchTemplates"; + +type TemplateVisual = { + Icon: LucideIcon; + iconClass: string; + accentClass: string; +}; + +const TEMPLATE_VISUALS: TemplateVisual[] = [ + { + Icon: Globe2, + iconClass: "bg-blue-50 text-blue-600", + accentClass: "bg-blue-500", + }, + { + Icon: Newspaper, + iconClass: "bg-amber-50 text-amber-600", + accentClass: "bg-amber-500", + }, + { + Icon: Sparkles, + iconClass: "bg-violet-50 text-violet-600", + accentClass: "bg-violet-500", + }, + { + Icon: TrendingUp, + iconClass: "bg-rose-50 text-rose-600", + accentClass: "bg-rose-500", + }, + { + Icon: BookOpen, + iconClass: "bg-emerald-50 text-emerald-600", + accentClass: "bg-emerald-500", + }, + { + Icon: BarChart3, + iconClass: "bg-cyan-50 text-cyan-600", + accentClass: "bg-cyan-500", + }, +]; + +function getTemplateVisual( + tpl: ResearchTemplate, + index: number, +): TemplateVisual { + const text = `${tpl.name} ${tpl.description ?? ""} ${tpl.article_type_key ?? ""}`; + if (/网摘|网络|热点|摘/.test(text)) return TEMPLATE_VISUALS[0]; + if (/周报|周刊|日报|月报/.test(text)) return TEMPLATE_VISUALS[1]; + if (/要讯|资讯|快讯|简报/.test(text)) return TEMPLATE_VISUALS[2]; + if (/行业|分析|市场|竞争/.test(text)) return TEMPLATE_VISUALS[3]; + if (/政策|解读|法规/.test(text)) return TEMPLATE_VISUALS[4]; + return TEMPLATE_VISUALS[index % TEMPLATE_VISUALS.length]; +} + +export function ResearchTemplatesPanel({ + className, +}: { + className?: string; +}) { + const navigate = useNavigate(); + const { templates, refresh } = useResearchTemplates(); + const { startWriting } = useAIWriting(); + const { + setIntent, + setArticleType, + setOutlineText, + setShowOutline, + setMaterialSource, + setWordCountInput, + setAudience, + setStrictMode, + setFormExpanded, + } = useWritingForm(); + const [templateSearch, setTemplateSearch] = useState(""); + + useEffect(() => { + void refresh(); + }, [refresh]); + + const filteredTemplates = useMemo(() => { + const keyword = templateSearch.trim().toLowerCase(); + if (!keyword) return templates; + return templates.filter((tpl) => + [tpl.name, tpl.description, tpl.article_type_key] + .filter(Boolean) + .some((value) => String(value).toLowerCase().includes(keyword)), + ); + }, [templates, templateSearch]); + + const handleTemplateClick = (tpl: ResearchTemplate) => { + const intent = tpl.topic?.trim() ?? ""; + const articleType = tpl.article_type_key || "analysis"; + const outline = tpl.outline?.trim() || ""; + const audience = tpl.audience?.trim() || "普通读者"; + const wordCount = tpl.word_count > 0 ? tpl.word_count : 800; + const writingMode = tpl.strict_mode ? "strict" : "loose"; + + if (intent) setIntent(intent); + if (tpl.article_type_key) setArticleType(tpl.article_type_key); + if (outline) { + setOutlineText(outline); + setShowOutline(true); + } + setMaterialSource(tpl.material_source); + setWordCountInput(String(wordCount)); + if (tpl.audience?.trim()) setAudience(audience); + setStrictMode(tpl.strict_mode); + setFormExpanded(true); + + if (!intent) return; + void startWriting({ + userIntent: intent, + userOutline: outline || undefined, + articleType, + targetAudience: audience, + wordCountTarget: wordCount, + keywordCount: 1, + writingMode, + materialSource: tpl.material_source, + }); + }; + + return ( +
+
+ +
+ + setTemplateSearch(event.target.value)} + onKeyDown={(event) => { + if (event.key === "Enter") event.preventDefault(); + }} + placeholder="搜索写作模板..." + className="h-8 w-full rounded-lg border border-slate-200 bg-slate-50/80 pl-8 pr-3 text-[12px] text-slate-600 outline-none transition focus:border-blue-200 focus:bg-white focus:ring-2 focus:ring-blue-100 dark:border-[#1B477E] dark:bg-[#022248] dark:text-[#AACEFF]" + /> +
+
+ + {templates.length === 0 ? ( +

+ 暂无研究模板,点击标题配置 +

+ ) : filteredTemplates.length === 0 ? ( +

+ 暂无匹配模板 +

+ ) : ( +
+ {filteredTemplates.map((tpl, index) => { + const visual = getTemplateVisual(tpl, index); + const Icon = visual.Icon; + return ( + + ); + })} +
+ )} +
+ ); +} diff --git a/frontend-web/src/open-canvas/pages/AIWritingPage.tsx b/frontend-web/src/open-canvas/pages/AIWritingPage.tsx index afc3fceb..4c56e940 100644 --- a/frontend-web/src/open-canvas/pages/AIWritingPage.tsx +++ b/frontend-web/src/open-canvas/pages/AIWritingPage.tsx @@ -81,7 +81,7 @@ * -d '{"retention_days": 0}' * ────────────────────────────────────────────────────────────────────────── */ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { ArrowLeft, History, @@ -113,6 +113,10 @@ import StudioNotebookDetailPage from '@/pages/StudioNotebookDetailPage'; import StudioNotebooksPage from '@/pages/StudioNotebooksPage'; import AgentChatPage from '@/pages/AgentChatPage'; import { ChatRuntime } from '@/pages/WorkspaceRoutes'; +import { + LayoutModeSwitcher, + ThemeSwitcher, +} from '@/components/workspace/appearance-controls'; import { AgentModuleSidebar, useAgentModuleSidebarData, @@ -137,10 +141,20 @@ const WRITING_ID = 'aw-writing'; const DRAFT_ID = 'aw-draft'; const AI_WRITING_AGENT_MODULE_KEY = 'ai-writing'; const AI_WRITING_AGENT_MODULE_TITLE = 'AI 写作智能体'; +const AI_WRITING_LAST_AGENT_KEY = `agent-module:${AI_WRITING_AGENT_MODULE_KEY}:last-agent`; // Match the original canvas page proportions (chat=35, artifact=65) const DEFAULT_LAYOUT = { [WRITING_ID]: 35, [DRAFT_ID]: 65 }; +function AIWritingCompactAppearanceActions() { + return ( +
+ + +
+ ); +} + function useAIWritingRouteBase() { const { pathname } = useLocation(); return useMemo(() => { @@ -170,7 +184,15 @@ function useAIWritingAgentRouteState(base: string) { function AIWritingAgentDefaultRedirect() { const { groups, isLoading } = useAgentModuleSidebarData(AI_WRITING_AGENT_MODULE_KEY); - const firstAgent = groups.flatMap((group) => group.agents)[0]; + const agents = groups.flatMap((group) => group.agents); + const lastAgentId = (() => { + try { + return sessionStorage.getItem(AI_WRITING_LAST_AGENT_KEY); + } catch { + return null; + } + })(); + const targetAgent = agents.find((agent) => agent.id === lastAgentId) ?? agents[0]; if (isLoading) { return ( @@ -180,7 +202,7 @@ function AIWritingAgentDefaultRedirect() { ); } - if (!firstAgent) { + if (!targetAgent) { return (
暂无可用智能体,请先在模块设置中配置或创建智能体。 @@ -188,24 +210,44 @@ function AIWritingAgentDefaultRedirect() { ); } - return ; + return ; } -function AIWritingAgentChatRoute() { +function AIWritingAgentChatRoute({ + compactAppearanceActions, +}: { + compactAppearanceActions?: ReactNode; +}) { const { agent_id } = useParams<{ agent_id: string }>(); return ( - + ); } -function AIWritingAgentRoutes({ base }: { base: string }) { +function AIWritingAgentRoutes({ + base, + compactAppearanceActions, +}: { + base: string; + compactAppearanceActions?: ReactNode; +}) { return ( } /> - } /> + + } + /> ); @@ -220,11 +262,26 @@ interface NotebookProps { studioToken?: string; } -function WritingFormPanel({ hideAdvancedFields, initialNotebookId, initialDocumentIds, studioToken }: { hideAdvancedFields: boolean } & NotebookProps) { +function WritingFormPanel({ + hideAdvancedFields, + initialNotebookId, + initialDocumentIds, + studioToken, + headerActionsBeforeCollapse, +}: { + hideAdvancedFields: boolean; + headerActionsBeforeCollapse?: ReactNode; +} & NotebookProps) { return ( // 与原布局保持相同的 flex-1 min-h-0 包裹,确保内部 h-full 正确解析
- +
); } @@ -234,7 +291,16 @@ function WritingFormPanel({ hideAdvancedFields, initialNotebookId, initialDocume * - idle(初始问答阶段):左=「写作助手 Q&A」,右=「写作配置选项」表单; * - 开始写作后:回到原布局——左=写作配置/时间线面板,右=草稿预览。 */ -function AIWritingLayout({ hideAdvancedFields, initialNotebookId, initialDocumentIds, studioToken }: { hideAdvancedFields: boolean } & NotebookProps) { +function AIWritingLayout({ + hideAdvancedFields, + initialNotebookId, + initialDocumentIds, + studioToken, + compactAppearanceActions, +}: { + hideAdvancedFields: boolean; + compactAppearanceActions?: ReactNode; +} & NotebookProps) { const layoutRef = useRef(null); const { state } = useAIWriting(); const { isHistoryMode } = useAIWritingHistory(); @@ -262,19 +328,28 @@ function AIWritingLayout({ hideAdvancedFields, initialNotebookId, initialDocumen formExpanded ? 'w-[36%] min-w-[340px] max-w-[600px] border-l' : 'w-0 min-w-0', )} > - +
{/* 收起态:右上角浮动展开图标按钮(与展开态头部的收起按钮位置呼应) */} {!formExpanded && ( - +
+ {compactAppearanceActions} + +
)}

); @@ -322,7 +397,16 @@ function AIWritingLayout({ hideAdvancedFields, initialNotebookId, initialDocumen * 写作页主体(侧栏 + 内容区)。放在 Provider 内部,以便读 useAIWriting 状态: * 进入写作(status !== idle 或查看历史)后自动收起左侧研究模板栏,让写作区更宽。 */ -function AIWritingBody({ hideAdvancedFields, initialNotebookId, initialDocumentIds, studioToken }: { hideAdvancedFields: boolean } & NotebookProps) { +function AIWritingBody({ + hideAdvancedFields, + initialNotebookId, + initialDocumentIds, + studioToken, + compactChrome = false, +}: { + hideAdvancedFields: boolean; + compactChrome?: boolean; +} & NotebookProps) { const { state } = useAIWriting(); const { isHistoryMode } = useAIWritingHistory(); const location = useLocation(); @@ -354,6 +438,9 @@ function AIWritingBody({ hideAdvancedFields, initialNotebookId, initialDocumentI // 历史内容显示到右侧区域);写作进行中收起;嵌入态(studioToken)始终不展示。 const showSidebar = !studioToken && (state.status === 'idle' || isHistoryMode || agentsActive); + const compactAppearanceActions = compactChrome ? ( + + ) : null; return (
@@ -459,7 +546,13 @@ function AIWritingBody({ hideAdvancedFields, initialNotebookId, initialDocumentI 查看笔记本 / 所有空间时在其上叠加内嵌页。 */}
- +
{overlayActive && !agentsActive && (
@@ -500,7 +593,10 @@ function AIWritingBody({ hideAdvancedFields, initialNotebookId, initialDocumentI )} {agentsActive && (
- +
)}
@@ -521,11 +617,13 @@ export default function AIWritingPage({ initialNotebookId, initialDocumentIds, studioToken, + compactChrome = false, }: { hideAdvancedFields?: boolean; initialNotebookId?: number; initialDocumentIds?: number[]; studioToken?: string; + compactChrome?: boolean; } = {}) { return ( @@ -545,6 +643,7 @@ export default function AIWritingPage({ initialNotebookId={initialNotebookId} initialDocumentIds={initialDocumentIds} studioToken={studioToken} + compactChrome={compactChrome} />
diff --git a/frontend-web/src/pages/AgentChatPage.tsx b/frontend-web/src/pages/AgentChatPage.tsx index e5309bfe..9bbb23cb 100644 --- a/frontend-web/src/pages/AgentChatPage.tsx +++ b/frontend-web/src/pages/AgentChatPage.tsx @@ -4,7 +4,7 @@ import { BotIcon, PlusSquare } from "lucide-react"; import { useParams, useRouter } from "next/navigation"; import { useLocation } from "react-router-dom"; import { useRouteBase } from "@/core/route-base"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; import { Button } from "@/components/ui/button"; @@ -65,6 +65,7 @@ export default function AgentChatPage({ taskBind, autoStartWhenPurposeEmpty, showAgentList, + compactAppearanceActions, }: { /** 当作为「通用问答右侧嵌入」渲染时由父组件传入的 agent id(替代路由参数)。 * 传入即视为嵌入态:路由仍停留在 /chats/new,仅右侧问答区换成该智能体的对话。 */ @@ -85,6 +86,8 @@ export default function AgentChatPage({ /** 是否在最左侧展示「智能体列表」栏(顶部下拉切换 我的/广场,点击进入该智能体对话)。 * 仅独立的智能体问答整页开启;任务工作区 / 模块页 / 嵌入态不传(各有自己的左栏)。 */ showAgentList?: boolean; + /** 简洁模式下,挂到右侧智能体信息面板收起按钮左侧的外观控件。 */ + compactAppearanceActions?: ReactNode; } = {}) { const routeBase = useRouteBase(); const { t } = useI18n(); @@ -589,6 +592,7 @@ export default function AgentChatPage({ onAskQuestion={(text) => handleSubmit({ text, files: [] })} defaultCollapsed={taskCtxOn} showRecentChats={!taskCtxOn} + compactAppearanceActions={compactAppearanceActions} />
diff --git a/frontend-web/src/pages/ChatsPage.tsx b/frontend-web/src/pages/ChatsPage.tsx index 49c6d497..8c033b3b 100644 --- a/frontend-web/src/pages/ChatsPage.tsx +++ b/frontend-web/src/pages/ChatsPage.tsx @@ -15,6 +15,10 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { ImportConversationsDialog } from "@/components/workspace/thread-share-dialogs"; +import { + LayoutModeSwitcher, + ThemeSwitcher, +} from "@/components/workspace/appearance-controls"; import { WorkspaceBody, WorkspaceContainer, @@ -40,7 +44,11 @@ import { cn } from "@/lib/utils"; const PAGE_SIZE = 20; -export default function ChatsPage() { +export default function ChatsPage({ + compactChrome = false, +}: { + compactChrome?: boolean; +}) { const pathOfThread = usePathOfThread(); const { t } = useI18n(); const { toggle: togglePin } = useToggleThreadPin(); @@ -171,7 +179,16 @@ export default function ChatsPage() { return ( - + + + +
+ ) : null + } + />
diff --git a/frontend-web/src/pages/ScheduledTasksPage.tsx b/frontend-web/src/pages/ScheduledTasksPage.tsx index cf8ee1df..d3efd218 100644 --- a/frontend-web/src/pages/ScheduledTasksPage.tsx +++ b/frontend-web/src/pages/ScheduledTasksPage.tsx @@ -43,6 +43,10 @@ import { WorkspaceContainer, WorkspaceHeader, } from "@/components/workspace/workspace-container"; +import { + LayoutModeSwitcher, + ThemeSwitcher, +} from "@/components/workspace/appearance-controls"; import { TagChipList } from "@/components/workspace/tags/tag-chip"; import { TagPickerDialog } from "@/components/workspace/tags/tag-picker-dialog"; import { TagSearchBar } from "@/components/workspace/tags/tag-search-bar"; @@ -144,7 +148,11 @@ const SCHEDULED_TASK_TEXTAREA_CLASS = const DESCRIPTION_TEXTAREA_ROWS = 4; const PROMPT_TEXTAREA_ROWS = 10; -export default function ScheduledTasksPage() { +export default function ScheduledTasksPage({ + compactChrome = false, +}: { + compactChrome?: boolean; +}) { const queryClient = useQueryClient(); const { theme } = useTheme(); const darkToastOpts = @@ -490,7 +498,16 @@ export default function ScheduledTasksPage() { return ( - + + + +
+ ) : null + } + />
diff --git a/frontend-web/src/pages/WorkspaceRoutes.tsx b/frontend-web/src/pages/WorkspaceRoutes.tsx index bcc3bda5..02054a19 100644 --- a/frontend-web/src/pages/WorkspaceRoutes.tsx +++ b/frontend-web/src/pages/WorkspaceRoutes.tsx @@ -5,7 +5,12 @@ import { getStoredAuth } from '@/core/auth'; import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'; import { PromptInputProvider } from '@/components/ai-elements/prompt-input'; +import { + LayoutModeSwitcher, + ThemeSwitcher, +} from '@/components/workspace/appearance-controls'; import { WorkspaceSidebar } from '@/components/workspace/workspace-sidebar'; +import { UserIdentityBadge } from '@/components/workspace/user-identity-badge'; import { CommandPalette } from '@/components/workspace/command-palette'; import { Toaster } from 'sonner'; import { SubtasksProvider } from '@/core/tasks/context'; @@ -72,6 +77,27 @@ function isInIframe(): boolean { } } +function shouldShowCompactTopActions(pathname: string): boolean { + return ( + pathname === '/page/workspace/agents' || + pathname === '/page/workspace/skills' || + pathname === '/page/workspace/memory' || + pathname === '/page/workspace/knowledge' || + pathname.startsWith('/page/workspace/knowledge/') + ); +} + +function CompactWorkspaceTopActions() { + return ( +
+ + +
+ +
+ ); +} + export function WorkspaceLayout({ children, pageSidebarCollapsed, @@ -98,7 +124,10 @@ export function WorkspaceLayout({ }) { // 全量模式下通用问答(/page/workspace/chats*)的历史侧栏默认展开;其余紧凑页 // (如智能体对话,为聊天区更宽而默认收起)维持原默认。 - const isGeneralQa = useLocation().pathname.startsWith("/page/workspace/chats"); + const pathname = useLocation().pathname; + const isGeneralQa = pathname.startsWith('/page/workspace/chats'); + const showCompactTopActions = + headerHidden && shouldShowCompactTopActions(pathname); const pageSidebarWidth = pageSidebarHidden ? '0rem' @@ -136,7 +165,14 @@ export function WorkspaceLayout({ - {children} + {showCompactTopActions ? ( + <> + +
{children}
+ + ) : ( + children + )}
@@ -222,7 +258,7 @@ export default function WorkspaceRoutes({ path="chats" element={ - + } /> @@ -338,7 +374,10 @@ export default function WorkspaceRoutes({ path="ai-writing/*" element={ - + } /> @@ -371,7 +410,7 @@ export default function WorkspaceRoutes({ element={ - + } @@ -433,7 +472,7 @@ export default function WorkspaceRoutes({ path="scheduled/tasks" element={ - + } /> diff --git a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx index 0c33fc0d..ffb04607 100644 --- a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx +++ b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx @@ -61,6 +61,10 @@ import { import { useTheme } from "@/contexts/ThemeContext"; import { useArtifacts } from "@/components/workspace/artifacts"; +import { + LayoutModeSwitcher, + ThemeSwitcher, +} from "@/components/workspace/appearance-controls"; import { useSidebarSafe } from "@/components/ui/sidebar"; import { DropdownMenu, @@ -282,7 +286,11 @@ function readEmbedHashQueryPrefill(): RoundtablePrefill | null { } -export default function RoundtablePlanningPage() { +export default function RoundtablePlanningPage({ + compactChrome = false, +}: { + compactChrome?: boolean; +}) { const { theme } = useTheme(); // 全工作区跨页的后台作业完成通知器(Provider 挂在 PageLayout 常驻层)。 const { watchJob } = useRoundtableJobNotifier(); @@ -2075,6 +2083,12 @@ export default function RoundtablePlanningPage() { > + {compactChrome && ( + <> + + + + )}