Share Code sidebar with conversation programming settings
This commit is contained in:
1 parent
5e3afa841a
commit
6bb15aec1f
7 files changed
+72
-27
No files matched your search
@@ -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.
|
||||
@@ -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 聚合指标。
|
||||
|
||||
@@ -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 <SettingsLayout />;
|
||||
|
||||
return (
|
||||
<div data-testid="main-layout" data-classroom={isChatWorkspace} className="relative flex h-[100dvh] flex-col overflow-hidden bg-transparent font-sans">
|
||||
<div data-testid="main-layout" data-classroom={isChatWorkspace} data-code-sidebar={isCodeSidebar} className="relative flex h-[100dvh] flex-col overflow-hidden bg-transparent font-sans">
|
||||
{/* Title bar: drag region on macOS, icon + controls on Windows */}
|
||||
<TitleBar
|
||||
integrated
|
||||
pageTitle={isCloudAgents ? '我的智能体' : undefined}
|
||||
showModuleReturn={isCloudAgents}
|
||||
workspaceLayout={isChatWorkspace}
|
||||
workspaceSidebar={isCodeSidebar}
|
||||
overlay={isPaintingModule}
|
||||
showSidebarControls={!isCanvasWorkspace}
|
||||
sidebarPeekOpen={isCanvasWorkspace || isCloudAgents ? false : sidebarPeekOpen}
|
||||
@@ -96,7 +99,7 @@ export function MainLayout() {
|
||||
{/* Below the title bar: sidebar + content */}
|
||||
<div className="relative flex min-h-0 flex-1 overflow-hidden">
|
||||
<Sidebar
|
||||
workspaceLayout={isChatWorkspace}
|
||||
workspaceLayout={isCodeSidebar}
|
||||
hideOnCompact={isCanvasWorkspace}
|
||||
forceExpanded={isCanvasWorkspace}
|
||||
sidebarPeekOpen={isCanvasWorkspace || isCloudAgents ? false : sidebarPeekOpen}
|
||||
|
||||
@@ -141,7 +141,6 @@ export function Sidebar({
|
||||
const isProgrammingModule = activeModule === 'programming';
|
||||
const isPaintingModule = activeModule === 'painting';
|
||||
const isRobotModule = activeModule === 'robot';
|
||||
const isProjectConfigPage = location.pathname === '/project-config' || location.pathname.startsWith('/project-config/');
|
||||
const visibleProjects = projects;
|
||||
const selectedProjectFolderName = getFolderName(newProjectSelectedPath);
|
||||
const accountName = userProfile?.displayName?.trim() || getAuthUserDisplayName(authUser) || '未登录用户';
|
||||
@@ -431,7 +430,7 @@ export function Sidebar({
|
||||
)}
|
||||
>
|
||||
{workspaceLayout && !sidebarPinnedCollapsed && <ClassroomSidebarResizer />}
|
||||
{!isProjectConfigPage && activeModule !== 'cloud_agents' && <div
|
||||
{activeModule !== 'cloud_agents' && <div
|
||||
className={cn(
|
||||
'bg-transparent px-3 text-foreground',
|
||||
workspaceLayout && 'classroom-sidebar-header',
|
||||
@@ -880,7 +879,7 @@ export function Sidebar({
|
||||
onOpenChange={setProfileDialogOpen}
|
||||
/>
|
||||
|
||||
{workspaceLayout && isProgrammingModule && !isProjectConfigPage && (
|
||||
{workspaceLayout && isProgrammingModule && (
|
||||
<div className="classroom-community-footer">
|
||||
<CommunityLink variant="sidebar" collapsed={sidebarCollapsed} />
|
||||
</div>
|
||||
|
||||
@@ -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 <ProductTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} showModuleReturn={showModuleReturn} nativeTrafficLights sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
|
||||
return <ProductTitleBar integrated={integrated} workspaceLayout={workspaceLayout} workspaceSidebar={workspaceSidebar} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} showModuleReturn={showModuleReturn} nativeTrafficLights sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
|
||||
}
|
||||
|
||||
// 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 ? <ProductTitleBar integrated={integrated} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} showModuleReturn sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} /> : null;
|
||||
}
|
||||
|
||||
return <WindowsTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} showModuleReturn={showModuleReturn} sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
|
||||
return <WindowsTitleBar integrated={integrated} workspaceLayout={workspaceLayout} workspaceSidebar={workspaceSidebar} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} showModuleReturn={showModuleReturn} sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
|
||||
}
|
||||
|
||||
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 = (
|
||||
<button
|
||||
type="button"
|
||||
@@ -107,13 +110,13 @@ function ProductTitleBar({
|
||||
className={cn(
|
||||
toolbarButtonClass,
|
||||
'pointer-events-auto absolute top-1 z-[401]',
|
||||
workspaceLayout || showModuleReturn ? 'right-2' : nativeTrafficLights ? 'left-[88px]' : 'left-2',
|
||||
workspaceSidebar || showModuleReturn ? 'right-2' : nativeTrafficLights ? 'left-[88px]' : 'left-2',
|
||||
)}
|
||||
onClick={toggleSidebar}
|
||||
onPointerEnter={() => handleSidebarPeekEnter('toggle')}
|
||||
onPointerLeave={() => handleSidebarPeekLeave('toggle')}
|
||||
onFocus={!workspaceLayout && !showModuleReturn ? () => handleSidebarPeekEnter('focus') : undefined}
|
||||
onBlur={!workspaceLayout && !showModuleReturn ? () => handleSidebarPeekLeave('focus') : undefined}
|
||||
onFocus={!workspaceSidebar && !showModuleReturn ? () => handleSidebarPeekEnter('focus') : undefined}
|
||||
onBlur={!workspaceSidebar && !showModuleReturn ? () => handleSidebarPeekLeave('focus') : undefined}
|
||||
>
|
||||
{sidebarCollapsed ? <PanelLeft className="h-4 w-4" /> : <PanelLeftClose className="h-4 w-4" />}
|
||||
</button>
|
||||
@@ -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 ? <div
|
||||
data-testid={workspaceLayout ? 'classroom-titlebar-navigation' : 'agent-titlebar-navigation'}
|
||||
{workspaceSidebar || showModuleReturn ? <div
|
||||
data-testid={workspaceSidebar ? 'classroom-titlebar-navigation' : 'agent-titlebar-navigation'}
|
||||
className={cn('flex h-full items-center gap-2 pr-12', nativeTrafficLights && !nativeFullscreen ? 'pl-[88px]' : 'pl-3')}
|
||||
>
|
||||
<ModuleSwitcher sidebarCollapsed={false} toolbar iconOnly />
|
||||
@@ -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<TitleBarProps, 'integrated'> & { integrated: boolean }) {
|
||||
function WindowsTitleBar({ integrated, workspaceLayout, workspaceSidebar, overlay, showSidebarControls, pageTitle, showModuleReturn, sidebarPeekOpen, onSidebarPeekChange }: Omit<TitleBarProps, 'integrated'> & { integrated: boolean }) {
|
||||
const [maximized, setMaximized] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -288,6 +291,7 @@ function WindowsTitleBar({ integrated, workspaceLayout, overlay, showSidebarCont
|
||||
<ProductTitleBar
|
||||
integrated={integrated}
|
||||
workspaceLayout={workspaceLayout}
|
||||
workspaceSidebar={workspaceSidebar}
|
||||
overlay={overlay}
|
||||
showSidebarControls={showSidebarControls}
|
||||
pageTitle={pageTitle}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* Approved playful Code workbench. Keep navigation skins scoped to /chat. */
|
||||
[data-testid="main-layout"][data-classroom="true"], .classroom-workspace {
|
||||
/* Shared Code navigation skin; chat content remains scoped to its workspace. */
|
||||
[data-testid="main-layout"][data-classroom="true"], [data-testid="sidebar"][data-classroom="true"], .classroom-workspace {
|
||||
--background: 0 0% 100%; --foreground: 214 34% 23%;
|
||||
--muted-foreground: 214 16% 44%; --border: 213 31% 90%;
|
||||
}
|
||||
[data-testid="main-layout"][data-classroom="true"] [data-testid="titlebar-sidebar-surface"] { background: #f3f7fb; border-color: #dde5ee; box-shadow: none; backdrop-filter: none; }
|
||||
[data-testid="main-layout"][data-code-sidebar="true"] [data-testid="titlebar-sidebar-surface"] { background: #f3f7fb; border-color: #dde5ee; box-shadow: none; backdrop-filter: none; }
|
||||
[data-testid="sidebar"][data-classroom="true"] { background: #f3f7fb; border-color: #dde5ee; box-shadow: none; backdrop-filter: none; color: #26384d; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-sidebar-header { padding-top: 0; padding-bottom: 0; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="classroom-sidebar-navigation"] { align-items: center; }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import './classroom-workspace.css';
|
||||
import { CodingChatPanel } from './CodingChatPanel';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { codingRecoveryAccount, readCodingLoginRecovery } from '@/lib/coding-login-recovery';
|
||||
|
||||
Reference in new issue
Block a user