Files
app/components/Navigation/DesktopSidebar.tsx
Albert 57d5405c41 feat: Move theme toggle to profile dropdown with icon-only SegmentedControl
Changes:
- Moved theme toggle from separate DesktopSidebar component into UserMenu dropdown
- Replaced simple light/dark toggle with SegmentedControl offering three options:
  - Light (sun icon)
  - Dark (moon icon)
  - System/Auto (desktop icon)
- Uses icon-only labels for compact display in dropdown menu
- Defaults to 'auto' mode (respects system preference) as configured in layout.tsx
- Removed standalone ThemeToggle component from DesktopSidebar

Benefits:
- Cleaner navigation UI with one less separate control
- Better UX with system preference option
- More compact dropdown menu layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 01:26:33 +00:00

142 lines
4.0 KiB
TypeScript

'use client';
/**
* Desktop Sidebar Navigation
*
* Vertical sidebar navigation for desktop (≥ 768px).
* Shows three navigation links: Convo, Edit, Galaxy
* Highlights the active mode based on app state machine.
*/
import { Stack, NavLink, Box, Title, Group, Divider, Text } from '@mantine/core';
import { IconMessageCircle, IconEdit, IconChartBubbleFilled } from '@tabler/icons-react';
import { useSelector } from '@xstate/react';
import { useAppMachine } from '@/hooks/useAppMachine';
import { UserMenu } from '@/components/UserMenu';
import styles from './DesktopSidebar.module.css';
export function DesktopSidebar() {
const actor = useAppMachine();
const state = useSelector(actor, (state) => state);
const send = actor.send;
const handleNavigation = (target: 'convo' | 'edit' | 'galaxy') => {
console.log('[Desktop Nav] Navigating to:', target);
if (target === 'convo') {
send({ type: 'NAVIGATE_TO_CONVO' });
} else if (target === 'edit') {
send({ type: 'NAVIGATE_TO_EDIT' });
} else if (target === 'galaxy') {
send({ type: 'NAVIGATE_TO_GALAXY' });
}
};
const isConvo = state.matches('convo');
const isEdit = state.matches('edit');
const isGalaxy = state.matches('galaxy');
console.log('[Desktop Nav] Current state:', state.value, {
isConvo,
isEdit,
isGalaxy,
});
return (
<Box className={styles.sidebar}>
<Stack gap="xs">
<Group gap="md" mb="lg" align="center" wrap="nowrap">
<img
src="/logo.svg"
alt="Ponderants logo"
width={32}
height={32}
style={{ flexShrink: 0, display: 'block' }}
/>
<Title order={3} style={{ margin: 0 }}>
Ponderants
</Title>
</Group>
<NavLink
label="Convo"
leftSection={<IconMessageCircle size={20} />}
active={isConvo}
onClick={() => handleNavigation('convo')}
variant="filled"
color="blue"
styles={{
root: {
borderRadius: '8px',
fontWeight: isConvo ? 600 : 400,
},
}}
/>
<NavLink
label="Manual"
leftSection={<IconEdit size={20} />}
active={isEdit}
onClick={() => handleNavigation('edit')}
variant="filled"
color="blue"
styles={{
root: {
borderRadius: '8px',
fontWeight: isEdit ? 600 : 400,
},
}}
/>
<NavLink
label="Galaxy"
leftSection={<IconChartBubbleFilled size={20} />}
active={isGalaxy}
onClick={() => handleNavigation('galaxy')}
variant="filled"
color="blue"
styles={{
root: {
borderRadius: '8px',
fontWeight: isGalaxy ? 600 : 400,
},
}}
/>
<Divider my="md" />
{/* User Menu - styled like other nav items, now includes theme toggle */}
<UserMenu showLabel={true} />
{/* Development state panel */}
{process.env.NODE_ENV === 'development' && (
<Box className={styles.devPanel}>
<Text size="xs" fw={700} c="dimmed" mb="xs">
DEV: App State
</Text>
<Text size="xs" c="dimmed">
State: {JSON.stringify(state.value)}
</Text>
<Text size="xs" c="dimmed">
Tags: {Array.from(state.tags).join(', ')}
</Text>
<Text size="xs" c="dimmed">
Mode: {state.context.mode}
</Text>
{state.context.pendingNodeDraft && (
<Text size="xs" c="dimmed">
Draft: {state.context.pendingNodeDraft.title || '(untitled)'}
</Text>
)}
{state.context.currentNodeId && (
<Text size="xs" c="dimmed">
Node: {state.context.currentNodeId}
</Text>
)}
</Box>
)}
</Stack>
</Box>
);
}