Skip to content

Commit c3003a0

Browse files
committed
Settings: reorganize into Appearance / Behavior / File systems / etc.
- New top-level order in the sidebar: Appearance, Behavior, AI, File systems, Viewer, Keyboard shortcuts, Developer, Updates, License, Advanced. `SettingsSidebar.svelte`'s `TOP_LEVEL_ORDER` is the source of truth; special non-registry sections are interleaved with registry-driven sections. - Appearance now has 4 subsections: - `Colors and formats` (theme mode, app color, size/date colors, date/time format, striped rows) - `Zoom and density` (text size, UI density) - `File and folder sizes` (size display, human-friendly units, file size format, size mismatch warning) - `Listing` (document icons, directory sort, brief column width) - `Themes` section is gone; `theme.mode` folds into `Appearance > Colors and formats`. "Coming soon" placeholders deleted. - `Behavior` collects file operations (extension changes only — the noisy `maxConflictsToShow` and `progressUpdateInterval` move into Advanced) and drive indexing. - `File systems` collects `SMB/Network shares`, `MTP (Android/Kindle/cameras)`, and `Git`. - `Viewer` and `Updates` get their own top-level entries (no subsections). - New section components: `AppearanceZoomSection.svelte`, `AppearanceSizesSection.svelte` (+ a11y tests). - E2E: new `settings.spec.ts` test asserts the exact top-to-bottom sidebar order. Existing settings tests untouched. - Updated cross-refs: `app-status-store` default section, `openSettingsWindow` deep-link in `VolumeBreadcrumb`, `settings/CLAUDE.md`, `navigation/CLAUDE.md`.
1 parent 2dfd17b commit c3003a0

29 files changed

Lines changed: 943 additions & 839 deletions

apps/desktop/src/lib/app-status-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export async function pruneRecentCommands(validIds: ReadonlySet<string>): Promis
294294
// Settings window section persistence
295295
// ============================================================================
296296

297-
const DEFAULT_SETTINGS_SECTION = ['General', 'Appearance']
297+
const DEFAULT_SETTINGS_SECTION = ['Appearance', 'Colors and formats']
298298

299299
/**
300300
* Loads the last viewed settings section.

apps/desktop/src/lib/file-explorer/navigation/CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ Pure logic for organizing volumes into display groups. No reactive state.
199199
5. Network: always includes a synthetic `'network'` entry (`smb://`) plus any mounted SMB shares. The synthetic entry's
200200
name flips to `"Network (disabled)"` when `options.networkEnabled === false`. `VolumeBreadcrumb` reads
201201
`getNetworkEnabled()` from reactive settings to set the option, and intercepts clicks on the disabled entry to open
202-
Settings → Network → SMB/Network shares (via `openSettingsWindow(['Network', 'SMB/Network shares'])`) instead of
203-
navigating.
202+
Settings → File systems → SMB/Network shares (via `openSettingsWindow(['File systems', 'SMB/Network shares'])`)
203+
instead of navigating.
204204

205205
`getIconForVolume(volume)`: returns the appropriate icon path for a volume based on its category.
206206

apps/desktop/src/lib/file-explorer/navigation/VolumeBreadcrumb.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
// so the user can flip it on. Identified by the synthetic id, not the label, so
178178
// future label tweaks don't break this branch.
179179
if (volume.id === 'network' && !getNetworkEnabled()) {
180-
void openSettingsWindow(['Network', 'SMB/Network shares'])
180+
void openSettingsWindow(['File systems', 'SMB/Network shares'])
181181
return
182182
}
183183

apps/desktop/src/lib/file-explorer/rename/rename-dialogs.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ describe('allowFileExtensionChanges setting', () => {
3131

3232
it('should be in the File operations section', () => {
3333
const def = getSettingDefinition('fileOperations.allowFileExtensionChanges')
34-
expect(def?.section).toEqual(['General', 'File operations'])
34+
expect(def?.section).toEqual(['Behavior', 'File operations'])
3535
})
3636

3737
it('should appear in File operations section listing', () => {
38-
const settings = getSettingsInSection(['General', 'File operations'])
38+
const settings = getSettingsInSection(['Behavior', 'File operations'])
3939
const ids = settings.map((s) => s.id)
4040
expect(ids).toContain('fileOperations.allowFileExtensionChanges')
4141
})

apps/desktop/src/lib/settings/CLAUDE.md

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ defined once in `settings-registry.ts` and accessed uniformly by both UI and MCP
2323
Single source of truth for all settings. Each `SettingDefinition` contains:
2424

2525
- `id`: Unique key (e.g., `appearance.uiDensity`)
26-
- `section`: Path in settings tree (e.g., `['General', 'Appearance']`)
26+
- `section`: Path in settings tree (e.g., `['Appearance', 'Colors and formats']`)
2727
- `type`: boolean, number, string, enum, duration
2828
- `default`: Default value
2929
- `constraints`: Type-specific validation (min/max, enum options, etc.)
@@ -91,14 +91,42 @@ applied via `data-size-colors` / `data-date-colors` attributes on `<html>`. Sett
9191

9292
### Sections (`sections/`)
9393

94-
15 section components rendered inside the settings window. `ListingSection` includes:
95-
96-
- `listing.sizeDisplay`: enum (smart/logical/physical), default smart, toggle-group. Reactive getter:
97-
`getSizeDisplayMode()`.
98-
- `listing.humanFriendlySizeUnits`: boolean, default true, switch. Reactive getter: `getHumanFriendlySizeUnits()`. ON
99-
shows "1.02 MB" in size columns and the SelectionInfo primary size readout; OFF shows raw bytes with thin-space triad
100-
separators. Volume/disk-space displays, dialogs, and tooltips that already show both formats are unaffected.
101-
- `listing.sizeMismatchWarning`: boolean, default true, switch. Reactive getter: `getSizeMismatchWarning()`.
94+
Top-level sidebar order (declared in `SettingsSidebar.svelte`'s `TOP_LEVEL_ORDER`; keep in sync with the E2E test in
95+
`settings.spec.ts`):
96+
97+
1. **Appearance**`Colors and formats`, `Zoom and density`, `File and folder sizes`, `Listing`
98+
2. **Behavior**`File operations`, `Drive indexing`
99+
3. **AI** (no subsections)
100+
4. **File systems**`SMB/Network shares`, `MTP (Android/Kindle/cameras)`, `Git`
101+
5. **Viewer** (no subsections)
102+
6. **Keyboard shortcuts** (special, non-registry)
103+
7. **Developer**`MCP server`, `Logging`
104+
8. **Updates** (no subsections)
105+
9. **License** (special, non-registry)
106+
10. **Advanced** (special, auto-generated from `showInAdvanced: true` entries)
107+
108+
Section ↔ component map (`sections/`):
109+
110+
- `AppearanceSection.svelte``Appearance > Colors and formats` (theme mode, app color, size/date colors, date/time
111+
format, striped rows)
112+
- `AppearanceZoomSection.svelte``Appearance > Zoom and density` (text size, UI density)
113+
- `AppearanceSizesSection.svelte``Appearance > File and folder sizes` (size display, human-friendly units, file size
114+
format, size mismatch warning)
115+
- `ListingSection.svelte``Appearance > Listing` (document icons, directory sort, brief column width)
116+
- `FileOperationsSection.svelte``Behavior > File operations` (extension changes only; `maxConflictsToShow` and
117+
`progressUpdateInterval` live in Advanced)
118+
- `DriveIndexingSection.svelte``Behavior > Drive indexing` (toggle + clear-index action)
119+
- `AiSection.svelte` (+ `AiCloudSection.svelte`, `AiLocalSection.svelte`) → `AI`
120+
- `NetworkSection.svelte``File systems > SMB/Network shares`
121+
- `MtpSection.svelte``File systems > MTP (Android/Kindle/cameras)`
122+
- `GitSection.svelte``File systems > Git`
123+
- `ViewerSection.svelte``Viewer`
124+
- `KeyboardShortcutsSection.svelte``Keyboard shortcuts` (special; renders the shortcut table)
125+
- `McpServerSection.svelte``Developer > MCP server`
126+
- `LoggingSection.svelte``Developer > Logging`
127+
- `UpdatesSection.svelte``Updates`
128+
- `LicenseSection.svelte``License` (special; reads `getLicenseInfo`/`getLicenseStatus`)
129+
- `AdvancedSection.svelte``Advanced` (auto-generated UI for every `showInAdvanced: true` entry)
102130

103131
`AdvancedSection` includes `advanced.maxLogStorageMb`: number, default 200, range 0–5000, MB suffix. `0` disables log
104132
storage entirely (the `Folder` target is dropped from the plugin builder, no error reports possible). Toggling between
@@ -114,10 +142,6 @@ changes take effect on the next keystroke without restart.
114142
reports when a user-visible error fires). Flow A (the **Help > Send error report…** menu item and the toast button) is
115143
always available regardless of this setting. Clicking is the consent.
116144

117-
Full list: `AppearanceSection`, `ListingSection`, `FileOperationsSection`, `MtpSection`, `KeyboardShortcutsSection`,
118-
`NetworkSection`, `LoggingSection`, `McpServerSection`, `UpdatesSection`, `ThemesSection`, `AdvancedSection`,
119-
`DriveIndexingSection`, `AiSection`, `LicenseSection`, `ViewerSection`.
120-
121145
`NetworkSection` includes `network.enabled`: boolean, default true, switch. The top-of-section toggle. When off, the
122146
volume picker shows "Network (disabled)" and the backend stops mDNS + clears discovered hosts. Below the switch is a
123147
non-interactive Local Network access info card with a deep link to System Settings > Privacy & Security > Local Network
@@ -182,7 +206,7 @@ row intentionally spans the full width.
182206
- **settings-applier.ts**: Listens for setting changes and applies side effects (CSS vars, backend config sync)
183207
- **network-settings.ts**: Network-specific setting helpers (proxy config, SMB auth defaults)
184208
- **settings-window.ts**: Logic for opening/focusing/closing the settings window (Tauri window management). Accepts an
185-
optional `section` array (e.g. `['Network', 'SMB/Network shares']`) to deep-link a specific section. Two delivery
209+
optional `section` array (e.g. `['File systems', 'SMB/Network shares']`) to deep-link a specific section. Two delivery
186210
paths: (a) new-window: JSON-encoded array on the URL as `?section=...` (JSON because section names can contain `/`,
187211
e.g. "SMB/Network shares"); (b) already-open window: emits a `navigate-to-section` Tauri event the settings page
188212
listens for. The settings page also reads the URL param at mount, so reloads or fresh-opens land on the same section.

apps/desktop/src/lib/settings/components/SectionSummary.a11y.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ vi.mock('$lib/settings/settings-store', () => ({
1616
}))
1717

1818
describe('SectionSummary a11y', () => {
19-
it('General section (multiple subsections) has no a11y violations', async () => {
19+
it('Appearance section (multiple subsections) has no a11y violations', async () => {
2020
const target = document.createElement('div')
2121
document.body.appendChild(target)
2222
mount(SectionSummary, {
2323
target,
24-
props: { sectionName: 'General', onNavigate: () => {} },
24+
props: { sectionName: 'Appearance', onNavigate: () => {} },
2525
})
2626
await tick()
2727
await expectNoA11yViolations(target)

apps/desktop/src/lib/settings/components/SectionSummary.svelte

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@
1919
function getSubsectionDescription(subsection: SettingsSection): string {
2020
// Return a brief description based on the subsection name
2121
const descriptions: Record<string, string> = {
22-
Appearance: 'Customize fonts, density, and visual display options.',
23-
'File operations': 'Configure copy, move, delete, and progress display settings.',
22+
'Colors and formats': 'Theme, app color, date and size coloring, and date/time format.',
23+
'Zoom and density': 'Text size and UI density for the whole app.',
24+
'File and folder sizes': 'How sizes are shown in the file list and warnings about size mismatches.',
25+
Listing: 'Document icons, directory sorting, and Brief mode column width.',
26+
'File operations': 'Behavior when renaming files (e.g. extension changes).',
2427
'Drive indexing': 'Background indexing for directory sizes. Manage index storage.',
25-
Updates: 'Manage automatic update checks and notifications.',
26-
'SMB/Network shares': 'Configure network timeouts and connection settings.',
28+
'SMB/Network shares': 'Enable networking, direct SMB connections, share cache, and timeouts.',
29+
'MTP (Android/Kindle/cameras)': 'Detect Android, Kindle, and camera devices over USB.',
30+
Git: 'Repository chip, per-file status column, and the virtual `.git` portal.',
2731
'MCP server': 'Configure the Model Context Protocol server for AI integrations.',
28-
Logging: 'Debug logging and diagnostic settings.',
32+
Logging: 'Verbose console output, log file access, and diagnostic info.',
2933
}
3034
return descriptions[subsection.name] ?? `Configure ${subsection.name.toLowerCase()} settings.`
3135
}

apps/desktop/src/lib/settings/components/SettingsContent.a11y.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ vi.mock('$lib/tauri-commands', () => ({
2828
}))
2929

3030
describe('SettingsContent a11y', () => {
31-
it('General summary page has no a11y violations', async () => {
31+
it('Appearance summary page has no a11y violations', async () => {
3232
const target = document.createElement('div')
3333
document.body.appendChild(target)
3434
mount(SettingsContent, {
3535
target,
3636
props: {
3737
searchQuery: '',
38-
selectedSection: ['General'],
38+
selectedSection: ['Appearance'],
3939
},
4040
})
4141
await tick()

0 commit comments

Comments
 (0)