Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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.4`
- Current version: `0.6.1`
- Min Obsidian version: `1.7.2`

## Commands
Expand All @@ -13,8 +13,9 @@ 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:release # release-validator and workflow tests (node --test)
npm run test:fixture # fixture-script safety tests (node --test)
npm run verify # lint + production build + all tests + fixture tests
npm run verify # lint + production build + Jest + release + fixture tests
```

## Architecture
Expand Down Expand Up @@ -57,20 +58,20 @@ src/explorer/__tests__/*.test.ts Unit/DOM/integration tests for explorer help
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 → direct render, or keyed windowed render via `VirtualList` above 200 rows
**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 for ungrouped, non-manual lists

**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

**Manual sort flow:** Manual sort resolves to list mode, initializes `settings.manualOrder`, attaches `DragSortManager` to row handles, and persists reordered paths through plugin settings.
**Manual sort flow:** Manual sort resolves to ungrouped list mode, initializes `settings.manualOrder`, attaches `DragSortManager` to row handles, and persists reordered paths through plugin settings. The plugin owns one lifetime vault-rename listener that migrates shared manual-order paths even with no explorer panes open. Each view migrates its own Undo snapshots and reconciles Undo against its complete FileIndex. Undo reverses ordering only; it does not undo file operations. Renames while the plugin is disabled or Obsidian is not running cannot reliably preserve path-based order.

## Conventions

- Sorters, groupers, filters, tree models, view-mode helpers, filter-state helpers, and manual-order helpers are pure functions — testable without Obsidian
- FileIndex is the single source of truth for vault file data
- Vault events (create/delete/rename/modify) update FileIndex incrementally, debounced at 300ms
- No network requests. Vault writes are limited to explicit user actions: creating notes/folders and saving plugin settings/manual order.
- Vault events (create/delete/rename/modify) update FileIndex incrementally; view rebuilds are debounced at 300ms
- No network requests. Explicit user actions can create notes or folders, rename files or folders, and move items to the configured trash. Renaming follows Obsidian's internal-link update preference. Plugin settings and manual order are saved locally, including path maintenance after vault renames while the plugin is enabled.
- Obsidian CSS variables for theming, prefixed with `.smart-explorer-`
- Tests use Jest with ts-jest, `__tests__` subdirectory per module

Expand All @@ -83,7 +84,7 @@ node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --fil
node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --remove # remove
```

The script only touches `<vault>/.smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file.
The script only touches `<vault>/smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file.

## Git workflow

Expand All @@ -106,9 +107,9 @@ The script only touches `<vault>/.smart-explorer-large-vault-fixture` and refuse
| Add group mode | `groupers.ts` + `types.ts` (GroupMode union) + `settings-helpers.ts` |
| Add filter | `filters.ts` + `types.ts` (ExplorerQuery) + `SmartExplorerView.ts` (toolbar) |
| Change tree view | `TreeModel.ts` / `treeFolderInfo.ts` + `SmartExplorerView.ts` |
| Change manual ordering | `manualOrder.ts` + `DragSortManager.ts` + `SmartExplorerView.ts` |
| Change manual ordering | `manualOrder.ts` + `DragSortManager.ts` + `SmartExplorerView.ts` + `main.ts` (shared rename tracking) |
| Change create actions | `creationPath.ts` + `SmartExplorerView.ts` |
| Change toolbar layout | `SmartExplorerView.ts` (renderToolbar) + `styles.css` |
| Add settings | `settings.ts` + `settings-tab.ts` + `main.ts` (load/save) |
| Fix rendering | `SmartExplorerView.ts` + `styles.css` |
| Add vault event handling | `SmartExplorerView.ts` (registerVaultEvents) |
| Add vault event handling | `SmartExplorerView.ts` (view index/UI events); `main.ts` (shared rename tracking) |
19 changes: 10 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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.4`
- Current version: `0.6.1`
- Min Obsidian version: `1.7.2`

## Commands
Expand All @@ -13,8 +13,9 @@ 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:release # release-validator and workflow tests (node --test)
npm run test:fixture # fixture-script safety tests (node --test)
npm run verify # lint + production build + all tests + fixture tests
npm run verify # lint + production build + Jest + release + fixture tests
```

## Architecture
Expand Down Expand Up @@ -57,20 +58,20 @@ src/explorer/__tests__/*.test.ts Unit/DOM/integration tests for explorer help
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 → direct render, or keyed windowed render via `VirtualList` above 200 rows
**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 for ungrouped, non-manual lists

**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

**Manual sort flow:** Manual sort resolves to list mode, initializes `settings.manualOrder`, attaches `DragSortManager` to row handles, and persists reordered paths through plugin settings.
**Manual sort flow:** Manual sort resolves to ungrouped list mode, initializes `settings.manualOrder`, attaches `DragSortManager` to row handles, and persists reordered paths through plugin settings. The plugin owns one lifetime vault-rename listener that migrates shared manual-order paths even with no explorer panes open. Each view migrates its own Undo snapshots and reconciles Undo against its complete FileIndex. Undo reverses ordering only; it does not undo file operations. Renames while the plugin is disabled or Obsidian is not running cannot reliably preserve path-based order.

## Conventions

- Sorters, groupers, filters, tree models, view-mode helpers, filter-state helpers, and manual-order helpers are pure functions — testable without Obsidian
- FileIndex is the single source of truth for vault file data
- Vault events (create/delete/rename/modify) update FileIndex incrementally, debounced at 300ms
- No network requests. Vault writes are limited to explicit user actions: creating notes/folders and saving plugin settings/manual order.
- Vault events (create/delete/rename/modify) update FileIndex incrementally; view rebuilds are debounced at 300ms
- No network requests. Explicit user actions can create notes or folders, rename files or folders, and move items to the configured trash. Renaming follows Obsidian's internal-link update preference. Plugin settings and manual order are saved locally, including path maintenance after vault renames while the plugin is enabled.
- Obsidian CSS variables for theming, prefixed with `.smart-explorer-`
- Tests use Jest with ts-jest, `__tests__` subdirectory per module

Expand All @@ -83,7 +84,7 @@ node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --fil
node scripts/prepare-large-vault-fixture.mjs --vault /Users/Roger/my-vault --remove # remove
```

The script only touches `<vault>/.smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file.
The script only touches `<vault>/smart-explorer-large-vault-fixture` and refuses to delete anything without its marker file.

## Git workflow

Expand All @@ -106,9 +107,9 @@ The script only touches `<vault>/.smart-explorer-large-vault-fixture` and refuse
| Add group mode | `groupers.ts` + `types.ts` (GroupMode union) + `settings-helpers.ts` |
| Add filter | `filters.ts` + `types.ts` (ExplorerQuery) + `SmartExplorerView.ts` (toolbar) |
| Change tree view | `TreeModel.ts` / `treeFolderInfo.ts` + `SmartExplorerView.ts` |
| Change manual ordering | `manualOrder.ts` + `DragSortManager.ts` + `SmartExplorerView.ts` |
| Change manual ordering | `manualOrder.ts` + `DragSortManager.ts` + `SmartExplorerView.ts` + `main.ts` (shared rename tracking) |
| Change create actions | `creationPath.ts` + `SmartExplorerView.ts` |
| Change toolbar layout | `SmartExplorerView.ts` (renderToolbar) + `styles.css` |
| Add settings | `settings.ts` + `settings-tab.ts` + `main.ts` (load/save) |
| Fix rendering | `SmartExplorerView.ts` + `styles.css` |
| Add vault event handling | `SmartExplorerView.ts` (registerVaultEvents) |
| Add vault event handling | `SmartExplorerView.ts` (view index/UI events); `main.ts` (shared rename tracking) |
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ 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; closed folders render lazily and long flat lists use windowed rendering, so large vaults stay fast |
| **Browse** | Folder tree by default, with folder counts and compact hover details; closed folders render lazily and long ungrouped, non-manual flat lists use windowed rendering |
| **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 |
| **Edit** | Rename files and folders inline (file extensions stay fixed); move items to the configured trash from the context menu |
| **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 — the mode is remembered between sessions; Manual sort automatically uses list mode for direct drag-and-drop |
Expand All @@ -22,7 +22,9 @@ Built for vaults with hundreds or thousands of notes where the default file tree

### Manual Drag-and-Drop Sorting

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.
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. Manual ordering uses an ungrouped list; tree and grouped manual ordering are not supported. Use **Undo** to revert the last reorder. Undo changes order only: it does not reverse creates, renames, or deletions. Renamed files retain their historical positions, deleted files stay removed, and new files remain sortable, including after Undo. The custom order is saved per vault and persists across sessions.

Rename tracking continues while all Smart Explorer panes are closed, provided the plugin remains enabled. Renames made while the plugin is disabled or Obsidian is not running cannot reliably retain positions because order is stored by path.

## Installation

Expand Down Expand Up @@ -61,21 +63,24 @@ Switch to **Manual** sort mode to drag the handle beside a file and reorder it,
## Compatibility

- Obsidian ≥ 1.7.2
- Desktop and mobile
- Desktop and mobile are declared supported; candidate-specific runtime verification is tracked in the [1.0 readiness report](docs/verification/1.0.0-readiness.md).
- The 1.0 candidate is not release-approved until required desktop, real iOS/Android, minimum-version, upgrade, accessibility, and performance gates pass.

## Privacy

No network requests. File writes only happen when you explicitly create a note or folder.
No network requests. Explicit user actions can create notes or folders, rename files or folders, and move items to the configured trash. Renaming follows Obsidian's internal-link update preference. Plugin settings and manual order are saved locally, including path maintenance after vault renames while the plugin is enabled.

## Development

```bash
npm install # install dependencies
npm run dev # watch mode
npm run build # type-check + production build
npm test # unit tests
npm run lint # eslint
npm run verify # lint + production build + all tests
npm install # install dependencies
npm run dev # watch mode
npm run build # type-check + production build
npm test # unit, DOM, and integration tests
npm run lint # eslint
npm run test:release # release-validator and workflow tests
npm run test:fixture # fixture-script safety tests
npm run verify # lint + production build + Jest + release + fixture tests
```

## License
Expand Down
Loading