Skip to content

Commit db7ea1f

Browse files
danielclickhclaudedustinhealy
authored
🎨 style: Improved Sidebar, Accordion, and Help Page UI (#3)
* feat(admin-panel): UI adjustments — sidebar, accordion, help page - Sidebar: add LibreChat logo + "Admin Panel" branding, set expanded width to 252px, persist collapsed state in localStorage, move toggle button to bottom with slide-in/slide-out icons, tighten nav item spacing - Configuration: replace custom sections with MultiAccordion (showBorder, showCheck=false), remove AI Providers outer wrapper so each provider is a direct accordion item, scope Expand/Collapse All to top-level only using data-top-level-accordion + :scope selectors and dispatchEvent to avoid focus/scroll side effects - Header: remove subtitle description line from all pages - Help: rename page title to "Help", make resource cards full width Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: copy librechat.svg to correct asset path The SVG was committed to experimental/admin-panel/src/assets/ instead of src/assets/ where the Sidebar import expects it. * fix(sidebar): prevent logo and avatar shift on expand/collapse Use fixed-width inner wrapper (w-9 justify-center) for both the logo and user avatar sections, matching the nav item pattern. This keeps icons at a stable position during the sidebar width transition instead of centering them in the animating container. * fix(dashboard): make nav tips full width and update wording Remove max-w-lg from the Getting Around section so it spans the full content area. Change command menu tip from "without navigating away" to "within the menu". * fix(import): remove extra focusable element in import dialog Add tabIndex={-1} to Tabs.Content panels so the tab panel container is no longer an unexpected focus stop when tabbing through the dialog. * fix(header): remove unused description param and convert to named export The description subtitle was removed from the header UI but the param was left in place, causing ESLint and TypeScript errors. Also converts to a named export per project conventions. * chore: remove stale experimental/ directory The SVG was committed to experimental/admin-panel/src/assets/ by mistake. The correct copy is at src/assets/librechat.svg. * chore: sort imports --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
1 parent f864b77 commit db7ea1f

15 files changed

Lines changed: 289 additions & 268 deletions

File tree

‎src/assets/librechat.svg‎

Lines changed: 32 additions & 0 deletions
Loading

‎src/components/Header.tsx‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type * as t from '@/types';
22
import { useLocalize } from '@/hooks';
33

4-
export default function Header({ title, description, onSearchClick, children }: t.HeaderProps) {
4+
export function Header({ title, onSearchClick, children }: t.HeaderProps) {
55
const localize = useLocalize();
66
const isMac =
77
typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);
@@ -16,9 +16,6 @@ export default function Header({ title, description, onSearchClick, children }:
1616
) : (
1717
<div />
1818
)}
19-
{description && (
20-
<p className="text-xs text-(--cui-color-text-muted)">{description}</p>
21-
)}
2219
</div>
2320
<div className="flex min-w-0 flex-1 items-center justify-end gap-2">
2421
{children}

‎src/components/Sidebar.tsx‎

Lines changed: 82 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Icon, Dropdown } from '@clickhouse/click-ui';
33
import { Link, useRouter } from '@tanstack/react-router';
44
import type * as t from '@/types';
55
import { useStripAriaExpanded, useCapabilities, useLocalize } from '@/hooks';
6-
import { SidebarIcon } from '@/components/shared';
6+
import libreChatLogo from '@/assets/librechat.svg';
77
import { SettingsDialog } from './SettingsDialog';
88
import { SystemCapabilities } from '@/constants';
99
import { getInitials, cn } from '@/utils';
@@ -79,31 +79,24 @@ export function Sidebar({ user, collapsed, onToggle }: t.SidebarProps) {
7979
aria-label={localize('com_a11y_admin_panel')}
8080
className={cn(
8181
'sticky top-0 z-(--z-floating) flex h-screen shrink-0 flex-col overflow-hidden border-r border-(--cui-color-stroke-default) bg-(--cui-color-background-panel) transition-[width] duration-200',
82-
collapsed ? 'w-14' : 'w-46',
82+
collapsed ? 'w-14' : 'w-63',
8383
)}
8484
>
85-
<div className="shrink-0 px-2 py-2 pt-4">
86-
<button
87-
type="button"
88-
onClick={onToggle}
89-
aria-label={localize(collapsed ? 'com_nav_expand_sidebar' : 'com_nav_collapse_sidebar')}
90-
title={localize(collapsed ? 'com_nav_expand_sidebar' : 'com_nav_collapse_sidebar')}
91-
className={cn(
92-
'flex h-9 cursor-pointer items-center rounded-lg border-none bg-transparent text-(--cui-color-text-muted) transition-colors hover:bg-(--cui-color-background-hover) hover:text-(--cui-color-text-default)',
93-
collapsed ? 'w-9 justify-center' : 'gap-3 pr-2.5 pl-2',
94-
)}
85+
<div className="flex h-14 shrink-0 items-center px-2">
86+
<div
87+
className={cn('flex items-center', collapsed ? 'w-9 justify-center' : 'gap-2.5 px-1.5')}
9588
>
96-
<span aria-hidden="true" className="shrink-0">
97-
<SidebarIcon className="h-5 w-5" />
98-
</span>
89+
<img src={libreChatLogo} alt="LibreChat" className="h-6 w-6 shrink-0" />
9990
{!collapsed && (
100-
<span className="truncate text-sm">{localize('com_nav_collapse_sidebar')}</span>
91+
<span className="flex-1 truncate text-sm font-semibold text-(--cui-color-text-default)">
92+
Admin Panel
93+
</span>
10194
)}
102-
</button>
95+
</div>
10396
</div>
10497

105-
<nav className="flex-1 overflow-y-auto px-2 pt-2" role="navigation">
106-
<div className="flex flex-col gap-1">
98+
<nav className="flex-1 overflow-y-auto px-2 py-2" role="navigation">
99+
<div className="flex flex-col gap-0.5">
107100
{visibleItems.map((item) => (
108101
<Link
109102
key={item.path}
@@ -112,8 +105,8 @@ export function Sidebar({ user, collapsed, onToggle }: t.SidebarProps) {
112105
aria-label={collapsed ? localize(item.labelKey) : undefined}
113106
title={collapsed ? localize(item.labelKey) : undefined}
114107
className={cn(
115-
'flex h-9 items-center rounded-lg text-sm no-underline transition-colors duration-100',
116-
collapsed ? 'w-9 justify-center' : 'gap-3 px-2.5',
108+
'flex h-8 items-center rounded-md text-sm no-underline transition-colors duration-100',
109+
collapsed ? 'w-9 justify-center' : 'gap-2.5 px-2.5',
117110
isActive(item.path)
118111
? 'bg-(--cui-color-background-active) font-medium text-(--cui-color-text-default)'
119112
: 'font-normal text-(--cui-color-text-muted) hover:bg-(--cui-color-background-hover) hover:text-(--cui-color-text-default)',
@@ -129,68 +122,80 @@ export function Sidebar({ user, collapsed, onToggle }: t.SidebarProps) {
129122
</nav>
130123

131124
{initials && (
132-
<div
133-
className={cn(
134-
'flex shrink-0 items-center border-t border-(--cui-color-stroke-default) py-3',
135-
collapsed ? 'justify-center' : 'px-3',
136-
)}
137-
>
138-
<Dropdown>
139-
<Dropdown.Trigger>
140-
<button
141-
ref={userMenuRef}
142-
type="button"
143-
className="flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-full border border-(--cui-color-stroke-default) bg-(--cui-color-background-default) transition-colors hover:border-(--cui-color-stroke-intense) hover:bg-(--cui-color-background-hover)"
144-
aria-label={`${localize('com_nav_user_menu')}, ${user?.name || user?.email || ''}`}
145-
aria-haspopup="true"
146-
title={user?.name || user?.email || ''}
147-
>
148-
<span
149-
aria-hidden="true"
150-
className="text-xs font-medium text-(--cui-color-text-muted)"
125+
<div className="flex shrink-0 items-center border-t border-(--cui-color-stroke-default) px-2 py-3">
126+
<div
127+
className={cn(
128+
'flex items-center',
129+
collapsed ? 'w-9 justify-center' : 'gap-2.5 px-0.5',
130+
)}
131+
>
132+
<Dropdown>
133+
<Dropdown.Trigger>
134+
<button
135+
ref={userMenuRef}
136+
type="button"
137+
className="flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-full border border-(--cui-color-stroke-default) bg-(--cui-color-background-default) transition-colors hover:border-(--cui-color-stroke-intense) hover:bg-(--cui-color-background-hover)"
138+
aria-label={`${localize('com_nav_user_menu')}, ${user?.name || user?.email || ''}`}
139+
aria-haspopup="true"
140+
title={user?.name || user?.email || ''}
151141
>
152-
{initials}
153-
</span>
154-
</button>
155-
</Dropdown.Trigger>
156-
<Dropdown.Content>
157-
<div className="user-dropdown flex min-w-45 flex-col select-none">
158-
{user && (
159-
<div className="px-3 pt-3 pb-2">
160-
<span className="block text-sm leading-tight font-medium text-(--cui-color-text-default)">
161-
{user.name || ''}
162-
</span>
163-
{user.email && (
164-
<span className="mt-0.5 block text-xs leading-tight text-(--cui-color-text-muted)">
165-
{user.email}
142+
<span
143+
aria-hidden="true"
144+
className="text-xs font-medium text-(--cui-color-text-muted)"
145+
>
146+
{initials}
147+
</span>
148+
</button>
149+
</Dropdown.Trigger>
150+
<Dropdown.Content>
151+
<div className="user-dropdown flex min-w-45 flex-col select-none">
152+
{user && (
153+
<div className="px-3 pt-3 pb-2">
154+
<span className="block text-sm leading-tight font-medium text-(--cui-color-text-default)">
155+
{user.name || ''}
166156
</span>
167-
)}
168-
</div>
157+
{user.email && (
158+
<span className="mt-0.5 block text-xs leading-tight text-(--cui-color-text-muted)">
159+
{user.email}
160+
</span>
161+
)}
162+
</div>
163+
)}
164+
<div className="border-t border-(--cui-color-stroke-default)" />
165+
<Dropdown.Item icon="settings" onClick={() => setSettingsOpen(true)}>
166+
{localize('com_ui_settings')}
167+
</Dropdown.Item>
168+
<Dropdown.Item icon="slide-out" onClick={handleLogout} disabled={isLoggingOut}>
169+
{isLoggingOut ? localize('com_ui_signing_out') : localize('com_ui_sign_out')}
170+
</Dropdown.Item>
171+
</div>
172+
</Dropdown.Content>
173+
</Dropdown>
174+
{!collapsed && user && (
175+
<div className="min-w-0 flex-1">
176+
<span className="block truncate text-sm leading-tight font-medium text-(--cui-color-text-default)">
177+
{user.name || ''}
178+
</span>
179+
{user.email && (
180+
<span className="block truncate text-xs leading-tight text-(--cui-color-text-muted)">
181+
{user.email}
182+
</span>
169183
)}
170-
<div className="border-t border-(--cui-color-stroke-default)" />
171-
<Dropdown.Item icon="settings" onClick={() => setSettingsOpen(true)}>
172-
{localize('com_ui_settings')}
173-
</Dropdown.Item>
174-
<Dropdown.Item icon="slide-out" onClick={handleLogout} disabled={isLoggingOut}>
175-
{isLoggingOut ? localize('com_ui_signing_out') : localize('com_ui_sign_out')}
176-
</Dropdown.Item>
177184
</div>
178-
</Dropdown.Content>
179-
</Dropdown>
180-
{!collapsed && user && (
181-
<div className="ml-2 min-w-0 flex-1">
182-
<span className="block truncate text-sm leading-tight font-medium text-(--cui-color-text-default)">
183-
{user.name || ''}
184-
</span>
185-
{user.email && (
186-
<span className="block truncate text-xs leading-tight text-(--cui-color-text-muted)">
187-
{user.email}
188-
</span>
189-
)}
190-
</div>
191-
)}
185+
)}
186+
</div>
192187
</div>
193188
)}
189+
190+
<button
191+
type="button"
192+
onClick={onToggle}
193+
aria-label={localize(collapsed ? 'com_nav_expand_sidebar' : 'com_nav_collapse_sidebar')}
194+
title={localize(collapsed ? 'com_nav_expand_sidebar' : 'com_nav_collapse_sidebar')}
195+
className="flex w-full shrink-0 cursor-pointer items-center justify-center border-t border-(--cui-color-stroke-default) bg-transparent py-3 text-(--cui-color-text-muted) transition-colors hover:bg-(--cui-color-background-hover) hover:text-(--cui-color-text-default)"
196+
>
197+
<Icon name={collapsed ? 'slide-in' : 'slide-out'} size="sm" />
198+
</button>
194199
</aside>
195200

196201
<SettingsDialog open={settingsOpen} onClose={() => setSettingsOpen(false)} />

‎src/components/configuration/ConfigPage.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import {
2626
getTabsWithPermission,
2727
} from '@/utils';
2828
import { useLocalize, useHighlightRef, useActiveSection, useCapabilities } from '@/hooks';
29-
import { ScopeSelector, ScopeTriggerButton } from './ScopeSelector';
3029
import { CONFIG_TABS, OTHER_TAB, SECTION_META, HIDDEN_SECTIONS } from './configMeta';
30+
import { ScopeSelector, ScopeTriggerButton } from './ScopeSelector';
3131
import { ConfigTableOfContents } from './ConfigTableOfContents';
3232
import { ConfirmSaveDialog } from './ConfirmSaveDialog';
3333
import { StickyActionBar } from '@/components/shared';

0 commit comments

Comments
 (0)