Adopt Obsidian-style settings navigation #192

Closed
opened 2026-06-01 08:40:58 +00:00 by steve · 0 comments
Owner

The settings panel currently derives the left navigation from configuration schema
categories and also registers plugin setting tabs through registerWebView().
That creates duplicate settings routes and can surface plugin-owned settings
under misleading generated headers such as Markdown.

Problem

The settings sidebar exposes implementation details: app schemas, imperative
plugin setting tabs, and declarative plugin configuration all feed different
navigation paths. This makes it hard to know where a setting belongs and makes
plugin settings appear both under plugin management and under the schema-derived
preferences tree.

Goal

Adopt an Obsidian-style settings navigation model: curated app settings under
Options, individual plugin settings under Core plugins and Community plugins, and search as the cross-surface shortcut. Each selected sidebar item
should render only its own settings surface.

Scope

  • Replace the schema-derived tree in the settings sidebar with flat settings
    surface groups.
  • Add sidebar icons for app and plugin settings surfaces.
  • Support plugin settings surfaces backed by imperative SettingTab,
    declarative configuration, or both.
  • Keep plugin management pages (Core plugins, Community plugins) available
    under Options.
  • Keep settings search, but route search results to canonical surfaces.
  • Update the settings/workspace spec and tests.

Non-goals

  • Do not rename or migrate persisted configuration keys such as
    appearence.*.
  • Do not remove schema-backed settings controls.
  • Do not change plugin data persistence or plugin enablement persistence.
  • Do not redesign the plugin management rows beyond navigation and routing
    changes needed for this issue.

Acceptance Criteria

  • The sidebar groups are Options, Core plugins, and Community plugins.
  • Options includes Workspace, Editor, Files and Links, Appearance,
    Hotkeys, Plugin registry, Core plugins, and Community plugins.
  • Plugin groups list only plugins with settings surfaces.
  • Sidebar navigation items render icons.
  • Selecting a schema app section renders only that section's settings.
  • Selecting a plugin surface renders its imperative settings tab, its
    declarative configuration, or both in one surface.
  • Plugin-owned settings no longer appear in an app-owned preferences tree.
  • Synthetic categoryId: "extensions" entries from registerWebView() do not
    create visible app navigation sections.
  • Settings search still finds app schema settings, plugin rows, plugin
    metadata, and declarative plugin configuration.
  • Search results open the canonical surface and highlight the target row when
    applicable.
  • Existing core/community plugin management pages still show plugin rows,
    enablement controls, diagnostics, and gear buttons.

Implementation Notes

  • Add an internal workspace SettingsSurface model with id, title, icon,
    group, and kind.
  • Build app schema surfaces from root category ids: workspace, editor,
    files, and appearence; display appearence as Appearance.
  • Build plugin surfaces from core/community plugin metadata plus imperative
    setting items and valid declarative configuration contributions.
  • Use plugin manifest ids as plugin surface ids.
  • Render app schema surfaces through the existing schema form renderer, scoped
    to the selected surface's ConfigProperty entries.
  • Render plugin surfaces as a composite: imperative SettingTab first when
    present, then owned declarative schema sections.
  • Remove the recursive sidebar tree, collapsible state, intersection observer,
    scroll-driven selection, and ancestor-open logic from configuration.svelte.
  • Reuse SettingItem.icon and the existing icon rendering path where practical.

Suggested Files or Specs To Inspect

  • packages/workspace/src/lib/components/configuration/configuration.svelte
  • packages/workspace/src/lib/components/configuration/configuration.ts
  • packages/workspace/src/lib/components/configuration/settings-search.ts
  • packages/workspace/src/lib/components/configuration/plugin-settings-target.ts
  • packages/api/src/lib/plugin.ts
  • packages/api/src/lib/configuration.svelte.ts
  • spec/src/30-cross-package-contracts/configuration-and-settings.md
  • spec/src/20-packages/workspace/index.md

Validation Commands

  • pnpm --filter @lapis-notes/workspace check:all
  • pnpm test:smoke
  • make spec-lint
  • mdbook build spec
  • pnpm backlog:verify-commit @-
  • pnpm backlog:doctor --strict

Follow-up Tasks

Implementation Summary

Implemented Obsidian-style flat settings navigation with stable Options/Core plugins/Community plugins groups, sidebar icons, canonical plugin settings surfaces for imperative and declarative settings, duplicate plugin surface de-duping, search routing to canonical surfaces, and regression coverage for duplicate keys and schema-toggle remount flashing.

The settings panel currently derives the left navigation from configuration schema categories and also registers plugin setting tabs through `registerWebView()`. That creates duplicate settings routes and can surface plugin-owned settings under misleading generated headers such as `Markdown`. ## Problem The settings sidebar exposes implementation details: app schemas, imperative plugin setting tabs, and declarative plugin configuration all feed different navigation paths. This makes it hard to know where a setting belongs and makes plugin settings appear both under plugin management and under the schema-derived preferences tree. ## Goal Adopt an Obsidian-style settings navigation model: curated app settings under `Options`, individual plugin settings under `Core plugins` and `Community plugins`, and search as the cross-surface shortcut. Each selected sidebar item should render only its own settings surface. ## Scope - Replace the schema-derived tree in the settings sidebar with flat settings surface groups. - Add sidebar icons for app and plugin settings surfaces. - Support plugin settings surfaces backed by imperative `SettingTab`, declarative configuration, or both. - Keep plugin management pages (`Core plugins`, `Community plugins`) available under `Options`. - Keep settings search, but route search results to canonical surfaces. - Update the settings/workspace spec and tests. ## Non-goals - Do not rename or migrate persisted configuration keys such as `appearence.*`. - Do not remove schema-backed settings controls. - Do not change plugin data persistence or plugin enablement persistence. - Do not redesign the plugin management rows beyond navigation and routing changes needed for this issue. ## Acceptance Criteria - The sidebar groups are `Options`, `Core plugins`, and `Community plugins`. - `Options` includes `Workspace`, `Editor`, `Files and Links`, `Appearance`, `Hotkeys`, `Plugin registry`, `Core plugins`, and `Community plugins`. - Plugin groups list only plugins with settings surfaces. - Sidebar navigation items render icons. - Selecting a schema app section renders only that section's settings. - Selecting a plugin surface renders its imperative settings tab, its declarative configuration, or both in one surface. - Plugin-owned settings no longer appear in an app-owned preferences tree. - Synthetic `categoryId: "extensions"` entries from `registerWebView()` do not create visible app navigation sections. - Settings search still finds app schema settings, plugin rows, plugin metadata, and declarative plugin configuration. - Search results open the canonical surface and highlight the target row when applicable. - Existing core/community plugin management pages still show plugin rows, enablement controls, diagnostics, and gear buttons. ## Implementation Notes - Add an internal workspace `SettingsSurface` model with `id`, `title`, `icon`, `group`, and `kind`. - Build app schema surfaces from root category ids: `workspace`, `editor`, `files`, and `appearence`; display `appearence` as `Appearance`. - Build plugin surfaces from core/community plugin metadata plus imperative setting items and valid declarative configuration contributions. - Use plugin manifest ids as plugin surface ids. - Render app schema surfaces through the existing schema form renderer, scoped to the selected surface's `ConfigProperty` entries. - Render plugin surfaces as a composite: imperative `SettingTab` first when present, then owned declarative schema sections. - Remove the recursive sidebar tree, collapsible state, intersection observer, scroll-driven selection, and ancestor-open logic from `configuration.svelte`. - Reuse `SettingItem.icon` and the existing icon rendering path where practical. ## Suggested Files or Specs To Inspect - `packages/workspace/src/lib/components/configuration/configuration.svelte` - `packages/workspace/src/lib/components/configuration/configuration.ts` - `packages/workspace/src/lib/components/configuration/settings-search.ts` - `packages/workspace/src/lib/components/configuration/plugin-settings-target.ts` - `packages/api/src/lib/plugin.ts` - `packages/api/src/lib/configuration.svelte.ts` - `spec/src/30-cross-package-contracts/configuration-and-settings.md` - `spec/src/20-packages/workspace/index.md` ## Validation Commands - `pnpm --filter @lapis-notes/workspace check:all` - `pnpm test:smoke` - `make spec-lint` - `mdbook build spec` - `pnpm backlog:verify-commit @-` - `pnpm backlog:doctor --strict` ## Related Issues - #186 ## Follow-up Tasks ## Implementation Summary Implemented Obsidian-style flat settings navigation with stable Options/Core plugins/Community plugins groups, sidebar icons, canonical plugin settings surfaces for imperative and declarative settings, duplicate plugin surface de-duping, search routing to canonical surfaces, and regression coverage for duplicate keys and schema-toggle remount flashing. <!-- backlog:task_id=TASK-SETTINGS-OBSIDIAN-NAV source_spec=spec/src/30-cross-package-contracts/configuration-and-settings.md -->
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lapis-notes/lapis#192
No description provided.