fix(gui): keep sidebar controls when collapsed
This commit is contained in:
@@ -15,6 +15,28 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Closed state is a persistent rail: the layout reserves exactly the root's
|
||||
horizontal padding plus one icon control. */
|
||||
.root.collapsed {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.collapsed .headerBlock {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.collapsed .logoRow {
|
||||
justify-content: center;
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
.collapsed .foot {
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
margin-top: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Header block (figma 133:7630): logo row + New Session, gap 16, padBottom 12. */
|
||||
.headerBlock {
|
||||
flex: none;
|
||||
|
||||
@@ -24,12 +24,10 @@ const GROUP_BY_ITEMS = [
|
||||
{ id: 'status', label: 'Status', disabled: true },
|
||||
]
|
||||
|
||||
/**
|
||||
* Render the sidebar column.
|
||||
* @param props - composed slot props (owner share + injected surface, contract/slots.ts).
|
||||
* @returns the sidebar element tree.
|
||||
*/
|
||||
export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootComponentProps) {
|
||||
type SidebarBodyProps = Pick<SidebarRootComponentProps, 'useTree' | 'useCurrent' | 'actions' | 'tree'>
|
||||
|
||||
/** Expanded-only content; unmounting drops tree/current subscriptions while the rail is collapsed. */
|
||||
function SidebarBody({ useTree, useCurrent, actions, tree }: SidebarBodyProps) {
|
||||
const rows = useTree((s) => s.rows)
|
||||
const query = useTree((s) => s.query)
|
||||
const groupBy = useTree((s) => s.groupBy)
|
||||
@@ -47,32 +45,7 @@ export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootC
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={css.root}>
|
||||
<div className={css.headerBlock}>
|
||||
<div className={css.logoRow}>
|
||||
<span className={css.brand}>
|
||||
{/* Wordmark svg not extracted yet (figma 88:8932) — text stands in at the same ink. */}
|
||||
<FishLogo size={23} />
|
||||
<span className={css.wordmark}>deepseek</span>
|
||||
<span className={css.badge}>HARNESS</span>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className={css.iconButton}
|
||||
aria-label="Collapse sidebar"
|
||||
onClick={() => { actions.toggleSidebar() }}
|
||||
>
|
||||
<IconPanelLeftOutline16 />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" className={css.newSession} onClick={() => { actions.create() }}>
|
||||
<IconNewChatOutline16 size={14} />
|
||||
New Session
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={css.listArea}>
|
||||
<div className={css.listArea}>
|
||||
<div className={css.sectionHeader}>
|
||||
<span className={css.sectionLabel}>WorkSpace</span>
|
||||
<Menu
|
||||
@@ -153,11 +126,66 @@ export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootC
|
||||
))}
|
||||
</div>
|
||||
<span className={css.fade} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the sidebar column.
|
||||
* @param props - composed slot props (owner share + injected surface, contract/slots.ts).
|
||||
* @returns the sidebar element tree.
|
||||
*/
|
||||
export function SidebarRoot(props: SidebarRootComponentProps) {
|
||||
const open = props.useSidebarOpen()
|
||||
|
||||
return (
|
||||
<div className={clsx(css.root, !open && css.collapsed)}>
|
||||
<div className={css.headerBlock}>
|
||||
<div className={css.logoRow}>
|
||||
{open
|
||||
? (
|
||||
<span className={css.brand}>
|
||||
{/* Wordmark svg not extracted yet (figma 88:8932) — text stands in at the same ink. */}
|
||||
<FishLogo size={23} />
|
||||
<span className={css.wordmark}>deepseek</span>
|
||||
<span className={css.badge}>HARNESS</span>
|
||||
</span>
|
||||
)
|
||||
: null}
|
||||
<button
|
||||
type="button"
|
||||
className={css.iconButton}
|
||||
aria-label={open ? 'Collapse sidebar' : 'Expand sidebar'}
|
||||
onClick={() => { props.actions.toggleSidebar() }}
|
||||
>
|
||||
<IconPanelLeftOutline16 />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{open
|
||||
? (
|
||||
<button type="button" className={css.newSession} onClick={() => { props.actions.create() }}>
|
||||
<IconNewChatOutline16 size={14} />
|
||||
New Session
|
||||
</button>
|
||||
)
|
||||
: null}
|
||||
</div>
|
||||
|
||||
<div className={clsx(css.foot)} role="button" tabIndex={0} aria-label="Settings">
|
||||
{open
|
||||
? (
|
||||
<SidebarBody
|
||||
useTree={props.useTree}
|
||||
useCurrent={props.useCurrent}
|
||||
actions={props.actions}
|
||||
tree={props.tree}
|
||||
/>
|
||||
)
|
||||
: null}
|
||||
|
||||
<div className={css.foot} role="button" tabIndex={0} aria-label="Settings">
|
||||
<IconSettingsOutline14 />
|
||||
Settings
|
||||
{open ? <span>Settings</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -37,6 +37,8 @@ export type SidebarRootInjected = {
|
||||
useTree: SnapshotSelectorHook<SidebarTreeState>
|
||||
/** Current session selector (row highlight); undefined selects nothing. */
|
||||
useCurrent: () => SessionId | undefined
|
||||
/** Sidebar open selector; the collapsed render keeps only persistent rail controls. */
|
||||
useSidebarOpen: () => boolean
|
||||
actions: SidebarActions
|
||||
tree: SidebarTreeActions
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export function apply(ctx: ClientContext): void {
|
||||
return {
|
||||
useTree: tree.store.useSelector,
|
||||
useCurrent: () => layout.current.useSelector(s => s.sessionId),
|
||||
useSidebarOpen: () => layout.sidebar.useSelector(s => s.open),
|
||||
actions: {
|
||||
open: (id) => { layout.open(id) },
|
||||
create: (cwd) => {
|
||||
|
||||
Reference in New Issue
Block a user