mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
added document move
This commit is contained in:
1 parent
714a84089a
commit
1a37420461
4 files changed
+57
-4
No files matched your search
@@ -276,6 +276,15 @@
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
void workspace.guard(() => workspace.openSelected())
|
void workspace.guard(() => workspace.openSelected())
|
||||||
break
|
break
|
||||||
|
case 'm':
|
||||||
|
// Pick a node up here, walk to a folder, put it down with `p`.
|
||||||
|
event.preventDefault()
|
||||||
|
workspace.mark()
|
||||||
|
break
|
||||||
|
case 'p':
|
||||||
|
event.preventDefault()
|
||||||
|
void workspace.guard(() => workspace.drop())
|
||||||
|
break
|
||||||
case 'o':
|
case 'o':
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
void runCommand('new')
|
void runCommand('new')
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
['O', 'new folder here'],
|
['O', 'new folder here'],
|
||||||
['i · a', 'edit the open document'],
|
['i · a', 'edit the open document'],
|
||||||
['R', 'rename what is marked — document, folder or card'],
|
['R', 'rename what is marked — document, folder or card'],
|
||||||
|
['m / p', 'pick a node up, then drop it into the folder you walk to'],
|
||||||
['b', "open this space's board"],
|
['b', "open this space's board"],
|
||||||
['Esc · q', 'back out to the list'],
|
['Esc · q', 'back out to the list'],
|
||||||
['/', 'full-text search, inside the current space'],
|
['/', 'full-text search, inside the current space'],
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<span class="accent">~/{workspace.space?.slug ?? 'diary'}</span>
|
<span class="accent name">~/{workspace.space?.slug ?? 'diary'}</span>
|
||||||
<span class="faint count">
|
<span class="faint count">
|
||||||
{workspace.nodes.length} {workspace.nodes.length === 1 ? 'item' : 'items'}
|
{workspace.nodes.length} {workspace.nodes.length === 1 ? 'item' : 'items'}
|
||||||
</span>
|
</span>
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
onclick={() => pick(index)}
|
onclick={() => pick(index)}
|
||||||
>
|
>
|
||||||
<span class="caret">{index === workspace.cursor ? '>' : ' '}</span>
|
<span class="caret">{index === workspace.cursor ? '>' : ' '}</span>
|
||||||
|
{#if workspace.marked?.id === node.id}<span class="marked" title="marked — p drops it in a folder">m</span>{/if}
|
||||||
<span class="time">{aside(node)}</span>
|
<span class="time">{aside(node)}</span>
|
||||||
<span class="title">{node.kind === 'document' ? '' : '/'}{label(node)}</span>
|
<span class="title">{node.kind === 'document' ? '' : '/'}{label(node)}</span>
|
||||||
{#if node.shared}<span class="shared" title="shared">◉</span>{/if}
|
{#if node.shared}<span class="shared" title="shared">◉</span>{/if}
|
||||||
@@ -158,9 +159,13 @@
|
|||||||
.time { color: var(--fg-faint); flex: none; font-size: 12px; }
|
.time { color: var(--fg-faint); flex: none; font-size: 12px; }
|
||||||
.title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
|
.title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
|
||||||
.shared { color: var(--accent); flex: none; }
|
.shared { color: var(--accent); flex: none; }
|
||||||
|
.marked { color: var(--warn); flex: none; font-weight: 700; }
|
||||||
.empty { padding: 12px 10px; }
|
.empty { padding: 12px 10px; }
|
||||||
|
|
||||||
.count { flex: 1; text-align: right; overflow: hidden; white-space: nowrap; }
|
.name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
/* The count is short and fixed-width-ish; the space name is the part that
|
||||||
|
can give way when the sidebar is narrow. */
|
||||||
|
.count { flex: none; white-space: nowrap; }
|
||||||
.tools { display: flex; gap: 2px; flex: none; }
|
.tools { display: flex; gap: 2px; flex: none; }
|
||||||
.tools button { padding: 0 6px; line-height: 18px; }
|
.tools button { padding: 0 6px; line-height: 18px; }
|
||||||
.tools .board { color: var(--accent); }
|
.tools .board { color: var(--accent); }
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ class Workspace {
|
|||||||
listCursor = $state(0)
|
listCursor = $state(0)
|
||||||
cardCursor = $state(0)
|
cardCursor = $state(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The node picked up by `m`, waiting for the `p` that drops it into whatever
|
||||||
|
* folder the list is showing then. A move is two keystrokes apart in time
|
||||||
|
* because the destination is somewhere else in the tree — there is no way to
|
||||||
|
* name it and be somewhere else at once.
|
||||||
|
*/
|
||||||
|
marked = $state<NodeSummary | null>(null)
|
||||||
|
|
||||||
pane = $state<Pane>('list')
|
pane = $state<Pane>('list')
|
||||||
vimMode = $state('normal')
|
vimMode = $state('normal')
|
||||||
flash = $state<Flash>(null)
|
flash = $state<Flash>(null)
|
||||||
@@ -279,8 +287,9 @@ class Workspace {
|
|||||||
await this.goTo(parent.id, from.id)
|
await this.goTo(parent.id, from.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async refresh() {
|
/** `keep` follows a node that just arrived, instead of holding the cursor. */
|
||||||
const keepId = this.selected?.id
|
async refresh(keep?: number) {
|
||||||
|
const keepId = keep ?? this.selected?.id
|
||||||
this.nodes = this.query
|
this.nodes = this.query
|
||||||
? await api.listNodes({ q: this.query, space: this.spaceId ?? undefined })
|
? await api.listNodes({ q: this.query, space: this.spaceId ?? undefined })
|
||||||
: await api.listNodes({ parent: this.parentId ?? undefined })
|
: await api.listNodes({ parent: this.parentId ?? undefined })
|
||||||
@@ -473,6 +482,35 @@ class Workspace {
|
|||||||
this.say(`moved #${id}`)
|
this.say(`moved #${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** `m`: pick the node under the cursor up, or put it back down unmoved. */
|
||||||
|
mark() {
|
||||||
|
const node = this.selected
|
||||||
|
if (!node) return this.say('nothing selected', 'error')
|
||||||
|
if (this.marked?.id === node.id) {
|
||||||
|
this.marked = null
|
||||||
|
return this.say('unmarked')
|
||||||
|
}
|
||||||
|
this.marked = node
|
||||||
|
this.say(`marked ${node.name.trim() || node.slug} — p drops it in this folder`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `p`: drop the marked node into the folder the list is showing. */
|
||||||
|
async drop() {
|
||||||
|
const node = this.marked
|
||||||
|
const parent = this.parentId
|
||||||
|
if (!node) return this.say('nothing marked — press m on a row first', 'error')
|
||||||
|
if (parent === null) return this.say('no folder open', 'error')
|
||||||
|
if (node.parent_id === parent) {
|
||||||
|
this.marked = null
|
||||||
|
return this.say('already here')
|
||||||
|
}
|
||||||
|
|
||||||
|
await api.moveNode(node.id, parent)
|
||||||
|
this.marked = null
|
||||||
|
await this.refresh(node.id)
|
||||||
|
this.say(`moved ${node.name.trim() || node.slug} here`)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Boards. One per space, which is what makes "what am I working on" a
|
* Boards. One per space, which is what makes "what am I working on" a
|
||||||
* question with an answer: work and uni are asked separately, and the diary
|
* question with an answer: work and uni are asked separately, and the diary
|
||||||
|
|||||||
Reference in new issue
Block a user