@kernhq/module-quire 0.10.5 → 0.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
session,
|
|
11
11
|
} from '@kernhq/ui'
|
|
12
12
|
import { createQuery, useQueryClient } from '@tanstack/svelte-query'
|
|
13
|
+
import { untrack } from 'svelte'
|
|
13
14
|
import { getQuireApi } from '../api-instance.js'
|
|
14
15
|
import { t } from '../i18n.js'
|
|
15
16
|
import { buildPageTree, type PageTreeNode } from '../index.js'
|
|
@@ -76,18 +77,31 @@ const matches = $derived(
|
|
|
76
77
|
query ? nodes.filter((n) => (n.title || t('untitled')).toLowerCase().includes(query)) : [],
|
|
77
78
|
)
|
|
78
79
|
|
|
79
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* A page opened from a link may be nested; its ancestors have to be open for it to be visible.
|
|
82
|
+
*
|
|
83
|
+
* `expanded` is read through `untrack` because this effect also writes it. Tracked, the write makes
|
|
84
|
+
* the effect its own trigger: collapsing an ancestor of the open page removed it from the set, the
|
|
85
|
+
* effect re-ran and put it straight back, and the disclosure was inert — click it, press Enter on
|
|
86
|
+
* it, nothing moves. That is the "effect that reads a flag it also clears" trap already written
|
|
87
|
+
* down in shell's CLAUDE.md, and it was invisible until `navigation.params.page` started arriving:
|
|
88
|
+
* with `activePageId` permanently null the loop never ran at all.
|
|
89
|
+
*
|
|
90
|
+
* What genuinely selects this effect is which page is open and what the tree contains. Whether a
|
|
91
|
+
* disclosure is open is the *result*, and a result must not be an input.
|
|
92
|
+
*/
|
|
80
93
|
$effect(() => {
|
|
81
94
|
if (!activePageId || nodes.length === 0) return
|
|
82
95
|
const byId = new Map(nodes.map((n) => [n.id, n]))
|
|
83
|
-
const
|
|
96
|
+
const current = untrack(() => expanded)
|
|
97
|
+
const next = new Set(current)
|
|
84
98
|
let cursor = byId.get(activePageId)?.parentId ?? null
|
|
85
99
|
let guard = 0
|
|
86
100
|
while (cursor && guard++ < 100) {
|
|
87
101
|
next.add(cursor)
|
|
88
102
|
cursor = byId.get(cursor)?.parentId ?? null
|
|
89
103
|
}
|
|
90
|
-
if (next.size !==
|
|
104
|
+
if (next.size !== current.size) expanded = next
|
|
91
105
|
})
|
|
92
106
|
|
|
93
107
|
function toggle(id: string) {
|
package/src/client/mock.ts
CHANGED
|
@@ -33,6 +33,21 @@ const iso = (msAgo = 0) => new Date(now - msAgo).toISOString()
|
|
|
33
33
|
|
|
34
34
|
const uid = (n: number) => `01920000-0000-7000-8000-0000000${String(n).padStart(5, '0')}`
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* The people the app's own mock signs you in as.
|
|
38
|
+
*
|
|
39
|
+
* Written out rather than derived: this module cannot see the shell's mock, and a comment with
|
|
40
|
+
* nobody's id on it loses the delete control only its author is offered — so the margin would look
|
|
41
|
+
* complete and be missing the one action that belongs to you.
|
|
42
|
+
*
|
|
43
|
+
* Declared here, above every factory that reads them, rather than beside the comment seed that used
|
|
44
|
+
* to own them: the page factory now stamps an author too, and it is called while the module body is
|
|
45
|
+
* still running. A `const` further down the same scope is in its temporal dead zone at that point,
|
|
46
|
+
* so the whole mock throws on import and every Quire screen renders nothing.
|
|
47
|
+
*/
|
|
48
|
+
const ME = '01920000-0000-7000-8000-000000000001'
|
|
49
|
+
const COLLEAGUE = '01920000-0000-7000-8000-000000000002'
|
|
50
|
+
|
|
36
51
|
interface Row extends Page {
|
|
37
52
|
/** the mock keeps trashed rows in the same list, as the server does */
|
|
38
53
|
_order: string
|
|
@@ -106,8 +121,16 @@ export function createMockQuireApi() {
|
|
|
106
121
|
coverUrl: null,
|
|
107
122
|
publishedVersionId: null,
|
|
108
123
|
hasUnpublishedChanges: false,
|
|
109
|
-
|
|
110
|
-
|
|
124
|
+
/*
|
|
125
|
+
* A seeded page has an author, because the byline reads one.
|
|
126
|
+
*
|
|
127
|
+
* These were both null, so `PageView` took its "author unknown" fallback on every page in the
|
|
128
|
+
* demo — the one environment where the byline is ever looked at — and the named path it now
|
|
129
|
+
* has shipped without anything rendering it. `ME` is the demo's signed-in member, so it
|
|
130
|
+
* resolves through `core.workspaces.members.list` like a comment's author does.
|
|
131
|
+
*/
|
|
132
|
+
createdBy: ME as Page['createdBy'],
|
|
133
|
+
updatedBy: ME as Page['updatedBy'],
|
|
111
134
|
createdAt: iso(9e7),
|
|
112
135
|
updatedAt: iso(36e5),
|
|
113
136
|
archivedAt: null,
|
|
@@ -246,16 +269,6 @@ export function createMockQuireApi() {
|
|
|
246
269
|
pages.push(row)
|
|
247
270
|
}
|
|
248
271
|
|
|
249
|
-
/**
|
|
250
|
-
* The people the app's own mock signs you in as.
|
|
251
|
-
*
|
|
252
|
-
* Written out rather than derived: this module cannot see the shell's mock, and a comment with
|
|
253
|
-
* nobody's id on it loses the delete control only its author is offered — so the margin would
|
|
254
|
-
* look complete and be missing the one action that belongs to you.
|
|
255
|
-
*/
|
|
256
|
-
const ME = '01920000-0000-7000-8000-000000000001'
|
|
257
|
-
const COLLEAGUE = '01920000-0000-7000-8000-000000000002'
|
|
258
|
-
|
|
259
272
|
/**
|
|
260
273
|
* What the pages used to say, and what people have asked about them.
|
|
261
274
|
*
|
|
@@ -301,7 +301,18 @@ async function trash() {
|
|
|
301
301
|
</div>
|
|
302
302
|
|
|
303
303
|
<div class="byline">
|
|
304
|
-
|
|
304
|
+
<!--
|
|
305
|
+
No avatar for an author nobody can name.
|
|
306
|
+
|
|
307
|
+
`Avatar` with no `name` draws a "?" disc whose `title` is empty, so an unresolved author put
|
|
308
|
+
a meaningless glyph at the head of the one line whose job is to say who touched the page —
|
|
309
|
+
and a screen reader read it out as "question mark". `updatedBy` is null for every page the
|
|
310
|
+
demo seeds and for any row written before the column existed, so this is the common path,
|
|
311
|
+
not the edge. The sentence beside it already falls back to wording that claims no author.
|
|
312
|
+
-->
|
|
313
|
+
{#if editor}
|
|
314
|
+
<Avatar id={doc.updatedBy} name={editor.name} src={editor.avatarUrl ?? undefined} size={24} />
|
|
315
|
+
{/if}
|
|
305
316
|
<span>
|
|
306
317
|
{editor
|
|
307
318
|
? t('edited_ago_by', { when: relativeTime(doc.updatedAt), who: editor.name })
|