From 0c7def31aa864c8f7d6e4b01b824c8db628cb8b6 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 4 Jun 2026 17:38:10 -0500 Subject: [PATCH] feat(desktop): show "+" in the rail for single-profile users Always mount the profile rail, but when only the default profile exists render just the create-profile "+" (hide the default/all toggle, the draggable squares, and Manage). Gives a first-profile affordance without the full switcher chrome; everything else appears once a 2nd profile exists. --- apps/desktop/src/app/chat/sidebar/index.tsx | 2 +- .../src/app/chat/sidebar/profile-switcher.tsx | 88 ++++++++++--------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index 986387fa7..e31dae018 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -737,7 +737,7 @@ export function ChatSidebar({ {sidebarOpen && !showSessionSections &&
} - {multiProfile && sidebarOpen && ( + {sidebarOpen && (
diff --git a/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx b/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx index bd685ac15..f5ccd632c 100644 --- a/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx +++ b/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx @@ -73,8 +73,9 @@ const stepThroughCells: Modifier = ({ containerNodeRect, draggingNodeRect, trans // Arc-Spaces-style profile rail at the sidebar foot: a default↔all toggle pinned // left, the colored named profiles scrolling between, and Manage pinned right. -// The active profile pops in its own color — the "where am I" cue. Only mounted -// when >1 profile exists, so single-profile users never see it. +// The active profile pops in its own color — the "where am I" cue. Single- +// profile users see only the "+" (create their first profile); everything else +// appears once a second profile exists. export function ProfileRail() { const profiles = useStore($profiles) const scope = useStore($profileScope) @@ -116,6 +117,7 @@ export function ProfileRail() { const onDefault = !isAll && activeKey === 'default' const named = sortByProfileOrder(profiles.filter(profile => !profile.is_default), order) + const multiProfile = profiles.length > 1 // distance constraint: a small drag reorders, a tap still selects the profile. const sensors = useSensors( @@ -166,48 +168,52 @@ export function ProfileRail() { return (
{/* One button toggles default ↔ all: home face when scoped to a profile, - layers face when showing everything. Pinned left like Manage is right. */} - {defaultProfile ? ( - // On default → toggle to all. Anywhere else (all view or a named - // profile) → return to default. So leaving a profile never lands on all. - (onDefault ? setShowAllProfiles(true) : selectProfile(defaultProfile.name))} - /> - ) : ( - setShowAllProfiles(true)} /> - )} + layers face when showing everything. Pinned left like Manage is right. + Hidden until a second profile exists. */} + {multiProfile && + (defaultProfile ? ( + // On default → toggle to all. Anywhere else (all view or a named + // profile) → return to default. So leaving a profile never lands on all. + (onDefault ? setShowAllProfiles(true) : selectProfile(defaultProfile.name))} + /> + ) : ( + setShowAllProfiles(true)} /> + ))}
- - profile.name)} strategy={horizontalListSortingStrategy}> - {/* relative → the strip is the dragged square's offsetParent, so the - clamp modifier bounds drags to the occupied cells (not the +). */} -
- {named.map(profile => ( - selectProfile(profile.name)} - /> - ))} -
-
-
+ {multiProfile && ( + + profile.name)} strategy={horizontalListSortingStrategy}> + {/* relative → the strip is the dragged square's offsetParent, so the + clamp modifier bounds drags to the occupied cells (not the +). */} +
+ {named.map(profile => ( + selectProfile(profile.name)} + /> + ))} +
+
+
+ )}
- navigate(PROFILES_ROUTE)} /> + {multiProfile && ( + navigate(PROFILES_ROUTE)} /> + )} setCreateOpen(false)} onCreated={refreshActiveProfile} open={createOpen} />