feat(frontend): rebuild the workspace shell on shadcn sidebar + site header - #570
Open
Ashin-LX-98 wants to merge 3 commits into
Open
feat(frontend): rebuild the workspace shell on shadcn sidebar + site header#570Ashin-LX-98 wants to merge 3 commits into
Ashin-LX-98 wants to merge 3 commits into
Conversation
…header - App shell: icon-rail sidebar (brand, nav, agents, rail toggle) plus a new h-12 site header with breadcrumbs, cmd-K search, notifications and the account menu. Replaces sidebar/sidebar-content/sidebar-header; the settings dialog is extracted so the header menu can own it. - Lands sidebar, breadcrumb, popover, command, input-group and skeleton from the shadcn radix-nova registry by hand — the CLI would have overwritten eight existing ReUI components (dialog, button, sheet, ...). Adds the --sidebar-* tokens and cmdk. - Panes sit flush against the rail with 1px dividers instead of floating cards, and every pane header is h-12 with a shared bottom border. - Share, create-routine and invitation dialogs follow the pinned header/body/footer spec and use design tokens instead of hardcoded zinc/blue. - Confirm and prompt flows move to the shared dialogs provider.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
zomux
approved these changes
Jul 28, 2026
zomux
left a comment
Contributor
There was a problem hiding this comment.
Approve with minor changes — solid, well-documented app-shell refactor; mostly presentational and tsc/build pass.
Would like addressed before merge:
command.tsx: DialogHeader/DialogTitle are rendered as siblings of DialogContent rather than inside it. aria wiring still works via Radix context, but Dialog.Root always renders children, so this leaves a persistent sr-only heading in the DOM when the palette is closed and diverges from the idiomatic shadcn pattern. Move the header inside DialogContent.
Worth a manual check:
notifications-menu.tsxhandleNavigate only navigates when notification.channelName exactly equals a sessionId — if those are different id spaces, clicking a notification silently no-ops. Please click through against real notifications.
Nits (non-blocking):
settings-dialog.tsxcollaborators list keeps a nestedmax-h-40 overflow-y-autoscroll region, contradicting the 'DialogBody is the only scroll region' convention applied to invitation-dialog.- components.json adds a third-party registry proxy (proxy.collectui.pro) with a bearer license key — only matters for future
npx shadcn add, but confirm the proxy/license is trusted. - Controlled SidebarProvider still writes the sidebar_state cookie that's never read back; mobile mounts a second global Cmd+B listener toggling an unused openMobile.
Verified fine: no Cmd+K/Cmd+B collision; showCloseButton / NotificationCard.onNavigate / useIsMobile all exist on-branch; rail CSS vars inherit into the fixed handle; AppSidebar gated behind !isDetailExpanded; data-active v4 fix is correct.
Replaces the sidebar + site-header shell with ReUI's app-shell-4 pattern: one `collapsible="icon"` shell holding two inner sidebars — a permanent icon rail and a 440px list panel — beside a single action header. - Rail (nav-rail) owns view navigation, agent presence and the global tools (search, notifications, account). Replaces nav-main/nav-agents/brand on desktop; the mobile sheet still uses them. - List panel (list-panel) hosts the per-view list. Threads is rebuilt on the MailItem pattern: header + search row + filter tabs (All/Starred/Archived/ DMs) + rich preview rows. Archived and DM sections become tabs. - One action header (app-header) replaces every per-view header bar: expand control, prev/next navigation through the current list, the selected item's title, and a toolbar each view fills through a portal (AppHeaderActions), so view logic stays in the view. Deletes site-header. - Knowledge is split into list + detail so it uses the shell instead of re-implementing a split view, which also gives it collapse for free. Skills and FileGrid fold their title rows into the header. - Threads gain real unread state. The backend has no per-thread read marker, so it is derived client-side from activity vs. last-opened, persisted in localStorage and baselined on first visit. lastEventAt comes back null on some workspaces, so activity falls back to createdAt plus an observed preview-change signal. The rail dot and row dots now mean unread instead of "list is non-empty" and "running". - List collapse is remembered per view in a cookie, so switching views or reloading no longer resets it. The sidebar's own sidebar_state cookie was never read back under controlled usage. Also lands the radix-nova tabs component by hand and fixes two defects it surfaced: tabs shipped `data-active:` variants that never match Radix's `data-state="active"`, and the rail's icon buttons had no accessible name.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Rebuilds the workspace desktop shell around the ReUI app-shell-12 block, without installing the block itself.
App shell
collapsible="icon") built fromBrand/NavMain/NavAgents/NavSecondary, plus the app-shell-12 rail handle (two bars that splay on hover with a Collapse/Expand label). Replacessidebar.tsx/sidebar-content.tsx/sidebar-header.tsx; nav counts and the agent list keep their previous behaviour.h-12bar with breadcrumbs (view + current thread/file), a Cmd-K command palette over threads/files/agents, a notifications popover reusing the Inbox card, and the account menu (theme, copy token, claim workspace, settings, sign in/out). Mobile gets the notifications + account menus inMobileHeaderso nothing that lived in the old sidebar footer is lost.SidebarProvideris controlled by the existinguseLayout().isSidebarOpen, so every other caller is untouched.Registry components landed by hand
npx shadcn add sidebar breadcrumb popover command skeletonwould have overwritten 8 existing files (dialog,button,sheet,tooltip,input,textarea,separator,hooks/use-mobile) —dialog.tsxcarries this repo's pinned header/footer contract andbutton.tsxdiffers from upstream by ~480 lines. So the six new files were extracted from the registry JSON and adapted instead: registry import paths rewritten, the brokenIconPlaceholderimport swapped for lucide icons, andsize="icon-sm"mapped to this Button'ssize="icon".--sidebar-*tokens (light + dark) were added toglobals.css;cmdkis the only new dependency.Layout & dialogs
rounded-xlcards, and every pane header ish-12with a shared bottom border, so the site header, list pane and detail pane line up.share-dialog,create-routine-dialogandinvitation-dialognow follow the dialog spec — actions live in a pinnedDialogFooter,DialogBodyis the only scroll region, and hardcodedzinc-*/blue-500/red-500are replaced by design tokens. Nativeconfirm/promptcalls move to the shared dialogs provider.Notes
data-active={isActive}in the upstreamsidebar.tsxrendersdata-active="false", which Tailwind v4'sdata-active:variant still matches — every menu item rendered as selected. Fixed toisActive || undefined.CommandDialogdoes not include a cmdk root, soSearchMenuwraps its children in<Command>itself.components.jsonis added with the@reuiregistry; the license key stays in.env.local(gitignored).Testing
npx tsc --noEmitcleannpm run buildsucceeds🤖 Generated with Claude Code