feat: simplify ask UI copy and note shortcuts

This commit is contained in:
Erik Kotsiuba
2026-04-19 16:32:27 +02:00
parent fcd1f1bce5
commit 9ab368ad6b
7 changed files with 39 additions and 19 deletions
+1
View File
@@ -164,6 +164,7 @@ Behavior details:
- free-form answer editors support pi-style `@` file path autocomplete for quickly mentioning project files - free-form answer editors support pi-style `@` file path autocomplete for quickly mentioning project files
- `Esc` closes the editor and returns to navigation mode - `Esc` closes the editor and returns to navigation mode
- `Ctrl+C` dismisses the entire ask flow immediately, even from note/free-form editing, without saving the current draft - `Ctrl+C` dismisses the entire ask flow immediately, even from note/free-form editing, without saving the current draft
- use `n` for the active option note and `Shift+N` for the current question note
- `Space` toggles the active option on single-select questions too, but does not auto-advance - `Space` toggles the active option on single-select questions too, but does not auto-advance
## Local development ## Local development
+4 -4
View File
@@ -80,8 +80,8 @@ This document defines the stable external behavior. It does not explain internal
- single-select, multi-select, and preview questions - single-select, multi-select, and preview questions
- inline free-form answers for non-preview questions - inline free-form answers for non-preview questions
- pi-style `@` file path autocomplete inside free-form answer and note editors - pi-style `@` file path autocomplete inside free-form answer and note editors
- question notes via `Ctrl+N` - question notes via `Shift+N`
- option notes via `N` - option notes via `n`
- number-key quick selection - number-key quick selection
- submit/cancel review tab - submit/cancel review tab
- transcript-friendly call and result rendering - transcript-friendly call and result rendering
@@ -97,8 +97,8 @@ Main flow:
- `Ctrl+C`: dismiss the entire flow immediately, even while editing a note or free-form answer - `Ctrl+C`: dismiss the entire flow immediately, even while editing a note or free-form answer
- `1..9`: select or toggle the matching option - `1..9`: select or toggle the matching option
- `Space`: toggle the active option - `Space`: toggle the active option
- `N`: edit the active option note - `n`: edit the active option note
- `Ctrl+N`: edit the current question note - `Shift+N`: edit the current question note
Editing flow: Editing flow:
+10 -10
View File
@@ -12,17 +12,17 @@ export const UI_DIMENSIONS = {
} as const; } as const;
export const UI_TEXT = { export const UI_TEXT = {
questionNoteTitle: "Question note", questionNoteTitle: "Note",
reviewTitle: "Review your answers", reviewTitle: "Review answers",
readyToSubmit: "Ready to submit your answers?", readyToSubmit: "Submit answers?",
unanswered: "→ (unanswered)", unanswered: "→ unanswered",
footerInput: " Enter submit · Esc save and close", footerInput: " Enter submit · Esc close",
footerNote: " Enter save · Esc save and close", footerNote: " Enter save · Esc close",
footerSubmit: " ↑↓ select · Enter confirm · Esc cancel", footerSubmit: " ↑↓ select · Enter confirm · Esc cancel",
footerMulti: footerMulti:
" ⇆ tab · ↑↓ select · Space toggle · Enter continue · N option note · Ctrl+N question note · Esc dismiss · 1-9 quick toggle", " ⇆ tab · ↑↓ select · Space toggle · Enter continue · N/Shift+N note · Esc dismiss",
footerDefault: footerDefault:
" ⇆ tab · ↑↓ select · Enter confirm · N option note · Ctrl+N question note · Esc dismiss", " ⇆ tab · ↑↓ select · Enter confirm · N/Shift+N note · Esc dismiss",
editorPlaceholderInput: "Type your answer...", editorPlaceholderInput: "Type answer...",
editorPlaceholderNote: "Add a note...", editorPlaceholderNote: "Add note...",
} as const; } as const;
+2 -2
View File
@@ -89,11 +89,11 @@ function getNavigationInputCommand(data: string): AskInputCommand {
} }
function isOptionNoteShortcut(data: string): boolean { function isOptionNoteShortcut(data: string): boolean {
return data === "n" || data === "N"; return data === "n";
} }
function isQuestionNoteShortcut(data: string): boolean { function isQuestionNoteShortcut(data: string): boolean {
return matchesKey(data, Key.ctrl("n")); return data === "N";
} }
function parseDigit(data: string): number | null { function parseDigit(data: string): number | null {
+19
View File
@@ -103,3 +103,22 @@ test("ctrl+c dismisses the flow from both navigation and editing modes", () => {
kind: "dismiss", kind: "dismiss",
}); });
}); });
test("note shortcuts use n for option notes and Shift+N for question notes", () => {
const navigation = createInitialState({
questions: [
{
id: "q1",
prompt: "Question?",
options: [{ value: "a", label: "A" }],
},
],
});
assert.deepEqual(getInputCommand(navigation, "n"), {
kind: "openOptionNote",
});
assert.deepEqual(getInputCommand(navigation, "N"), {
kind: "openQuestionNote",
});
});
+2 -2
View File
@@ -74,6 +74,6 @@ test("renderEditorBlock reapplies background after editor reset sequences", () =
}); });
test("editing footers do not advertise tab navigation", () => { test("editing footers do not advertise tab navigation", () => {
assert.equal(renderFooterText("input"), " Enter submit · Esc save and close"); assert.equal(renderFooterText("input"), " Enter submit · Esc close");
assert.equal(renderFooterText("note"), " Enter save · Esc save and close"); assert.equal(renderFooterText("note"), " Enter save · Esc close");
}); });
+1 -1
View File
@@ -80,7 +80,7 @@ test("selected custom option keeps its label and renders editor below", () => {
}); });
assert(lines.some((line) => line.includes("Type your own"))); assert(lines.some((line) => line.includes("Type your own")));
assert(lines.some((line) => line.includes("Type your answer..."))); assert(lines.some((line) => line.includes("Type answer...")));
}); });
test("selected multiline custom option renders full editor block", () => { test("selected multiline custom option renders full editor block", () => {