mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
board: F jumps to a card by letter
`F` on the board puts a letter or two over every card in view, as it does over links in the reader, and typing one puts the cursor on that card; Enter then opens its notes as before. Hints are pinned where their targets are when they appear, so `F` pressed while a pane was still sliding in — the board just opened, a space just switched to — put them where the targets were going to be. They now wait for the pane to settle.
This commit is contained in:
1 parent
9fce0112e2
commit
439d5b083b
3 files changed
+25
-2
No files matched your search
@@ -214,6 +214,7 @@ you were. On the board, `o` or `c` puts a card on the column under the cursor.
|
||||
| `D` | due date — `fri`, `tm`, `+3d`, `+2w`, `10-31`, `2026-10-31` |
|
||||
| `R` | rename the card, or the column when it has none |
|
||||
| `z` | show done cards older than a week |
|
||||
| `F` | a letter over every card in view; typing it puts the cursor on that card |
|
||||
| `x`, `dd` | delete the card |
|
||||
| `q`, `Esc` | back to the tree |
|
||||
|
||||
|
||||
+23
-2
@@ -45,6 +45,7 @@
|
||||
let importRoot = false
|
||||
let shell = $state<HTMLDivElement>()
|
||||
let overlayEl = $state<HTMLDivElement>()
|
||||
let boardEl = $state<HTMLDivElement>()
|
||||
/** The first half of `gg`, `dd`, `]]` …, shown until the second comes. */
|
||||
let pending = $state('')
|
||||
/** `F`: the pane whose links and buttons are wearing hints right now. */
|
||||
@@ -390,6 +391,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* `F`: the hints are pinned where the targets are, so a pane still sliding
|
||||
* in — a space switch, the board just opened — is let settle first.
|
||||
*/
|
||||
async function showHints(root: HTMLElement) {
|
||||
// What moves the root may be an animation on a pane around it. A blinking
|
||||
// cursor never finishes, so only what ends is waited for.
|
||||
const settling = document.getAnimations().filter((animation) => {
|
||||
const target = (animation.effect as KeyframeEffect | null)?.target
|
||||
if (!target || animation.effect?.getComputedTiming().endTime === Infinity) return false
|
||||
return target.contains(root) || root.contains(target)
|
||||
})
|
||||
await Promise.all(settling.map((animation) => animation.finished.catch(() => {})))
|
||||
if (root.isConnected) hintRoot = root
|
||||
}
|
||||
|
||||
/** `gx`: the file as the browser shows it, in a tab of its own. */
|
||||
function openInTab() {
|
||||
const file = workspace.target?.file
|
||||
@@ -487,6 +504,10 @@
|
||||
case 'z':
|
||||
workspace.showOldDone = !workspace.showOldDone
|
||||
return true
|
||||
case 'F':
|
||||
// A letter over every card in view: typing it puts the cursor there.
|
||||
if (boardEl) void showHints(boardEl)
|
||||
return true
|
||||
case ' ':
|
||||
void workspace.guard(() => workspace.toggleDone())
|
||||
return true
|
||||
@@ -772,7 +793,7 @@
|
||||
// on its other key.
|
||||
event.preventDefault()
|
||||
const root = reading ? hooks.hintRoot() : null
|
||||
if (root) hintRoot = root
|
||||
if (root) void showHints(root)
|
||||
break
|
||||
}
|
||||
case 'm':
|
||||
@@ -906,7 +927,7 @@
|
||||
{#if workspace.view === 'board'}
|
||||
<!-- The board takes the whole width: its columns are the two panes. -->
|
||||
<div class="panes board switch" style="--dir: {workspace.switchDirection}">
|
||||
<div class="window focused"><Board /></div>
|
||||
<div class="window focused" bind:this={boardEl}><Board /></div>
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
['D', 'due date: fri, tm, +3d, 10-31 …'],
|
||||
['R', 'rename the card, or the list when it is empty'],
|
||||
['z', 'show done cards older than a week'],
|
||||
['F', 'a letter over every card in view — type it to put the cursor there'],
|
||||
['r', 'read the board again, for changes made elsewhere'],
|
||||
['x · dd', 'delete the card (asks y/N)'],
|
||||
['q · Esc', 'back to the tree'],
|
||||
|
||||
Reference in new issue
Block a user