Complete playful Code workbench styling in real navigation
This commit is contained in:
@@ -74,7 +74,7 @@ export function MainLayout() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div data-testid="main-layout" className="relative flex h-[100dvh] flex-col overflow-hidden bg-transparent font-sans">
|
||||
<div data-testid="main-layout" data-classroom={isChatWorkspace} 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
|
||||
|
||||
@@ -410,13 +410,14 @@ export function Sidebar({
|
||||
)}
|
||||
>
|
||||
<div className="min-w-0 w-full">
|
||||
{workspaceLayout ? <button type="button" aria-label="返回首页" title="返回首页" onClick={() => navigate('/module-select')} className="flex w-full items-center gap-2 rounded-lg px-1 pb-4 pt-3 text-left hover:bg-black/[0.025]">
|
||||
<img src={classroomMark} alt="" className="h-7 w-7" /><span className="text-base font-semibold tracking-tight">麦洛</span>
|
||||
{workspaceLayout ? <button type="button" aria-label="返回首页" title="返回首页" onClick={() => navigate('/module-select')} className="classroom-brand flex w-full items-center gap-2 rounded-lg text-left">
|
||||
<span className="classroom-brand-mark"><img src={classroomMark} alt="" className="h-7 w-7" /></span>
|
||||
<span className="min-w-0"><span className="block text-base font-semibold tracking-tight">麦洛</span><span className="classroom-brand-caption">把脑洞变成作品</span></span>
|
||||
</button> : <ModuleSwitcher sidebarCollapsed={sidebarCollapsed} compact={!sidebarCollapsed} />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 flex-1 overflow-auto px-2 py-2">
|
||||
<div className="classroom-sidebar-content min-h-0 flex-1 overflow-auto px-2 py-2">
|
||||
{isPaintingModule ? (
|
||||
<ImageWorkspaceSidebar sidebarCollapsed={sidebarCollapsed} />
|
||||
) : isProgrammingModule ? (
|
||||
@@ -434,19 +435,19 @@ export function Sidebar({
|
||||
<Plus className="h-4 w-4 shrink-0 text-brand" />
|
||||
{!sidebarCollapsed && '新建项目'}
|
||||
</button>
|
||||
<div className="mt-3">
|
||||
<div className="classroom-projects mt-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setProjectsOpen(!projectsOpen)}
|
||||
className={cn(
|
||||
'motion-press flex min-h-8 w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground hover:bg-surface-subtle hover:text-foreground',
|
||||
'classroom-projects-heading motion-press flex min-h-8 w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground hover:bg-surface-subtle hover:text-foreground',
|
||||
sidebarCollapsed ? 'justify-center px-0' : '',
|
||||
)}
|
||||
>
|
||||
<FolderKanban className="h-4 w-4 shrink-0" />
|
||||
{!sidebarCollapsed && (
|
||||
<>
|
||||
<span className="min-w-0 flex-1 truncate">项目</span>
|
||||
<span className="min-w-0 flex-1 truncate">{workspaceLayout ? '我的项目' : '项目'}</span>
|
||||
<span className="text-xs">{projectsOpen ? '收起' : '展开'}</span>
|
||||
</>
|
||||
)}
|
||||
@@ -471,13 +472,14 @@ export function Sidebar({
|
||||
aria-current={active ? 'page' : undefined}
|
||||
onClick={() => void openProject(project)}
|
||||
className={cn(
|
||||
'motion-press group/project flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left transition-colors duration-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand/35 focus-visible:ring-offset-1',
|
||||
'classroom-project-card motion-press group/project flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left transition-colors duration-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand/35 focus-visible:ring-offset-1',
|
||||
active
|
||||
? 'bg-transparent text-foreground'
|
||||
: 'bg-transparent text-foreground hover:bg-surface-tertiary',
|
||||
)}
|
||||
>
|
||||
<Gamepad2 className="h-3.5 w-3.5 shrink-0 text-muted-foreground" /><span className="min-w-0 flex-1 truncate text-[13px] font-medium">{project.name}</span>
|
||||
{workspaceLayout ? <span className="classroom-project-icon" data-tone={['orange', 'green', 'blue'][Array.from(project.id).reduce((sum, char) => sum + char.charCodeAt(0), 0) % 3]}><Gamepad2 aria-hidden="true" /></span> : <Gamepad2 className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />}
|
||||
<span className="min-w-0 flex-1 truncate text-[13px] font-medium">{project.name}</span>
|
||||
<ChevronRight aria-hidden="true" className="h-3.5 w-3.5 shrink-0 -translate-x-0.5 text-muted-foreground opacity-50 transition-[opacity,transform,color] duration-200 ease-out group-hover/project:translate-x-0 group-hover/project:text-foreground group-hover/project:opacity-100 group-focus-visible/project:translate-x-0 group-focus-visible/project:text-foreground group-focus-visible/project:opacity-100" />
|
||||
</button>
|
||||
{active && <CodingProjectConversations key={project.id} projectId={project.id} compact={workspaceLayout} />}
|
||||
@@ -794,7 +796,7 @@ export function Sidebar({
|
||||
onOpenChange={setProfileDialogOpen}
|
||||
/>
|
||||
|
||||
<div className="mt-auto px-2 pb-2 pt-1">
|
||||
<div className="classroom-account-footer mt-auto shrink-0 px-2 pb-2 pt-1">
|
||||
<div className="relative">
|
||||
<div className={cn(
|
||||
'flex items-center gap-2',
|
||||
|
||||
@@ -70,7 +70,7 @@ export function CodingProjectConversations({ projectId, compact = false }: { pro
|
||||
className={compact ? "py-1" : "ml-5 py-1 pl-1"}
|
||||
data-testid="project-conversations"
|
||||
>
|
||||
<div className="flex items-center gap-1 text-muted-foreground">
|
||||
<div className="classroom-conversation-actions flex items-center gap-1 text-muted-foreground">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="新建对话"
|
||||
@@ -119,7 +119,8 @@ export function CodingProjectConversations({ projectId, compact = false }: { pro
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`group/session flex items-center rounded-lg ${selected === item.id ? 'bg-[#e7e9e1]' : 'hover:bg-surface-tertiary'}`}
|
||||
data-selected={selected === item.id}
|
||||
className={`classroom-conversation-row group/session flex items-center rounded-lg ${selected === item.id ? 'bg-[#e7e9e1]' : 'hover:bg-surface-tertiary'}`}
|
||||
>
|
||||
<button
|
||||
className="flex min-w-0 flex-1 items-center gap-1.5 px-2 py-2 text-left text-xs"
|
||||
|
||||
@@ -370,8 +370,8 @@ export function TeacherChatPanel({
|
||||
return (
|
||||
<aside className={cn('consultation-pane flex h-full min-h-0 w-full flex-col', role === 'friend' && 'consultation-friend')}
|
||||
data-testid="teacher-chat-panel" data-role={role ?? 'teacher'} aria-label={`${label}聊天`}>
|
||||
<header className="flex h-[68px] shrink-0 items-center gap-3 px-5">
|
||||
<img className="h-9 w-9 rounded-xl [image-rendering:pixelated]" src={avatar} alt="" />
|
||||
<header className="consultation-header flex h-[68px] shrink-0 items-center gap-3 px-5">
|
||||
<img className="consultation-avatar h-9 w-9 rounded-xl [image-rendering:pixelated]" src={avatar} alt="" />
|
||||
<div className="min-w-0 flex-1"><h2 className="truncate text-sm font-semibold">{definition?.name ?? (role === 'friend' ? '小麦' : '麦洛老师')}</h2>
|
||||
<p className="mt-1 text-[11px] text-muted-foreground">{draftRevision ? '运营草稿试聊' : role === 'friend' ? '陪你体验,也听你说' : !role ? '结合当前会话和项目文件答疑' : '一起想清楚,再动手'}</p></div>
|
||||
{onExpand && <button className="consult-icon" aria-label={expanded ? '恢复咨询栏宽度' : '展开咨询栏'} onClick={onExpand}><Maximize2 className="h-4 w-4" /></button>}
|
||||
|
||||
@@ -1,22 +1,57 @@
|
||||
/* The classroom surface follows the approved quiet project/chat prototype. */
|
||||
[data-testid="sidebar"][data-classroom="true"] { background: #f5f5f1; border-color: #e9eae3; box-shadow: none; backdrop-filter: none; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="project-conversations"] { font-size: 13px; }
|
||||
[data-testid="coding-conversation-header"] { border-bottom-color: #eceee7; background: #fff; }
|
||||
.classroom-workspace { --background: 0 0% 100%; --foreground: 98 9% 22%; --muted-foreground: 94 6% 47%; --border: 85 15% 89%; }
|
||||
.classroom-tabs { display: flex; flex-shrink: 0; height: 44px; gap: 26px; padding: 0 26px; border-bottom: 1px solid #eceee7; }
|
||||
.classroom-tabs button { display: flex; align-items: center; gap: 7px; position: relative; padding: 0 2px; font-size: 12px; color: #8a9083; }
|
||||
.classroom-tabs button[aria-selected="true"] { color: #414e38; }
|
||||
.classroom-tabs button[aria-selected="true"]::after { content: ''; position: absolute; bottom: -1px; left: 0; right: 0; height: 2px; background: #647357; border-radius: 2px; }
|
||||
/* Approved playful Code workbench. Keep navigation skins scoped to /chat. */
|
||||
[data-testid="main-layout"][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="sidebar"][data-classroom="true"] { background: #f3f7fb; border-color: #dde5ee; box-shadow: none; backdrop-filter: none; color: #26384d; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-brand { gap: 10px; padding: 10px 2px 12px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-brand:hover { background: #eaf1f8; }
|
||||
.classroom-brand-mark { display: grid; place-items: center; width: 40px; height: 42px; flex-shrink: 0; border: 1px solid #f1d1aa; border-radius: 12px; background: #fff0dd; box-shadow: 0 3px 0 #ecdbc5; }
|
||||
.classroom-brand-caption { display: block; margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: #64758a; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-sidebar-content { padding: 4px 12px 14px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="sidebar-create-project"] { min-height: 41px; gap: 9px; padding: 8px 11px; border: 1px solid #d5e1ed; border-radius: 11px; background: #fff; color: #304968; box-shadow: 0 3px 0 #e3eaf3; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="sidebar-create-project"] svg { color: #c44b23; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="sidebar-create-project"]:hover { background: #fff7ef; border-color: #ecc5a5; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-projects { margin-top: 20px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-projects-heading { padding: 6px 3px; color: #64758a; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-projects-heading > svg { display: none; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-project-card { min-height: 56px; gap: 9px; padding: 8px; border: 1px solid transparent; border-radius: 13px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-project-card:hover { background: #fff; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-project-card[aria-current="page"] { background: #fff; border-color: #c9d9e9; box-shadow: 0 3px 0 #e2eaf3; }
|
||||
.classroom-project-icon { display: grid; place-items: center; flex-shrink: 0; width: 34px; height: 37px; border-radius: 10px; background: #ffead9; color: #a85026; }
|
||||
.classroom-project-icon svg { width: 21px; height: 21px; }
|
||||
.classroom-project-icon[data-tone="green"] { background: #e1f1d9; color: #507d39; }
|
||||
.classroom-project-icon[data-tone="blue"] { background: #deedfb; color: #3a6d9d; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="project-conversations"] { padding: 8px 0 4px; font-size: 13px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-actions { gap: 2px; margin-bottom: 4px; color: #64758a; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-actions button { min-height: 32px; min-width: 30px; border-radius: 8px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-actions button:hover { background: #e5edf6; color: #36557b; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-row { margin: 3px 0; border: 1px solid transparent; border-radius: 10px; color: #64758a; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-row:hover { background: #eaf1f8; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-row[data-selected="true"] { background: #e0ecfa; border-color: #cedef0; color: #304f75; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-row > button:first-child { min-height: 35px; gap: 7px; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-conversation-row > button:first-child > svg { color: #7891af; }
|
||||
[data-testid="sidebar"][data-classroom="true"] .classroom-account-footer { padding: 10px 10px 12px; border-top: 1px solid #dde5ee; background: #edf3f9; }
|
||||
[data-testid="sidebar"][data-classroom="true"] [data-testid="sidebar-member-menu-trigger"] { min-height: 42px; border: 1px solid #d9e3ee; border-radius: 11px; background: #fff; font-size: 12px; }
|
||||
.classroom-workspace [data-testid="coding-conversation-header"] { border-bottom-color: #e8edf3; background: #fff; color: #304968; }
|
||||
.classroom-tabs { display: flex; flex-shrink: 0; height: 46px; gap: 9px; padding: 6px 22px; border-bottom: 1px solid #e8edf3; }
|
||||
.classroom-tabs button { display: flex; align-items: center; gap: 7px; position: relative; padding: 0 12px; border: 1px solid transparent; border-radius: 9px; background: #f4f7fa; font-size: 12px; color: #62738b; }
|
||||
.classroom-tabs button:hover { background: #eaf1f8; }
|
||||
.classroom-tabs button[aria-selected="true"] { background: #eaf1fb; border-color: #ccdaeb; color: #36557b; box-shadow: 0 2px 0 #dce6f3; }
|
||||
.classroom-chat-view:not([hidden]), .classroom-work-view:not([hidden]) { display: flex; }
|
||||
.classroom-chat-view[hidden], .classroom-work-view[hidden] { display: none; }
|
||||
.classroom-workspace [data-testid="coding-message-composer"] { max-width: 740px; padding-bottom: 22px; }
|
||||
.classroom-workspace .chat-composer-surface { border-color: #dddfd6; border-radius: 17px; box-shadow: 0 2px 8px #29392005; }
|
||||
.classroom-workspace .chat-composer-surface { border-color: #d3dfeb; border-bottom-width: 3px; border-radius: 14px; box-shadow: 0 3px 12px #3a557806; }
|
||||
.classroom-workspace [data-testid="coding-conversation-timeline"] { padding-top: 30px; }
|
||||
.classroom-work-view [data-testid="agent-browser-panel"] { border: 1px solid #e5e8de; border-radius: 12px; }
|
||||
.classroom-consultation-dock { border-color: #e3e7dc; max-width: min(55vw, 640px); }
|
||||
.classroom-work-view [data-testid="agent-browser-panel"] { border: 1px solid #dce5ef; border-radius: 12px; }
|
||||
.classroom-consultation-dock { border-color: #dde5ee; max-width: min(55vw, 640px); }
|
||||
.classroom-consultation-resizer { position: absolute; inset: 0 auto 0 -4px; width: 8px; z-index: 2; cursor: col-resize; }
|
||||
.classroom-consultation-resizer:hover, .classroom-consultation-resizer:focus-visible { background: #82986733; }
|
||||
.consultation-pane { background: #fafbf7; color: #434f3a; }
|
||||
.classroom-consultation-resizer:hover, .classroom-consultation-resizer:focus-visible { background: #7994b533; }
|
||||
.consultation-pane { background: #fffdf8; color: #30465f; }
|
||||
.classroom-workspace .consultation-header { height: 78px; padding: 12px 15px; gap: 10px; border-bottom: 1px solid #eddbb2; background: #fff4d9; }
|
||||
.classroom-workspace .consultation-avatar { width: 44px; height: 44px; flex-shrink: 0; border: 2px solid white; border-radius: 11px; box-shadow: 0 3px 0 #e3cea2; }
|
||||
.classroom-workspace .consultation-friend .consultation-header { background: #f7efdf; }
|
||||
.consultation-help-prompt, .consultation-guided-help { color: #536747; }
|
||||
.consultation-help-prompt { background: #f1f5ea; border: 1px solid #dfe7d5; }
|
||||
.consultation-help-prompt:hover:not(:disabled) { background: #e6eedc; border-color: #bacba8; }
|
||||
@@ -34,7 +69,7 @@
|
||||
.consultation-friend .consultation-suggestion { color: #8b7657; }
|
||||
.consultation-friend .consultation-suggestion:hover, .consultation-friend .consult-icon:hover { background: #f4eddf; }
|
||||
.consultation-friend .consultation-send { background: #8c7858; }
|
||||
@media (max-width: 1100px) { .classroom-tabs { padding: 0 18px; } }
|
||||
@media (max-width: 1100px) { .classroom-tabs { padding-left: 18px; padding-right: 18px; } }
|
||||
@media (max-width: 900px) { .classroom-consultation-dock { position: absolute; inset: 0 0 0 auto; z-index: 45; max-width: 100%; box-shadow: -12px 0 36px #24311b0d; } .classroom-consultation-resizer { display: none; } }
|
||||
@media (max-width: 600px) { .classroom-consultation-dock { width: 100%!important; } .classroom-workspace [data-testid="coding-message-composer"] { width: calc(100% - 24px); } }
|
||||
@media (prefers-reduced-motion: reduce) { .classroom-workspace *, .consultation-pane * { scroll-behavior: auto!important; } }
|
||||
|
||||
Reference in New Issue
Block a user