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:
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user