feat(cli): redesign Notion page picker UI and add skip-empty flow (#78)

Rework the inline picker to use a cleaner visual style (filled/empty
square glyphs, bordered layout, clack-style header) and streamlined
keybindings (Enter to confirm, Escape to quit, Right Arrow to expand).
Replace the transient "select at least one" hint with a skip-empty
confirmation prompt that exits cleanly via quit-without-save.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Luca Martial 2026-05-13 17:28:48 -04:00 committed by GitHub
parent 9ecb8cb119
commit f219ba22a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 126 additions and 86 deletions

View file

@ -11,7 +11,6 @@ import {
selectAllVisible,
selectNone,
toggleChecked,
TRANSIENT_HINT_DURATION_MS,
visibleNodeIds,
type NotionPickerPageInput,
} from './notion-page-picker-tree.js';
@ -223,22 +222,24 @@ describe('bulk actions and reducer effects', () => {
});
});
it('blocks empty saves, updates search state, and quits without saving', () => {
it('prompts skip-empty confirmation on empty save, updates search state, and quits without saving', () => {
const state = buildInitialState({
tree: buildPickerTree(pages()),
existingRootPageIds: [],
currentCrawlMode: 'selected_roots',
});
const blockedSave = reducer(state, 'save-request', 9000);
expect(blockedSave).toEqual({
next: {
...state,
transientHint: {
text: 'Select at least one page or press q to quit',
expiresAt: 9000 + TRANSIENT_HINT_DURATION_MS,
},
},
const emptySave = reducer(state, 'save-request');
expect(emptySave).toEqual({
next: { ...state, pendingConfirm: 'skip-empty' },
effect: null,
});
expect(reducer(emptySave.next, 'save-confirm')).toEqual({
next: { ...state, pendingConfirm: null },
effect: 'quit-without-save',
});
expect(reducer(emptySave.next, 'save-cancel')).toEqual({
next: { ...state, pendingConfirm: null },
effect: null,
});
expect(
@ -262,7 +263,7 @@ describe('bulk actions and reducer effects', () => {
const withHint = {
...state,
transientHint: {
text: 'Select at least one page or press q to quit',
text: 'Select at least one page or press esc to cancel',
expiresAt: 11500,
},
};