mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
focus: keys go where the screen says they go
A password prompt now hands the focus back to whatever had it before it opened, or to the editor or the list when that is gone. Until now the focus was left on nothing once the field went away, so after an :unlock typed in the editor the status line still said NORMAL while j walked the list and dd asked to delete the document. A key that lands outside the editor while it is open is handed back to it for the same reason. A document or folder asked for from the board — T, :12, :e, a search — is now shown instead of being opened in a tree hidden behind the board, and closing such a document goes back to the board. A space switch that reopens a remembered document still keeps the board on screen. Unlocking the vault says so while the key is stretched.
This commit is contained in:
1 parent
e0a4c01654
commit
4bf8634991
3 files changed
+44
-2
No files matched your search
@@ -443,6 +443,15 @@
|
||||
|
||||
if (cmdline !== null || isTypingTarget(event.target)) return
|
||||
|
||||
// While writing, the status line says the editor is listening. A key that
|
||||
// lands anywhere else — the focus left behind by a prompt, a click on the
|
||||
// header — hands the focus back to it instead of walking the list unseen.
|
||||
if (workspace.editing && workspace.pane === 'document' && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
||||
event.preventDefault()
|
||||
hooks.focusEditor()
|
||||
return
|
||||
}
|
||||
|
||||
// Ctrl-P: find anything, in any space — the one search that is not
|
||||
// confined to where you are.
|
||||
if (event.ctrlKey && !event.metaKey && !event.altKey && event.key === 'p') {
|
||||
|
||||
@@ -10,15 +10,34 @@
|
||||
* field alone: it is not the login, and their menus redrawn on every key
|
||||
* are a flicker of their own.
|
||||
*/
|
||||
import { untrack } from 'svelte'
|
||||
import { hooks } from './commands'
|
||||
import { workspace } from './store.svelte'
|
||||
|
||||
let value = $state('')
|
||||
let input = $state<HTMLInputElement>()
|
||||
/*
|
||||
* Where the keys went before the question took them. Putting the field away
|
||||
* would otherwise leave the focus nowhere, and the next keys — meant for the
|
||||
* editor the status line still says is listening — would walk the list.
|
||||
*/
|
||||
let returnTo: HTMLElement | null = null
|
||||
let asking = false
|
||||
|
||||
$effect(() => {
|
||||
if (workspace.secret) {
|
||||
value = ''
|
||||
if (!asking) returnTo = document.activeElement as HTMLElement | null
|
||||
asking = true
|
||||
input?.focus()
|
||||
} else if (asking) {
|
||||
asking = false
|
||||
untrack(() => {
|
||||
if (returnTo?.isConnected && returnTo !== document.body) returnTo.focus()
|
||||
else if (workspace.editing && workspace.pane === 'document') hooks.focusEditor()
|
||||
else hooks.focusList()
|
||||
})
|
||||
returnTo = null
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -276,6 +276,8 @@ class Workspace {
|
||||
if (this.vault.unlocked) return true
|
||||
const password = await this.askSecret('vault password')
|
||||
if (password === null) return false
|
||||
// The key is stretched on purpose, which takes a moment worth saying.
|
||||
this.say('unlocking …')
|
||||
this.vault = await api.unlockVault(password)
|
||||
this.say('vault unlocked')
|
||||
return true
|
||||
@@ -583,7 +585,8 @@ class Workspace {
|
||||
}
|
||||
if (spot && this.parentId === spot.parentId) {
|
||||
if (spot.openId !== null && this.nodes.some((n) => n.id === spot.openId)) {
|
||||
await this.openNode(spot.openId)
|
||||
// Reopened under the board, if that is what is on screen.
|
||||
await this.openNode(spot.openId, false, true)
|
||||
this.pane = spot.pane
|
||||
} else {
|
||||
this.cursor = Math.min(spot.cursor, Math.max(this.nodes.length - 1, 0))
|
||||
@@ -637,6 +640,8 @@ class Workspace {
|
||||
}
|
||||
|
||||
async search(query: string, global = this.globalSearch) {
|
||||
// The results are rows in the list, which the board would hide.
|
||||
if (query && this.view === 'board') this.closeBoard()
|
||||
this.query = query
|
||||
this.globalSearch = global && query !== ''
|
||||
this.cursor = 0
|
||||
@@ -648,10 +653,19 @@ class Workspace {
|
||||
this.cursor = Math.min(Math.max(this.cursor + delta, 0), this.nodes.length - 1)
|
||||
}
|
||||
|
||||
async openNode(id: number, edit = false) {
|
||||
async openNode(id: number, edit = false, underBoard = false) {
|
||||
if (this.open?.id !== id) await this.flush()
|
||||
|
||||
const node = await api.getNode(id)
|
||||
// What is asked for from the board — `:12`, `T`, a search — is shown, not
|
||||
// opened behind it; closing a document goes back to the board.
|
||||
if (this.view === 'board' && !underBoard) {
|
||||
if (isContainer(node)) this.closeBoard()
|
||||
else {
|
||||
this.view = 'tree'
|
||||
this.returnTo = 'board'
|
||||
}
|
||||
}
|
||||
if (isContainer(node)) {
|
||||
await this.goTo(node.id)
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user