Skip to content

Commit a58c1dc

Browse files
author
Test
committed
🤖 refactor: move mobile sidebar toggle to header
Replace bottom-right FAB with a header button for better accessibility: - Add panel icon button next to terminal button in WorkspaceHeader - Only visible on mobile (max-md breakpoint) - Remove FAB that was blocking chat input area - Keep swipe gestures and backdrop overlay - Expose sidebar open function via callback prop chain The header button is more discoverable and doesn't interfere with other mobile UI elements like the chat input. _Generated with `cmux`_ Change-Id: Ib26964982a9872748bb43041a39f787f12974de1 Signed-off-by: Test <test@example.com>
1 parent 56edb98 commit a58c1dc

File tree

4 files changed

+41
-20
lines changed

4 files changed

+41
-20
lines changed

src/components/AIView.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ const AIViewInner: React.FC<AIViewProps> = ({
102102
chatInputAPI.current?.appendText(note);
103103
}, []);
104104

105+
// Ref to store the sidebar open function (for mobile header button)
106+
const openRightSidebarRef = useRef<(() => void) | null>(null);
107+
const handleOpenRightSidebar = useCallback(() => {
108+
openRightSidebarRef.current?.();
109+
}, []);
110+
105111
// Thinking level state from context
106112
const { thinkingLevel: currentWorkspaceThinking, setThinkingLevel } = useThinking();
107113

@@ -328,6 +334,7 @@ const AIViewInner: React.FC<AIViewProps> = ({
328334
branch={branch}
329335
namedWorkspacePath={namedWorkspacePath}
330336
runtimeConfig={runtimeConfig}
337+
onOpenRightSidebar={handleOpenRightSidebar}
331338
/>
332339

333340
<div className="relative flex-1 overflow-hidden">
@@ -482,6 +489,9 @@ const AIViewInner: React.FC<AIViewProps> = ({
482489
onStartResize={isReviewTabActive ? startResize : undefined} // Pass resize handler when Review active
483490
isResizing={isResizing} // Pass resizing state
484491
onReviewNote={handleReviewNote} // Pass review note handler to append to chat
492+
onMountOpenCallback={(openFn) => {
493+
openRightSidebarRef.current = openFn;
494+
}}
485495
/>
486496
</div>
487497
);

src/components/RightSidebar.tsx

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ interface RightSidebarProps {
8585
isResizing?: boolean;
8686
/** Callback when user adds a review note from Code Review tab */
8787
onReviewNote?: (note: string) => void;
88+
/** Callback to expose the open sidebar function (for mobile header button) */
89+
onMountOpenCallback?: (openFn: () => void) => void;
8890
}
8991

9092
const RightSidebarComponent: React.FC<RightSidebarProps> = ({
@@ -96,6 +98,7 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
9698
onStartResize,
9799
isResizing = false,
98100
onReviewNote,
101+
onMountOpenCallback,
99102
}) => {
100103
// Global tab preference (not per-workspace)
101104
const [selectedTab, setSelectedTab] = usePersistedState<TabType>("right-sidebar-tab", "costs");
@@ -187,6 +190,13 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
187190
const showMeter = showCollapsed || selectedTab === "review";
188191
const verticalMeter = showMeter ? <VerticalTokenMeter data={verticalMeterData} /> : null;
189192

193+
// Expose open function to parent (for mobile header button)
194+
React.useEffect(() => {
195+
if (onMountOpenCallback) {
196+
onMountOpenCallback(() => setShowCollapsed(false));
197+
}
198+
}, [onMountOpenCallback, setShowCollapsed]);
199+
190200
// Swipe gesture detection for mobile - right-to-left swipe to open sidebar
191201
React.useEffect(() => {
192202
// Only enable swipe on mobile when sidebar is collapsed
@@ -252,25 +262,6 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
252262

253263
return (
254264
<>
255-
{/* FAB - Floating Action Button for mobile, only visible when collapsed */}
256-
{showCollapsed && (
257-
<button
258-
onClick={() => setShowCollapsed(false)}
259-
title={`Open ${selectedTab} panel`}
260-
aria-label={`Open ${selectedTab} panel`}
261-
className={cn(
262-
"hidden max-md:flex fixed bottom-20 right-4 z-[998]",
263-
"w-12 h-12 bg-accent border border-accent rounded-full cursor-pointer",
264-
"items-center justify-center text-white text-lg transition-all duration-200",
265-
"shadow-[0_4px_12px_rgba(0,0,0,0.4)]",
266-
"hover:bg-accent-hover hover:scale-105",
267-
"active:scale-95"
268-
)}
269-
>
270-
{selectedTab === "costs" ? "💰" : "📋"}
271-
</button>
272-
)}
273-
274265
{/* Backdrop overlay - only on mobile when sidebar is expanded */}
275266
{!showCollapsed && (
276267
<div

src/components/WorkspaceHeader.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface WorkspaceHeaderProps {
1313
branch: string;
1414
namedWorkspacePath: string;
1515
runtimeConfig?: RuntimeConfig;
16+
onOpenRightSidebar?: () => void;
1617
}
1718

1819
export const WorkspaceHeader: React.FC<WorkspaceHeaderProps> = ({
@@ -21,6 +22,7 @@ export const WorkspaceHeader: React.FC<WorkspaceHeaderProps> = ({
2122
branch,
2223
namedWorkspacePath,
2324
runtimeConfig,
25+
onOpenRightSidebar,
2426
}) => {
2527
const gitStatus = useGitStatus(workspaceId);
2628
const handleOpenTerminal = useCallback(() => {
@@ -56,6 +58,24 @@ export const WorkspaceHeader: React.FC<WorkspaceHeaderProps> = ({
5658
Open in terminal ({formatKeybind(KEYBINDS.OPEN_TERMINAL)})
5759
</Tooltip>
5860
</TooltipWrapper>
61+
62+
{/* Open sidebar button - only visible on mobile */}
63+
{onOpenRightSidebar && (
64+
<TooltipWrapper inline>
65+
<button
66+
onClick={onOpenRightSidebar}
67+
className="text-muted hover:text-foreground hidden cursor-pointer items-center justify-center border-none bg-transparent p-1 transition-colors max-md:flex [&_svg]:h-4 [&_svg]:w-4"
68+
aria-label="Open costs and review panel"
69+
>
70+
<svg viewBox="0 0 16 16" fill="currentColor">
71+
<path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm1.75-.25a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25H9.5v-13H1.75zm12.5 13H11v-13h3.25a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25z" />
72+
</svg>
73+
</button>
74+
<Tooltip className="tooltip" position="bottom" align="center">
75+
Open review panel
76+
</Tooltip>
77+
</TooltipWrapper>
78+
)}
5979
</div>
6080
</div>
6181
);

vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default defineConfig(({ mode }) => ({
8585
host: devServerHost, // Configurable via CMUX_VITE_HOST (defaults to 127.0.0.1 for security)
8686
port: devServerPort,
8787
strictPort: true,
88-
allowedHosts: devServerHost === "0.0.0.0" ? undefined : ["localhost", "127.0.0.1"],
88+
allowedHosts: devServerHost === "0.0.0.0" ? [".ts.net"] : ["localhost", "127.0.0.1"],
8989
sourcemapIgnoreList: () => false, // Show all sources in DevTools
9090
},
9191
preview: {

0 commit comments

Comments
 (0)