feat: sidebar reorg, compact view preference, and UI polish

- Remove redundant Settings link from sidebar (accessible via user menu)
- Move Transactions section below Board Reference for better grouping
- Promote Investment Scenarios to its own top-level sidebar item
- Add Compact View preference with tighter spacing theme
- Wire compact theme into MantineProvider with dynamic switching
- Enable Compact View toggle in both Preferences and Settings pages
- Install missing @simplewebauthn/browser package (lock file update)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 06:39:41 -04:00
parent 20438b7ef5
commit af68304692
7 changed files with 86 additions and 32 deletions

View File

@@ -1,12 +1,12 @@
{ {
"name": "hoa-ledgeriq-frontend", "name": "hoa-ledgeriq-frontend",
"version": "2026.3.11", "version": "2026.3.17",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "hoa-ledgeriq-frontend", "name": "hoa-ledgeriq-frontend",
"version": "2026.3.11", "version": "2026.3.17",
"dependencies": { "dependencies": {
"@mantine/core": "^7.15.3", "@mantine/core": "^7.15.3",
"@mantine/dates": "^7.15.3", "@mantine/dates": "^7.15.3",

View File

@@ -17,11 +17,9 @@ import {
IconChartAreaLine, IconChartAreaLine,
IconClipboardCheck, IconClipboardCheck,
IconSparkles, IconSparkles,
IconHeartRateMonitor,
IconCalculator, IconCalculator,
IconGitCompare, IconGitCompare,
IconScale, IconScale,
IconSettings,
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { useAuthStore } from '../../stores/authStore'; import { useAuthStore } from '../../stores/authStore';
@@ -47,14 +45,6 @@ const navSections = [
{ label: 'Assessment Groups', icon: IconCategory, path: '/assessment-groups', tourId: 'nav-assessment-groups' }, { label: 'Assessment Groups', icon: IconCategory, path: '/assessment-groups', tourId: 'nav-assessment-groups' },
], ],
}, },
{
label: 'Transactions',
items: [
{ label: 'Transactions', icon: IconReceipt, path: '/transactions', tourId: 'nav-transactions' },
{ label: 'Invoices', icon: IconFileInvoice, path: '/invoices' },
{ label: 'Payments', icon: IconCash, path: '/payments' },
],
},
{ {
label: 'Board Planning', label: 'Board Planning',
items: [ items: [
@@ -68,12 +58,8 @@ const navSections = [
{ {
label: 'Assessment Scenarios', icon: IconCalculator, path: '/board-planning/assessments', label: 'Assessment Scenarios', icon: IconCalculator, path: '/board-planning/assessments',
}, },
{ { label: 'Investment Planning', icon: IconSparkles, path: '/investment-planning', tourId: 'nav-investment-planning' },
label: 'Investment Planning', icon: IconSparkles, path: '/investment-planning', tourId: 'nav-investment-planning', { label: 'Investment Scenarios', icon: IconScale, path: '/board-planning/investments' },
children: [
{ label: 'Investment Scenarios', path: '/board-planning/investments' },
],
},
{ label: 'Compare Scenarios', icon: IconGitCompare, path: '/board-planning/compare' }, { label: 'Compare Scenarios', icon: IconGitCompare, path: '/board-planning/compare' },
], ],
}, },
@@ -83,6 +69,14 @@ const navSections = [
{ label: 'Vendors', icon: IconUsers, path: '/vendors' }, { label: 'Vendors', icon: IconUsers, path: '/vendors' },
], ],
}, },
{
label: 'Transactions',
items: [
{ label: 'Transactions', icon: IconReceipt, path: '/transactions', tourId: 'nav-transactions' },
{ label: 'Invoices', icon: IconFileInvoice, path: '/invoices' },
{ label: 'Payments', icon: IconCash, path: '/payments' },
],
},
{ {
label: 'Reports', label: 'Reports',
items: [ items: [
@@ -103,12 +97,6 @@ const navSections = [
}, },
], ],
}, },
{
label: 'Account',
items: [
{ label: 'Settings', icon: IconSettings, path: '/settings' },
],
},
]; ];
interface SidebarProps { interface SidebarProps {

View File

@@ -9,7 +9,7 @@ import '@mantine/core/styles.css';
import '@mantine/dates/styles.css'; import '@mantine/dates/styles.css';
import '@mantine/notifications/styles.css'; import '@mantine/notifications/styles.css';
import { App } from './App'; import { App } from './App';
import { theme } from './theme/theme'; import { defaultTheme, compactTheme } from './theme/theme';
import { usePreferencesStore } from './stores/preferencesStore'; import { usePreferencesStore } from './stores/preferencesStore';
const queryClient = new QueryClient({ const queryClient = new QueryClient({
@@ -24,9 +24,11 @@ const queryClient = new QueryClient({
function Root() { function Root() {
const colorScheme = usePreferencesStore((s) => s.colorScheme); const colorScheme = usePreferencesStore((s) => s.colorScheme);
const compactView = usePreferencesStore((s) => s.compactView);
const activeTheme = compactView ? compactTheme : defaultTheme;
return ( return (
<MantineProvider theme={theme} forceColorScheme={colorScheme}> <MantineProvider theme={activeTheme} forceColorScheme={colorScheme}>
<Notifications position="top-right" /> <Notifications position="top-right" />
<ModalsProvider> <ModalsProvider>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>

View File

@@ -10,7 +10,7 @@ import { usePreferencesStore } from '../../stores/preferencesStore';
export function UserPreferencesPage() { export function UserPreferencesPage() {
const { user, currentOrg } = useAuthStore(); const { user, currentOrg } = useAuthStore();
const { colorScheme, toggleColorScheme } = usePreferencesStore(); const { colorScheme, toggleColorScheme, compactView, toggleCompactView } = usePreferencesStore();
return ( return (
<Stack> <Stack>
@@ -78,7 +78,7 @@ export function UserPreferencesPage() {
<Text size="sm">Compact View</Text> <Text size="sm">Compact View</Text>
<Text size="xs" c="dimmed">Reduce spacing in tables and lists</Text> <Text size="xs" c="dimmed">Reduce spacing in tables and lists</Text>
</div> </div>
<Switch disabled /> <Switch checked={compactView} onChange={toggleCompactView} />
</Group> </Group>
<Divider /> <Divider />
<Text size="xs" c="dimmed" ta="center">More display preferences coming in a future release</Text> <Text size="xs" c="dimmed" ta="center">More display preferences coming in a future release</Text>

View File

@@ -1,7 +1,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { import {
Title, Text, Card, Stack, Group, SimpleGrid, Badge, ThemeIcon, Divider, Title, Text, Card, Stack, Group, SimpleGrid, Badge, ThemeIcon, Divider,
Tabs, Button, Tabs, Button, Switch,
} from '@mantine/core'; } from '@mantine/core';
import { import {
IconBuilding, IconUser, IconSettings, IconShieldLock, IconBuilding, IconUser, IconSettings, IconShieldLock,
@@ -9,6 +9,7 @@ import {
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { useAuthStore } from '../../stores/authStore'; import { useAuthStore } from '../../stores/authStore';
import { usePreferencesStore } from '../../stores/preferencesStore';
import { MfaSettings } from './MfaSettings'; import { MfaSettings } from './MfaSettings';
import { PasskeySettings } from './PasskeySettings'; import { PasskeySettings } from './PasskeySettings';
import { LinkedAccounts } from './LinkedAccounts'; import { LinkedAccounts } from './LinkedAccounts';
@@ -16,6 +17,7 @@ import api from '../../services/api';
export function SettingsPage() { export function SettingsPage() {
const { user, currentOrg } = useAuthStore(); const { user, currentOrg } = useAuthStore();
const { compactView, toggleCompactView } = usePreferencesStore();
const [loggingOutAll, setLoggingOutAll] = useState(false); const [loggingOutAll, setLoggingOutAll] = useState(false);
const handleLogoutEverywhere = async () => { const handleLogoutEverywhere = async () => {
@@ -112,6 +114,14 @@ export function SettingsPage() {
<Text size="sm" c="dimmed">API</Text> <Text size="sm" c="dimmed">API</Text>
<Text size="sm" ff="monospace" c="dimmed">/api/docs</Text> <Text size="sm" ff="monospace" c="dimmed">/api/docs</Text>
</Group> </Group>
<Divider />
<Group justify="space-between">
<div>
<Text size="sm">Compact View</Text>
<Text size="xs" c="dimmed">Reduce spacing in tables and lists</Text>
</div>
<Switch checked={compactView} onChange={toggleCompactView} />
</Group>
</Stack> </Stack>
</Card> </Card>

View File

@@ -5,19 +5,26 @@ type ColorScheme = 'light' | 'dark';
interface PreferencesState { interface PreferencesState {
colorScheme: ColorScheme; colorScheme: ColorScheme;
compactView: boolean;
toggleColorScheme: () => void; toggleColorScheme: () => void;
setColorScheme: (scheme: ColorScheme) => void; setColorScheme: (scheme: ColorScheme) => void;
toggleCompactView: () => void;
setCompactView: (compact: boolean) => void;
} }
export const usePreferencesStore = create<PreferencesState>()( export const usePreferencesStore = create<PreferencesState>()(
persist( persist(
(set) => ({ (set) => ({
colorScheme: 'light', colorScheme: 'light',
compactView: false,
toggleColorScheme: () => toggleColorScheme: () =>
set((state) => ({ set((state) => ({
colorScheme: state.colorScheme === 'light' ? 'dark' : 'light', colorScheme: state.colorScheme === 'light' ? 'dark' : 'light',
})), })),
setColorScheme: (scheme) => set({ colorScheme: scheme }), setColorScheme: (scheme) => set({ colorScheme: scheme }),
toggleCompactView: () =>
set((state) => ({ compactView: !state.compactView })),
setCompactView: (compact) => set({ compactView: compact }),
}), }),
{ {
name: 'ledgeriq-preferences', name: 'ledgeriq-preferences',

View File

@@ -1,10 +1,57 @@
import { createTheme } from '@mantine/core'; import { createTheme } from '@mantine/core';
export const theme = createTheme({ const baseFontFamily = '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif';
export const defaultTheme = createTheme({
primaryColor: 'blue', primaryColor: 'blue',
fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif', fontFamily: baseFontFamily,
headings: { headings: {
fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif', fontFamily: baseFontFamily,
}, },
defaultRadius: 'md', defaultRadius: 'md',
}); });
export const compactTheme = createTheme({
primaryColor: 'blue',
fontFamily: baseFontFamily,
headings: {
fontFamily: baseFontFamily,
},
defaultRadius: 'md',
spacing: {
xs: '4px',
sm: '6px',
md: '10px',
lg: '12px',
xl: '16px',
},
fontSizes: {
xs: '11px',
sm: '12px',
md: '13px',
lg: '15px',
xl: '18px',
},
components: {
Table: {
defaultProps: {
verticalSpacing: 'xs',
horizontalSpacing: 'xs',
fz: 'sm',
},
},
Card: {
defaultProps: {
padding: 'sm',
},
},
AppShell: {
defaultProps: {
padding: 'xs',
},
},
},
});
/** @deprecated Use `defaultTheme` or `compactTheme` instead */
export const theme = defaultTheme;