From 9cf5d2a58ece261d481fe829c3e856332805c987 Mon Sep 17 00:00:00 2001 From: Roger Deng <13251150+rogerdigital@users.noreply.github.com> Date: Mon, 24 Aug 2026 15:04:11 +0800 Subject: [PATCH] docs: document explorer optimization behavior --- AGENTS.md | 36 ++++++++++++++++++++++++++++-------- CLAUDE.md | 36 ++++++++++++++++++++++++++++-------- README.md | 14 ++++++++------ docs/release-checklist.md | 5 +++++ 4 files changed, 69 insertions(+), 22 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 173db71..d58208f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,17 +3,18 @@ Obsidian plugin — alternative side-pane file explorer with tree/list browsing, sorting, grouping, filtering, and manual order. - Plugin ID: `smart-explorer` -- Current version: `0.5.0` +- Current version: `0.5.4` - Min Obsidian version: `1.7.2` ## Commands ```bash -npm run dev # esbuild watch mode -npm run build # tsc check + esbuild production -npm test # jest with ts-jest -npm run lint # eslint -npm run verify # lint + production build + all tests +npm run dev # esbuild watch mode +npm run build # tsc check + esbuild production +npm test # jest with ts-jest (node + jsdom suites) +npm run lint # eslint +npm run test:fixture # fixture-script safety tests (node --test) +npm run verify # lint + production build + all tests + fixture tests ``` ## Architecture @@ -35,6 +36,8 @@ src/explorer/sorters.ts Pure sorting functions (8 modes, path tie-br src/explorer/groupers.ts Pure grouping functions (5 modes: none, folder, extension, modified-month, top-folder) src/explorer/filters.ts Pure filter functions (search, extension, file kind, date range) src/explorer/filterState.ts Clear/detect active search and filters +src/explorer/queryNormalization.ts Shared search-text normalization for filters + state +src/explorer/focusNavigation.ts Pure key → focus/expand/activate resolver for list/tree rows src/explorer/fileRow.ts File row display formatting helpers src/explorer/creationPath.ts Pure helpers for new note/folder target paths src/explorer/treeFolderInfo.ts Tree folder hover metadata helpers @@ -43,14 +46,20 @@ src/explorer/revealPath.ts Pure path-reveal helpers for active file / s src/explorer/touchLongPress.ts Pure touch long-press threshold helpers src/explorer/viewMode.ts Resolves effective tree/list mode + manual seed sort +src/explorer/rowHeight.ts List row-height constants (44px desktop / 52px mobile) src/settings/settings.ts Settings type + defaults +src/settings/settings-normalization.ts Strict validation/migration of persisted settings src/settings/settings-tab.ts PluginSettingTab UI src/settings/settings-helpers.ts Sort/group option lists (shared by toolbar + settings) +src/test-utils/obsidianDom.ts jsdom shims (Obsidian DOM helpers, deterministic layout) -src/explorer/__tests__/*.test.ts Unit tests for pure explorer helpers and models +src/explorer/__tests__/*.test.ts Unit/DOM/integration tests for explorer helpers and models +scripts/prepare-large-vault-fixture.mjs Marker-protected synthetic fixture generator ``` -**List data flow:** `FileIndex.build()` → hidden-extension filter → `buildSections(records, query)` → filter → sort → group → `VirtualList` render +**List data flow:** `FileIndex.build()` → hidden-extension filter → `buildSections(records, query)` → filter → sort → group → direct render, or keyed windowed render via `VirtualList` above 200 rows + +**Keyboard model:** the list container holds the single tab stop and DOM focus; the active row is tracked via `aria-activedescendant` (pinned across windowed renders). Selection highlight follows `workspace.file-open` without auto-reveal. **Tree data flow:** `FileIndex.build()` → hidden-extension filter → `buildTree(records, query)` → filter → folder tree sort → recursive tree render @@ -65,6 +74,17 @@ src/explorer/__tests__/*.test.ts Unit tests for pure explorer helpers and mod - Obsidian CSS variables for theming, prefixed with `.smart-explorer-` - Tests use Jest with ts-jest, `__tests__` subdirectory per module +## Test vault and large-vault fixture + +`/Users/Roger/my-vault` is the dedicated local development/test vault (the plugin folder symlinks to a repo checkout). For large-vault testing: + +```bash +node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --files 5000 # create +node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --remove # remove +``` + +The script only touches `/.smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file. + ## Git workflow - `main` branch: PR required, CI `verify` job must pass, no force push, no deletion diff --git a/CLAUDE.md b/CLAUDE.md index 173db71..d58208f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,17 +3,18 @@ Obsidian plugin — alternative side-pane file explorer with tree/list browsing, sorting, grouping, filtering, and manual order. - Plugin ID: `smart-explorer` -- Current version: `0.5.0` +- Current version: `0.5.4` - Min Obsidian version: `1.7.2` ## Commands ```bash -npm run dev # esbuild watch mode -npm run build # tsc check + esbuild production -npm test # jest with ts-jest -npm run lint # eslint -npm run verify # lint + production build + all tests +npm run dev # esbuild watch mode +npm run build # tsc check + esbuild production +npm test # jest with ts-jest (node + jsdom suites) +npm run lint # eslint +npm run test:fixture # fixture-script safety tests (node --test) +npm run verify # lint + production build + all tests + fixture tests ``` ## Architecture @@ -35,6 +36,8 @@ src/explorer/sorters.ts Pure sorting functions (8 modes, path tie-br src/explorer/groupers.ts Pure grouping functions (5 modes: none, folder, extension, modified-month, top-folder) src/explorer/filters.ts Pure filter functions (search, extension, file kind, date range) src/explorer/filterState.ts Clear/detect active search and filters +src/explorer/queryNormalization.ts Shared search-text normalization for filters + state +src/explorer/focusNavigation.ts Pure key → focus/expand/activate resolver for list/tree rows src/explorer/fileRow.ts File row display formatting helpers src/explorer/creationPath.ts Pure helpers for new note/folder target paths src/explorer/treeFolderInfo.ts Tree folder hover metadata helpers @@ -43,14 +46,20 @@ src/explorer/revealPath.ts Pure path-reveal helpers for active file / s src/explorer/touchLongPress.ts Pure touch long-press threshold helpers src/explorer/viewMode.ts Resolves effective tree/list mode + manual seed sort +src/explorer/rowHeight.ts List row-height constants (44px desktop / 52px mobile) src/settings/settings.ts Settings type + defaults +src/settings/settings-normalization.ts Strict validation/migration of persisted settings src/settings/settings-tab.ts PluginSettingTab UI src/settings/settings-helpers.ts Sort/group option lists (shared by toolbar + settings) +src/test-utils/obsidianDom.ts jsdom shims (Obsidian DOM helpers, deterministic layout) -src/explorer/__tests__/*.test.ts Unit tests for pure explorer helpers and models +src/explorer/__tests__/*.test.ts Unit/DOM/integration tests for explorer helpers and models +scripts/prepare-large-vault-fixture.mjs Marker-protected synthetic fixture generator ``` -**List data flow:** `FileIndex.build()` → hidden-extension filter → `buildSections(records, query)` → filter → sort → group → `VirtualList` render +**List data flow:** `FileIndex.build()` → hidden-extension filter → `buildSections(records, query)` → filter → sort → group → direct render, or keyed windowed render via `VirtualList` above 200 rows + +**Keyboard model:** the list container holds the single tab stop and DOM focus; the active row is tracked via `aria-activedescendant` (pinned across windowed renders). Selection highlight follows `workspace.file-open` without auto-reveal. **Tree data flow:** `FileIndex.build()` → hidden-extension filter → `buildTree(records, query)` → filter → folder tree sort → recursive tree render @@ -65,6 +74,17 @@ src/explorer/__tests__/*.test.ts Unit tests for pure explorer helpers and mod - Obsidian CSS variables for theming, prefixed with `.smart-explorer-` - Tests use Jest with ts-jest, `__tests__` subdirectory per module +## Test vault and large-vault fixture + +`/Users/Roger/my-vault` is the dedicated local development/test vault (the plugin folder symlinks to a repo checkout). For large-vault testing: + +```bash +node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --files 5000 # create +node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --remove # remove +``` + +The script only touches `/.smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file. + ## Git workflow - `main` branch: PR required, CI `verify` job must pass, no force push, no deletion diff --git a/README.md b/README.md index c5f9599..18ba5a9 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,19 @@ Built for vaults with hundreds or thousands of notes where the default file tree | Category | Options | |----------|---------| -| **Browse** | Folder tree by default, with folder counts and compact hover details | +| **Browse** | Folder tree by default, with folder counts and compact hover details; closed folders render lazily and long flat lists use windowed rendering, so large vaults stay fast | | **Create** | Create notes and folders via toolbar, context menu, or command palette — with inline name editing | | **Edit** | Rename files inline; extensions stay fixed so only the name changes | | **Sort** | Name (A-Z / Z-A), modified date, created date, extension, file size, manual drag order | | **Filter** | Search by name/path, extension, file kind (all / markdown / non-markdown / images), date range (1d / 7d / 30d) | -| **View** | Tree/list toggle; Manual sort automatically uses list mode for direct drag-and-drop | +| **View** | Tree/list toggle — the mode is remembered between sessions; Manual sort automatically uses list mode for direct drag-and-drop | | **Commands** | Open, focus search, reveal active file, new note, new folder — all in the Command Palette | -| **Keyboard** | Focus search, clear search, move through rows, and open selected files | +| **Keyboard** | Full keyboard navigation: arrows move through rows, Home/End jump, arrow keys open and close folders, Enter opens files, and `Alt+Arrow` reorders files in Manual mode | | **Settings** | Default sort/group mode, hidden extensions, reset manual order | ### Manual Drag-and-Drop Sorting -Switch to **Manual** sort mode to drag the handle beside a file and reorder it. The starting order matches whatever sort you were viewing ("what you see is what you drag"), shown in a toolbar hint. Use **Undo** to revert the last reorder. The custom order is saved per vault, keeps new files draggable, and persists across sessions. Works on both desktop and mobile. +Switch to **Manual** sort mode to drag the handle beside a file and reorder it, or keep your hands on the keyboard and use `Alt+ArrowUp` / `Alt+ArrowDown` on the selected file. The starting order matches whatever sort you were viewing ("what you see is what you drag"), shown in a toolbar hint. Use **Undo** to revert the last reorder. The custom order is saved per vault, keeps new files draggable, and persists across sessions. Works on both desktop and mobile. ## Installation @@ -52,8 +52,10 @@ Switch to **Manual** sort mode to drag the handle beside a file and reorder it. - `Cmd/Ctrl+F` focuses the search box - `Esc` clears search text or closes the filter row -- `Arrow Up/Down` moves through file rows -- `Enter` opens the focused file +- `Arrow Up/Down` moves through rows; `Home`/`End` jump to the first/last row +- `Arrow Right/Left` opens/closes the focused folder in tree mode +- `Enter` or `Space` opens the focused file or toggles the focused folder +- `Alt+ArrowUp` / `Alt+ArrowDown` moves the selected file in Manual sort mode (announced via screen reader) - Command Palette actions: **Smart Explorer: Open**, **Focus search**, **Reveal active file**, **New note**, **New folder** ## Compatibility diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 8641151..3035a4f 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -9,6 +9,10 @@ - [ ] Changelog / release notes drafted - [ ] No network requests in codebase (`grep -rn "fetch\|XMLHttpRequest" src/`) - [ ] Vault writes are limited to explicit create-note/create-folder actions and plugin settings +- [ ] Large-vault check (optional but recommended before perf-touching releases): + - [ ] Create the synthetic fixture: `node scripts/prepare-large-vault-fixture.mjs --vault --files 5000` + - [ ] Closed tree shows folder summaries only; flat list stays smooth and bounded + - [ ] Remove the fixture afterwards: `node scripts/prepare-large-vault-fixture.mjs --vault --remove`; confirm the vault is otherwise untouched - [ ] Plugin tested in Obsidian vault: - [ ] Loads without console errors - [ ] File list displays correctly @@ -17,6 +21,7 @@ - [ ] New note and new folder actions create items in the expected folder - [ ] Collapse all and reveal active file work in tree mode - [ ] Manual drag handles and undo work in Manual sort mode + - [ ] Keyboard navigation works: Tab enters once, arrows move, ArrowRight/Left open/close folders, Enter opens files, Alt+Arrow reorders in Manual mode - [ ] Settings persist after reload - [ ] Vault events (create/delete/rename/modify) trigger reindex