From 6bb15aec1fafc7435f14957716127fa3c01f49e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=A8=E9=B1=BC=E8=BE=A3=E6=A4=92?= Date: Wed, 14 Oct 2026 11:33:59 +0800 Subject: [PATCH] Share Code sidebar with conversation programming settings --- ...20261014-code-settings-sidebar-8f4b2c71.md | 40 +++++++++++++++++++ README.md | 2 +- src/components/layout/MainLayout.tsx | 7 +++- src/components/layout/Sidebar.tsx | 5 +-- src/components/layout/TitleBar.tsx | 38 ++++++++++-------- src/pages/Chat/classroom-workspace.css | 6 +-- src/pages/Chat/index.tsx | 1 - 7 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 .project-docs/30-worklog/tasks/20261014-code-settings-sidebar-8f4b2c71.md diff --git a/.project-docs/30-worklog/tasks/20261014-code-settings-sidebar-8f4b2c71.md b/.project-docs/30-worklog/tasks/20261014-code-settings-sidebar-8f4b2c71.md new file mode 100644 index 00000000..52783b85 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20261014-code-settings-sidebar-8f4b2c71.md @@ -0,0 +1,40 @@ +# Task: Use Code sidebar throughout conversation programming settings + +## Identity + +- Task ID: 20261014-code-settings-sidebar-8f4b2c71 +- Mode: Feature +- Branch: codex/20261014-code-settings-sidebar-8f4b2c71-code-settings-sidebar +- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore/20261014-code-settings-sidebar-8f4b2c71 +- Base commit: 5e3afa841a86b005a6f19462e1634d4bf92cd881 +- Owner: codex +- Status: In Progress + +## Scope + +- Reuse the approved Code left rail for conversation programming settings (`/project-config?agent=…`) and its plugin resource route, including navigation/brand, shared resize/collapse, project rows, footer gallery and account placement. + +## Intent And Constraints + +- User explicitly supersedes the old config-specific header/gallery omission. Keep project configuration content, APIs, back/unsaved guards, session/project identities, current home-entry behavior and all trial inherited features unchanged. Renderer-only update preserves actual Main process/bytes. Load the Code skin from shared layout for direct route/reload. + +## Outcome + +- Implemented a shared Code sidebar route scope for `/chat`, `/project-config` and descendants. TitleBar uses a sidebar-specific layout flag so configuration title/project context/logo and main content padding retain their existing behavior. +- Removed configuration-only suppression of brand/header and gallery footer; project/session/account state and handlers are shared. Moved Code CSS loading to MainLayout so direct configuration entry and reload include the approved skin. Only two CSS scoping rules changed; footer rules and accepted placement remain exact. +- README behavior updated; focused Electron and trial update pending. + +## Verification + +- Official Concurrent/Planning Gates passed; 64 peer records/192 sections inspected read-only, no blocking semantic conflict. +- Typecheck, scoped ESLint, default full `build:vite` passed. +- 40 focused unit tests passed across layout peek, sidebar project actions, community, module navigation and Canvas layout. +- Focused Electron flow and native trial refresh pending. + +## Follow-ups + +- None recorded. + +## Promotion Candidates + +- None recorded. diff --git a/README.md b/README.md index d7feb64d..0c10824c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智 - macOS 窗口按钮:红色关闭当前窗口,全屏时先退出全屏再关闭;黄色最小化,绿色保留原生缩放/全屏行为。关窗后应用和进行中的后台任务继续运行,点击 Dock、托盘或菜单可重新打开窗口;`Cmd+Q` 退出应用。 - 桌面文本右键菜单:主 Renderer 窗口由 Electron Main 提供原生“剪切、复制、粘贴、全选”操作;菜单只在可编辑区域或已有文本选择时出现,普通空白区域不显示,也不向 Renderer 暴露剪贴板 IPC。 - AI 编程核心对话运行时:Electron Main 按需启动一个长驻 Pi Agent Server,同一进程内为每条 Conversation 建立独立的 Runtime、Session、凭证视图、扩展上下文和 JSONL 通道,同时复用 Pi 模块与进程启动成本;Server 异常退出时所有旧通道统一失效,下一次恢复只重启一个 Server。正式包中的 Agent Server 从明确传入的 `resources/pi-runtime` 根定位依赖清单与包入口,不从脚本所在目录或应用 `node_modules` 猜测解析。Renderer 不直接启动或调用 Pi,也不读取其 wire 类型。项目与 Conversation 元数据先从本地读取,选中对话后才按需准备对应逻辑线程;输入框不等待运行时准备完成。同一助手工具批次中,会取得项目写租约的 `bash`、`edit`、`write` 与动态产品工具按顺序执行,避免批次在命令启动前自锁;纯只读工具仍可并行。子 Agent 仍使用独立的短生命周期进程,以保留并发配额、故障和写入边界;macOS 上两类后台进程都使用 Electron 自带的 Helper,不在 Dock 中创建额外应用图标。 -- AI 编程默认入口:进入 Code 后保持在 `/chat`。顶部返回箭头与侧栏收起图标同排,与右侧项目/会话名称对齐;折叠时保留返回和展开入口。macOS 为原生窗口按钮保留安全空间,窄侧栏仍可使用。下方麦洛品牌与“操作对话/作品”标签行对齐;“作品广场”与“新建项目”沿用 Agent 的彩色图标徽章+文字样式,不再使用整行白色块与厚阴影,其中“新建项目”位于品牌下方原广场入口的位置,“作品广场”移至底部、紧邻账户按钮上方;“我的项目”和项目列表紧接新建项目,列表沿用图标与文字布局及浅色选中反馈;项目配置及其资源子页不再重复显示此侧栏入口,保留配置页自身的返回操作。尚未选择本地项目时,页面以麦洛 M 标识和居中引导语建立焦点,下方提供独立的“新增项目”主操作以及可横向浏览、直接进入的已有项目卡片;项目创建和进入仍复用侧栏现有流程。已有项目的新 Conversation 在可编辑 Composer 上方沿用同一品牌引导,第一条消息出现后切换为正常时间线。 +- AI 编程默认入口:进入 Code 后保持在 `/chat`。顶部返回箭头与侧栏收起图标同排,与右侧项目/会话名称对齐;折叠时保留返回和展开入口。macOS 为原生窗口按钮保留安全空间,窄侧栏仍可使用。下方麦洛品牌与“操作对话/作品”标签行对齐;“作品广场”与“新建项目”沿用 Agent 的彩色图标徽章+文字样式,不再使用整行白色块与厚阴影,其中“新建项目”位于品牌下方原广场入口的位置,“作品广场”移至底部、紧邻账户按钮上方;“我的项目”和项目列表紧接新建项目,列表沿用图标与文字布局及浅色选中反馈;进入“会话编程设置”后的项目配置页及插件资源页复用相同的左侧工作栏,品牌、返回与收起按钮、项目和会话列表、底部作品广场与账户的位置保持一致,并沿用当前宽度和收起状态;配置正文、顶部项目名称与配置页自身的返回操作保留。尚未选择本地项目时,页面以麦洛 M 标识和居中引导语建立焦点,下方提供独立的“新增项目”主操作以及可横向浏览、直接进入的已有项目卡片;项目创建和进入仍复用侧栏现有流程。已有项目的新 Conversation 在可编辑 Composer 上方沿用同一品牌引导,第一条消息出现后切换为正常时间线。 - AI 编程历史与配额反馈:Pi 上下文压缩不删除用户可见的 active-branch 历史,压缩摘要保持 Main-private;Renderer 首次渲染最近 120 个节点,向上滚动时按 100 个节点追加更早内容并保持阅读位置。Main 精确识别 `token_point_balance_exhausted` / `词元点数余额不足`,只向 Renderer 投影不可重试的稳定配额错误和安全中文提示,重开会话后仍可见且不暴露上游原始错误或 request id。 - 账号词元点数:左下角账户菜单显示本人永久余额和预占;“词元点数与充值”入口暂时隐藏,充值、充值订单与分页收支记录的既有实现保留。真正新注册赠送 100 点,1 元充值 50 点,永久有效;旧账户不补送,旧会员/订阅/周额度/重置卡入口已移除。家长为孩子充值时登录孩子的账号,页面显示当前昵称和账号,点数进入该账号自己的钱包;无需将孩子身份改为家长。当前有效账号可给本人充值,青少年可查看自己的精确余额;使用他人共享钱包时仅显示可用状态,不显示付款人的余额或记录。Main 持有凭据并转发充值请求;付款结果未知时沿用原请求并核查原订单,只有服务端确认才显示到账。扫码信息缺失时可到网页账户页继续原订单,付款来源也由网页账户页管理,充值不会自动切换共享/个人来源。需配套部署 Works Square 当前账号充值资格更新(本次无需新迁移,原永久点数基础为 0094);本地模拟验收不代表真实支付通过。 - 桌面性能策略:应用窗口使用不透明浅色表面并默认保留硬件合成;仅在显式安全模式或短时间内重复 GPU 进程崩溃时启用软件渲染,并把故障原因保存在用户数据目录。启动关键路径只创建本地应用壳,认证、代理、同步、更新和遥测在首帧后延迟初始化;开发版可通过 `app:performance` 快照观察 GPU、进程、WebContents、事件循环与 Renderer Long Task 聚合指标。 diff --git a/src/components/layout/MainLayout.tsx b/src/components/layout/MainLayout.tsx index 6e34ad2e..cc3b718e 100644 --- a/src/components/layout/MainLayout.tsx +++ b/src/components/layout/MainLayout.tsx @@ -12,6 +12,7 @@ import { getAiModuleForPath } from '@/lib/ai-modules'; import { useSettingsStore } from '@/stores/settings'; import { cn } from '@/lib/utils'; import type { SidebarPeekSource } from './sidebar-peek'; +import '@/pages/Chat/classroom-workspace.css'; const SIDEBAR_PEEK_CLOSE_DELAY_MS = 180; @@ -31,6 +32,7 @@ export function MainLayout() { const isPaintingModule = activeModule === 'painting'; const isCanvasWorkspace = location.pathname === '/image-canvas'; const isChatWorkspace = location.pathname === '/chat'; + const isCodeSidebar = isChatWorkspace || location.pathname === '/project-config' || location.pathname.startsWith('/project-config/'); const isCloudAgents = activeModule === 'cloud_agents'; const handleSidebarPeekChange = useCallback((open: boolean, source: SidebarPeekSource) => { @@ -80,13 +82,14 @@ export function MainLayout() { if (location.pathname === '/settings' || location.pathname.startsWith('/settings/')) return ; return ( -
+
{/* Title bar: drag region on macOS, icon + controls on Windows */} {workspaceLayout && !sidebarPinnedCollapsed && } - {!isProjectConfigPage && activeModule !== 'cloud_agents' &&
- {workspaceLayout && isProgrammingModule && !isProjectConfigPage && ( + {workspaceLayout && isProgrammingModule && (
diff --git a/src/components/layout/TitleBar.tsx b/src/components/layout/TitleBar.tsx index 043df9b1..b9cf996a 100644 --- a/src/components/layout/TitleBar.tsx +++ b/src/components/layout/TitleBar.tsx @@ -24,6 +24,7 @@ type SidebarPeekChange = (open: boolean, source: SidebarPeekSource) => void; type TitleBarProps = { integrated?: boolean; workspaceLayout?: boolean; + workspaceSidebar?: boolean; overlay?: boolean; showSidebarControls?: boolean; pageTitle?: string; @@ -32,11 +33,11 @@ type TitleBarProps = { onSidebarPeekChange?: SidebarPeekChange; }; -export function TitleBar({ integrated = false, workspaceLayout = false, overlay = false, showSidebarControls = true, pageTitle, showModuleReturn = false, sidebarPeekOpen = false, onSidebarPeekChange }: TitleBarProps) { +export function TitleBar({ integrated = false, workspaceLayout = false, workspaceSidebar = workspaceLayout, overlay = false, showSidebarControls = true, pageTitle, showModuleReturn = false, sidebarPeekOpen = false, onSidebarPeekChange }: TitleBarProps) { const platform = window.electron?.platform; if (platform === 'darwin') { - return ; + return ; } // Linux keeps its native window frame. Agents still needs an application @@ -45,12 +46,13 @@ export function TitleBar({ integrated = false, workspaceLayout = false, overlay return showModuleReturn ? : null; } - return ; + return ; } function ProductTitleBar({ integrated, workspaceLayout = false, + workspaceSidebar = workspaceLayout, overlay = false, showSidebarControls = true, pageTitle, @@ -63,6 +65,7 @@ function ProductTitleBar({ }: { integrated: boolean; workspaceLayout?: boolean; + workspaceSidebar?: boolean; overlay?: boolean; showSidebarControls?: boolean; pageTitle?: string; @@ -93,10 +96,10 @@ function ProductTitleBar({ // The project sidebar preview is rendered below the title bar, so mirror // its full width in the title bar for ordinary pages. The chat workspace // keeps project conversations in the sidebar and must preserve its title rail. - const sidebarPreviewTitlebarVisible = sidebarCollapsed && sidebarPeekOpen && !workspaceLayout && !overlay; + const sidebarPreviewTitlebarVisible = sidebarCollapsed && sidebarPeekOpen && !workspaceSidebar && !overlay; const sidebarTitlebarHidden = sidebarCollapsed && !sidebarPreviewTitlebarVisible; const agentNavigationWidth = sidebarTitlebarHidden ? (nativeTrafficLights && !nativeFullscreen ? 168 : 88) : 256; - const navigationWidth = workspaceLayout ? classroomTitlebarWidth : showModuleReturn ? agentNavigationWidth : undefined; + const navigationWidth = workspaceSidebar ? classroomTitlebarWidth : showModuleReturn ? agentNavigationWidth : undefined; const sidebarToggle = ( @@ -123,18 +126,18 @@ function ProductTitleBar({ data-testid="titlebar-sidebar-toggle-layer" className={cn( 'no-drag pointer-events-auto fixed left-0 top-0 z-[400] h-10', - !workspaceLayout && !showModuleReturn && (nativeTrafficLights ? 'w-[132px]' : 'w-[52px]'), + !workspaceSidebar && !showModuleReturn && (nativeTrafficLights ? 'w-[132px]' : 'w-[52px]'), )} style={navigationWidth !== undefined ? { width: navigationWidth } : undefined} - onPointerEnter={workspaceLayout || showModuleReturn ? () => handleSidebarPeekEnter('titlebar') : undefined} - onPointerLeave={workspaceLayout || showModuleReturn ? () => handleSidebarPeekLeave('titlebar') : undefined} - onFocusCapture={workspaceLayout || showModuleReturn ? () => handleSidebarPeekEnter('focus') : undefined} - onBlurCapture={workspaceLayout || showModuleReturn ? (event) => { + onPointerEnter={workspaceSidebar || showModuleReturn ? () => handleSidebarPeekEnter('titlebar') : undefined} + onPointerLeave={workspaceSidebar || showModuleReturn ? () => handleSidebarPeekLeave('titlebar') : undefined} + onFocusCapture={workspaceSidebar || showModuleReturn ? () => handleSidebarPeekEnter('focus') : undefined} + onBlurCapture={workspaceSidebar || showModuleReturn ? (event) => { if (!event.currentTarget.contains(event.relatedTarget as Node | null)) handleSidebarPeekLeave('focus'); } : undefined} > - {workspaceLayout || showModuleReturn ?
@@ -184,7 +187,7 @@ function ProductTitleBar({ style={navigationWidth !== undefined ? { width: navigationWidth, minWidth: navigationWidth, flexBasis: navigationWidth } : undefined} className={cn( 'flex h-full shrink-0 items-center gap-1 px-2', - workspaceLayout + workspaceSidebar ? '' : sidebarTitlebarHidden ? nativeTrafficLights @@ -258,7 +261,7 @@ function ProductTitleBar({ ); } -function WindowsTitleBar({ integrated, workspaceLayout, overlay, showSidebarControls, pageTitle, showModuleReturn, sidebarPeekOpen, onSidebarPeekChange }: Omit & { integrated: boolean }) { +function WindowsTitleBar({ integrated, workspaceLayout, workspaceSidebar, overlay, showSidebarControls, pageTitle, showModuleReturn, sidebarPeekOpen, onSidebarPeekChange }: Omit & { integrated: boolean }) { const [maximized, setMaximized] = useState(false); useEffect(() => { @@ -288,6 +291,7 @@ function WindowsTitleBar({ integrated, workspaceLayout, overlay, showSidebarCont