Settings revamp: searchable Home hub, ranked reveal-to-row search, and a tinted sidebar#699
Merged
Conversation
… a tinted sidebar The Settings window gets a designed landing surface and a search that lands on the exact control: - Home is now a composed page: identity hero, a prominent search field over the whole catalog, status cards (global toggle, engine and model, permissions) and tinted quick links, with the feature demos and a one-line footer below. - Search relevance moves to a pure SettingsSearchRanker (tiered prefix/word/substring/subsequence scoring, multi-token queries, reverse prefix for plurals, diacritic folding). Every catalog item gains a searchable one-line summary, and results render as ranked rich rows. - Picking a result reveals the setting: the pane opens, scrolls to the row, and pulses it. Every indexed setting carries a .settingsItem anchor. - Sidebar rows get System Settings-style tinted icon tiles and spacing-only group clusters. Cmd-F focuses the Home search from any pane. - Declutter: the Ko-fi pitch leaves General (it lives on Home and About), permission rows gain real status iconography, the window title follows the pane via navigationTitle instead of racing NSWindow.title writes. - New -cotabby-open-settings launch argument opens the Settings window at startup so UI work on it can be exercised by tooling.
- Remove the dead syncWindowTitle helper (navigationTitle owns the window title now) and the AppKit import it required. - Repair-pass the reveal scroll: a second staggered scrollTo covers slow layout instead of trusting one 80 ms guess. - Sidebar Return key opens from the same computed results the list renders. - Share the display-version formatting between the sidebar header and the Home hero via Bundle.cotabbyDisplayVersion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Settings window had grown cluttered: twelve flat sidebar rows, a form-styled Home that mostly repeated the support pitch (which appeared in three different panes), and a search that was a substring filter that could only land you on a pane. This redesigns Settings around finding and understanding things. Home becomes a real landing surface (an identity hero, a prominent search field over the whole settings catalog, live status cards for the global toggle / engine / permissions, tinted quick-link cards, and the feature demos). Search gains true relevance ranking in a new pure
SettingsSearchRanker(tiered prefix/word/substring scoring, multi-word queries, plural folding, subsequence typo matching, per-item summaries), and selecting a result now reveals the exact setting: the pane opens, scrolls to the row, and pulses it. The sidebar gets System Settings-style tinted icon tiles with spacing-only group clusters, and Cmd-F jumps to search from any pane.Validation
Visual verification was done by rendering the new surfaces off-screen through a temporary
NSHostingViewsnapshot harness in the test bundle (removed before commit) and reviewing the PNGs:FormignoreslistRowBackground(highlighted and plain renders were pixel-identical); the pulse now draws as a direct row background instead.Also launched the app with the new
-cotabby-open-settingsargument and confirmed via CGWindowList that the Settings window opens at startup. The live scroll-to-row behavior was not exercised end to end in the running window (scripting the unsigned dev build's AX tree turned out to be blocked at the system level); the navigation and ranking logic behind it is unit-tested and the pulse rendering is snapshot-verified.Linked issues
None directly; this is the Settings UX revamp.
Risk / rollout notes
CotabbySettingsWindowV6toV7: everyone reopens once at the new default size (1060x720), then their resize sticks again..navigationTitle(pane name, or "Cotabby Settings" on Home). The old asyncNSWindow.titlewrite raced SwiftUI's own title management and lost whenever the window was not key.SettingsItem.results(for:)now returns ranked results instead of declaration order. Search behavior strictly widens (typo subsequences, plural/reverse-prefix matching, summaries searched); the existingSettingsIndexTestsqueries all still pass.HomePaneViewnow takes the navigation model and live status objects; it is the only pane not rendered inside the shared grouped-form scaffold, by design.-cotabby-open-settingsopens the Settings window at startup for UI tooling; it is a no-op unless passed.Greptile Summary
This PR redesigns the Settings window around discoverability: Home becomes a rich landing surface (identity hero, global search, at-a-glance status cards, quick-link grid, feature demos), search gains a full relevance-ranking engine (
SettingsSearchRanker) with tiered scoring, multi-word queries, typo subsequences, and per-item summaries, and the sidebar adopts System Settings–style tinted icon tiles arranged in spacing-only groups. Selecting a search result now navigates to the exact row, scrolls to it, and pulses it.SettingsSearchRankeris a pure, fully unit-tested ranker (no SwiftUI/app-state dependencies) with 10 new tests;SettingsItemconforms viaSettingsSearchable, andSettingsIndexremains a thin catalog accessor.SettingsNavigationModelcentralises all navigation state (pane selection, in-flight highlight, pending Cmd-F focus) and replaces the old@Binding var selectionthreading;SettingsCategorygainstint,summary, andsidebarGroups(with a unit test that pins coverage toallCases).HomePaneViewis rewritten from a flat form into a composed page;SettingsCoordinatorbumps the autosave name toV7to reset window frames, andBundleVersion.swiftextracts the duplicated version-formatting helper.Confidence Score: 5/5
Safe to merge. All navigation state flows through SettingsNavigationModel, cancellation is handled correctly, and the ranking logic is fully unit-tested.
The navigation model's Task-based highlight clearing is correct under rapid re-invocations: cancellation propagates through Task.sleep and the guard prevents stale clears. The scroll Tasks in SettingsPaneScaffold are unstructured but their effects on orphaned proxies are benign no-ops. The ranker, catalog, sidebar grouping, and the Cmd-F focus flow are all logically sound, and 1,602 passing tests (including 10 new ranker tests and extended index tests) back that up.
No files require special attention.
Important Files Changed
normalizecalls both.folding(.caseInsensitive)and.lowercased(), which is harmlessly redundant.onChange(initial: true)correctly handles cross-pane Cmd-F.@State var selectionto@StateObject var navigation; deadsyncWindowTitleremoved; title driven by.navigationTitle; Cmd-F zero-size button wired correctly.searchResultsproperty for both rendering and the Enter-key action.tint,summary, andsidebarGroups; import changed from Foundation to SwiftUI for Color.sidebarGroupscoverage is pinned by a new unit test.summaryto every item andSettingsSearchableconformance; replaces the oldcontains-basedresults(for:)with the rankedSettingsSearchRankercall.-cotabby-open-settingslaunch argument that opens Settings at startup; no-op unless passed, guarded with an explicitarguments.containscheck.Bundle.cotabbyDisplayVersion; both the sidebar header and Home hero now use it.Sequence Diagram
sequenceDiagram actor User participant Sidebar as SettingsSidebarView participant Home as HomePaneView participant Nav as SettingsNavigationModel participant Container as SettingsContainerView participant Scaffold as SettingsPaneScaffold participant Row as SettingsItemAnchor User->>Sidebar: types query Sidebar->>Sidebar: searchResults (ranked via SettingsSearchRanker) User->>Sidebar: selects result / presses Return Sidebar->>Nav: reveal(item) Nav->>Nav: "selection = item.category" Nav->>Nav: "highlightedItem = item" Nav->>Nav: start 2.4s clear Task Nav-->>Container: "@Published selection changes" Container->>Container: .id(selection) rebuilds detail pane Container->>Scaffold: mount pane with .settingsHighlightedItem env Scaffold->>Scaffold: onAppear → Task: sleep 80ms → scrollTo(item) Scaffold->>Scaffold: repair: sleep 350ms → scrollTo(item) Scaffold-->>Row: "env settingsHighlightedItem = item" Row->>Row: "isHighlighted = true → pulse animation" Note over Nav,Row: after 2.4s Nav->>Nav: "highlightedItem = nil" Row->>Row: "isHighlighted = false → fade out" User->>Container: Cmd-F Container->>Nav: requestSearchFocus() Nav->>Nav: "open(.home) + pendingSearchFocus = true" Nav-->>Home: "@Published pendingSearchFocus" Home->>Home: "onChange(initial:true) → isSearchFocused = true" Home->>Nav: consumeSearchFocusRequest()Reviews (2): Last reviewed commit: "refactor(settings): address review on th..." | Re-trigger Greptile