Triage the whole queue from the keyboard, and never type an n
The last of the UX review's item 8. Ctrl+. and Ctrl+, step through the underlines from anywhere in the text; the card that opens takes focus and answers Tab / Shift+Tab / Enter / Del / ? / Esc itself. Answering a card advances to the next by itself, and the last one closes and puts the caret back in the prose — so a document is triaged in five presses of Enter. The item asked for bare Tab or n/p. Neither can exist in a text editor: an unmodified letter is a letter. They work fine once a card holds focus, which is where the item wanted them; getting there needs a chord that is safe to press mid-sentence, and mid-composition, so the entry keys are IME-guarded like every other binding. The queue is the underlines read off the decoration DOM in document order, not the suggestion list: a stop she cannot see is worse than one she never visits, and it guarantees the card can anchor itself. Escape is stopped at the card. Unhandled it would also have left distraction-free mode, restoring the sidebar and — via the rail-follows-the- mode fix — pulling the rail out from under her mid-triage. The legend is bilingual and leads with the pair language, unlike the card's English buttons: those name what she is learning, this is an instruction for operating Petal, like the status bar. Key names are as printed on her keyboard (Entrée, Suppr, Intro, Supr). The es pack's own punctuation test caught the "?" and is right in general; the key cap is one named exemption. Verified in a real browser at 1517x810 on a fresh database with no model, over CDP — a keystroke feature deserves real keystrokes. Both layouts, wrap in both directions, the accept/dismiss/advance loop, Ask Petal and back, the full triage-to-empty criterion, and Accept-all clicked from a keyboard card. The wiring has no unit test for the reason items 6, 7 and 8 recorded: jsdom has no layout. triage.ts is pure and tested; browser-verified is written down as browser-verified. Claude-Session: https://claude.ai/code/session_01GJHNvirh7Hzhc9RL3HAvz7
This commit is contained in:
@@ -203,6 +203,22 @@ describe('the zh pack', () => {
|
||||
expect(p.status.petalsToPolish(2).en).toContain('petals to polish')
|
||||
})
|
||||
|
||||
// The triage legend is the only place a Petal binding is written down, so a
|
||||
// pack that drops a key drops the feature for that pair: nothing else on
|
||||
// screen says Tab moves to the next underline. The key caps themselves stay
|
||||
// as they are printed on the keyboard, which is why the English half is not
|
||||
// the interesting one — a pack may well translate "Entrée" and be right to.
|
||||
it.each(PACKS)('names every triage key in both halves ($code)', (p) => {
|
||||
const { native, en } = p.editor.triageHint
|
||||
expect(native, `${p.code} has no pair-language triage legend`).toBeTruthy()
|
||||
expect(en, `${p.code} has no English triage legend`).toBeTruthy()
|
||||
expect(en).toBe('Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit')
|
||||
// Five bindings, five entries — in whatever the pack calls the keys.
|
||||
expect(native.split('·'), `${p.code} lists the wrong number of keys`).toHaveLength(5)
|
||||
expect(native, `${p.code} loses the Tab key`).toContain('Tab')
|
||||
expect(native, `${p.code} loses the Ask Petal key`).toContain('?')
|
||||
})
|
||||
|
||||
it.each(PACKS)('labels every companion, tone and style ($code)', async (p) => {
|
||||
const { COMPANIONS } = await import('../components/Companion/companions')
|
||||
for (const c of COMPANIONS) {
|
||||
@@ -414,7 +430,12 @@ describe('the es pack', () => {
|
||||
}
|
||||
walk(es, '')
|
||||
expect(lines.length).toBeGreaterThan(40)
|
||||
// The one exemption, and it is not a question: `triageHint` is a legend of
|
||||
// key caps, and its "?" is the key she presses to ask Petal — the same
|
||||
// literal printed on the keyboard, no more Spanish punctuation than "Esc".
|
||||
const keyCaps = new Set(['editor.triageHint'])
|
||||
for (const { native, where } of lines) {
|
||||
if (keyCaps.has(where)) continue
|
||||
if (native.includes('?')) expect(native, `${where} closes ? without ¿`).toContain('¿')
|
||||
if (native.includes('!')) expect(native, `${where} closes ! without ¡`).toContain('¡')
|
||||
}
|
||||
|
||||
@@ -374,6 +374,11 @@ export const es: Pack = {
|
||||
replace: 'Reemplazar',
|
||||
replaceAll: 'Todo',
|
||||
translateLabel: 'Traducción · Translate',
|
||||
// Intro, Supr, Esc — as they are printed on a Spanish keyboard.
|
||||
triageHint: {
|
||||
native: 'Tab siguiente · Intro aceptar · Supr descartar · ? preguntar a Petal · Esc salir',
|
||||
en: 'Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit',
|
||||
},
|
||||
spelling: 'Ortografía · Spelling',
|
||||
noSuggestions: 'Sin sugerencias · No suggestions',
|
||||
addToDictionary: 'Agregar al diccionario · Add to dictionary',
|
||||
|
||||
@@ -316,6 +316,13 @@ export const fr: Pack = {
|
||||
replace: 'Remplacer',
|
||||
replaceAll: 'Tout',
|
||||
translateLabel: 'Traduction · Translate',
|
||||
// The key names are the ones printed on a French keyboard — Entrée, Suppr,
|
||||
// Échap — not their English equivalents. A legend she has to translate back
|
||||
// to find the key is not a legend.
|
||||
triageHint: {
|
||||
native: 'Tab suivant · Entrée accepter · Suppr ignorer · ? demander à Petal · Échap quitter',
|
||||
en: 'Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit',
|
||||
},
|
||||
spelling: 'Orthographe · Spelling',
|
||||
noSuggestions: 'Aucune suggestion · No suggestions',
|
||||
addToDictionary: 'Ajouter au dictionnaire · Add to dictionary',
|
||||
|
||||
@@ -294,6 +294,10 @@ export const ptPT: Pack = {
|
||||
replace: 'Substituir',
|
||||
replaceAll: 'Tudo',
|
||||
translateLabel: 'Tradução · Translate',
|
||||
triageHint: {
|
||||
native: 'Tab seguinte · Enter aceitar · Del ignorar · ? perguntar à Petal · Esc sair',
|
||||
en: 'Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit',
|
||||
},
|
||||
spelling: 'Ortografia · Spelling',
|
||||
noSuggestions: 'Sem sugestões · No suggestions',
|
||||
addToDictionary: 'Adicionar ao dicionário · Add to dictionary',
|
||||
|
||||
@@ -205,6 +205,10 @@ export const zh: Pack = {
|
||||
replace: '替换',
|
||||
replaceAll: '全部',
|
||||
translateLabel: '翻译 · Translate',
|
||||
triageHint: {
|
||||
native: 'Tab 下一处 · Enter 采纳 · Del 忽略 · ? 问问 Petal · Esc 退出',
|
||||
en: 'Tab next · Enter accept · Del dismiss · ? Ask Petal · Esc exit',
|
||||
},
|
||||
spelling: '拼写 · Spelling',
|
||||
noSuggestions: '没有建议 · No suggestions',
|
||||
addToDictionary: '添加到词典 · Add to dictionary',
|
||||
|
||||
@@ -195,6 +195,13 @@ export interface Pack {
|
||||
// opposite case — its whole subject is her own language — so it says so in
|
||||
// her language first. The pack holds the rendered string, separator and all.
|
||||
translateLabel: string
|
||||
// The key map shown along the bottom of a card opened by keyboard triage.
|
||||
// Unlike the card's buttons — Accept, Dismiss, Ask Petal, which stay English
|
||||
// because they name the thing she is learning to talk about — this is an
|
||||
// instruction for using Petal, so it is bilingual like the status bar. The
|
||||
// key names themselves (Tab, Enter, Esc) are what is printed on her
|
||||
// keyboard, so they don't translate.
|
||||
triageHint: Line
|
||||
spelling: string
|
||||
noSuggestions: string
|
||||
addToDictionary: string
|
||||
|
||||
Reference in New Issue
Block a user