@abraca/nuxt 2.10.0 → 2.13.0
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/dist/module.d.mts +14 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -0
- package/dist/runtime/assets/editor.css +1 -1
- package/dist/runtime/components/AConnectionBadge.d.vue.ts +29 -0
- package/dist/runtime/components/AConnectionBadge.vue +79 -0
- package/dist/runtime/components/AConnectionBadge.vue.d.ts +29 -0
- package/dist/runtime/components/ADocPickerModal.d.vue.ts +31 -0
- package/dist/runtime/components/ADocPickerModal.vue +191 -0
- package/dist/runtime/components/ADocPickerModal.vue.d.ts +31 -0
- package/dist/runtime/components/ADocumentTree.vue +65 -0
- package/dist/runtime/components/AEditor.d.vue.ts +19 -12
- package/dist/runtime/components/AEditor.vue +243 -165
- package/dist/runtime/components/AEditor.vue.d.ts +19 -12
- package/dist/runtime/components/AEncryptionModePicker.d.vue.ts +33 -0
- package/dist/runtime/components/AEncryptionModePicker.vue +211 -0
- package/dist/runtime/components/AEncryptionModePicker.vue.d.ts +33 -0
- package/dist/runtime/components/AModalShell.d.vue.ts +48 -0
- package/dist/runtime/components/AModalShell.vue +105 -0
- package/dist/runtime/components/AModalShell.vue.d.ts +48 -0
- package/dist/runtime/components/ANodePanel.d.vue.ts +17 -7
- package/dist/runtime/components/ANodePanel.vue +550 -451
- package/dist/runtime/components/ANodePanel.vue.d.ts +17 -7
- package/dist/runtime/components/ANodePanelHeader.d.vue.ts +20 -10
- package/dist/runtime/components/ANodePanelHeader.vue +17 -3
- package/dist/runtime/components/ANodePanelHeader.vue.d.ts +20 -10
- package/dist/runtime/components/ANodeSettingsPanel.d.vue.ts +2 -0
- package/dist/runtime/components/ANodeSettingsPanel.vue +21 -1
- package/dist/runtime/components/ANodeSettingsPanel.vue.d.ts +2 -0
- package/dist/runtime/components/ASnapshotPreviewModal.d.vue.ts +33 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue +430 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue.d.ts +33 -0
- package/dist/runtime/components/ATagsEditor.d.vue.ts +19 -0
- package/dist/runtime/components/ATagsEditor.vue +60 -0
- package/dist/runtime/components/ATagsEditor.vue.d.ts +19 -0
- package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- package/dist/runtime/components/chat/AChatInput.d.vue.ts +11 -6
- package/dist/runtime/components/chat/AChatInput.vue +33 -2
- package/dist/runtime/components/chat/AChatInput.vue.d.ts +11 -6
- package/dist/runtime/components/chat/AChatList.d.vue.ts +12 -0
- package/dist/runtime/components/chat/AChatList.vue +76 -32
- package/dist/runtime/components/chat/AChatList.vue.d.ts +12 -0
- package/dist/runtime/components/chat/AChatMessages.d.vue.ts +4 -0
- package/dist/runtime/components/chat/AChatMessages.vue +57 -4
- package/dist/runtime/components/chat/AChatMessages.vue.d.ts +4 -0
- package/dist/runtime/components/chat/AChatPanel.d.vue.ts +6 -2
- package/dist/runtime/components/chat/AChatPanel.vue +17 -1
- package/dist/runtime/components/chat/AChatPanel.vue.d.ts +6 -2
- package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -1
- package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
- package/dist/runtime/components/editor/ALocationPickerPopover.vue +28 -7
- package/dist/runtime/components/registry/APluginDetail.d.vue.ts +2 -2
- package/dist/runtime/components/registry/APluginDetail.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/AChartRenderer.client.d.vue.ts +17 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue +622 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue.d.ts +17 -0
- package/dist/runtime/components/renderers/AGraphRenderer.vue +64 -15
- package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.vue.d.ts +2 -2
- package/dist/runtime/components/settings/ASettingsAppearancePanel.d.vue.ts +3 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue +67 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue.d.ts +3 -0
- package/dist/runtime/components/settings/ASettingsGroup.d.vue.ts +24 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue +31 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue.d.ts +24 -0
- package/dist/runtime/components/settings/ASettingsModal.vue +84 -53
- package/dist/runtime/components/settings/ASettingsPlaceholder.d.vue.ts +20 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue +32 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue.d.ts +20 -0
- package/dist/runtime/components/settings/ASettingsRow.d.vue.ts +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue.d.ts +34 -0
- package/dist/runtime/components/settings/sections.d.ts +37 -0
- package/dist/runtime/components/settings/sections.js +45 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +6 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +75 -3
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +6 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.d.vue.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue +253 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue.d.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelSettings.d.vue.ts +2 -0
- package/dist/runtime/components/shell/ADocPanelSettings.vue +15 -4
- package/dist/runtime/components/shell/ADocPanelSettings.vue.d.ts +2 -0
- package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
- package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
- package/dist/runtime/composables/useChat.d.ts +22 -1
- package/dist/runtime/composables/useChat.js +79 -8
- package/dist/runtime/composables/useDocBreadcrumb.d.ts +17 -2
- package/dist/runtime/composables/useDocBreadcrumb.js +17 -3
- package/dist/runtime/composables/useDocSnapshots.d.ts +2 -1
- package/dist/runtime/composables/useDocSnapshots.js +5 -0
- package/dist/runtime/composables/useEditor.d.ts +1 -1
- package/dist/runtime/composables/useEditor.js +120 -0
- package/dist/runtime/composables/useEditorToolbar.d.ts +12 -4
- package/dist/runtime/composables/useEditorToolbar.js +78 -56
- package/dist/runtime/composables/useNodeContextMenu.d.ts +14 -0
- package/dist/runtime/composables/useNodeContextMenu.js +59 -1
- package/dist/runtime/composables/useSettingsModal.d.ts +1 -1
- package/dist/runtime/composables/useSwipeGesture.d.ts +48 -0
- package/dist/runtime/composables/useSwipeGesture.js +140 -0
- package/dist/runtime/extensions/document-header.js +16 -6
- package/dist/runtime/extensions/document-meta.js +344 -19
- package/dist/runtime/extensions/meta-field.js +42 -0
- package/dist/runtime/extensions/views/DocumentMetaView.vue +33 -7
- package/dist/runtime/extensions/views/FieldView.vue +51 -19
- package/dist/runtime/extensions/views/MetaFieldView.vue +30 -4
- package/dist/runtime/locale.d.ts +8 -0
- package/dist/runtime/locale.js +9 -1
- package/dist/runtime/middleware/abracadabra-auth.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.js +12 -2
- package/dist/runtime/plugin-abracadabra.server.d.ts +1 -1
- package/dist/runtime/plugin-shared-globals.client.d.ts +1 -1
- package/dist/runtime/utils/chatContent.d.ts +20 -2
- package/dist/runtime/utils/chatContent.js +20 -1
- package/dist/runtime/utils/docTypes.js +43 -0
- package/dist/runtime/utils/titleSync.d.ts +130 -0
- package/dist/runtime/utils/titleSync.js +53 -0
- package/package.json +11 -4
package/dist/module.d.mts
CHANGED
|
@@ -30,6 +30,7 @@ declare module '@nuxt/schema' {
|
|
|
30
30
|
abracadabra: {
|
|
31
31
|
url: string;
|
|
32
32
|
entryDocId: string;
|
|
33
|
+
pinServer: boolean;
|
|
33
34
|
persistAuth: boolean;
|
|
34
35
|
authStorageKey: string;
|
|
35
36
|
disabledBuiltins: string[];
|
|
@@ -115,6 +116,19 @@ interface ModuleOptions {
|
|
|
115
116
|
* entryDocId > saved server entryDocId > first Space (kind="space" top-level doc)
|
|
116
117
|
*/
|
|
117
118
|
entryDocId?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Pin the app to the configured `url` and ignore any persisted active
|
|
121
|
+
* server (`abracadabra_current_server`) or `?server=` deep-link override.
|
|
122
|
+
* Default: false — the switcher's last-used / deep-linked server wins, which
|
|
123
|
+
* is what multi-server apps (arcana, aperio) want.
|
|
124
|
+
*
|
|
125
|
+
* Set `true` for single-server consumers (marketing, landing) so a visitor
|
|
126
|
+
* who once connected the origin to another server can't get silently pinned
|
|
127
|
+
* to it on later loads while `entryDocId` still points at the configured
|
|
128
|
+
* server's doc — the failure mode is a phantom/empty entry doc with no sync
|
|
129
|
+
* or awareness. When `true`, boot always uses `url`.
|
|
130
|
+
*/
|
|
131
|
+
pinServer?: boolean;
|
|
118
132
|
/**
|
|
119
133
|
* Whether to persist the JWT token across page reloads via localStorage.
|
|
120
134
|
* Default: true.
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -19,6 +19,7 @@ const module$1 = defineNuxtModule({
|
|
|
19
19
|
},
|
|
20
20
|
defaults: {
|
|
21
21
|
url: process.env.ABRACADABRA_URL ?? "https://abra.cou.sh",
|
|
22
|
+
pinServer: false,
|
|
22
23
|
persistAuth: true,
|
|
23
24
|
authStorageKey: "abracadabra:auth",
|
|
24
25
|
disabledBuiltins: [],
|
|
@@ -85,6 +86,7 @@ const module$1 = defineNuxtModule({
|
|
|
85
86
|
},
|
|
86
87
|
url: options.url,
|
|
87
88
|
entryDocId: options.entryDocId ?? "",
|
|
89
|
+
pinServer: options.pinServer ?? false,
|
|
88
90
|
persistAuth: options.persistAuth,
|
|
89
91
|
authStorageKey: options.authStorageKey,
|
|
90
92
|
disabledBuiltins: options.disabledBuiltins,
|
|
@@ -290,6 +292,13 @@ const module$1 = defineNuxtModule({
|
|
|
290
292
|
prebundleDeps.push("mapbox-gl");
|
|
291
293
|
} catch {
|
|
292
294
|
}
|
|
295
|
+
for (const pkg of ["@unovis/vue", "@unovis/ts"]) {
|
|
296
|
+
try {
|
|
297
|
+
createRequire(`${nuxt.options.rootDir}/`).resolve(pkg);
|
|
298
|
+
prebundleDeps.push(pkg);
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
}
|
|
293
302
|
if (options.features?.code !== false) {
|
|
294
303
|
const cmPeers = [
|
|
295
304
|
"@codemirror/view",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
html.dark .tiptap .shiki,html.dark .tiptap .shiki span{background-color:var(--ui-bg-muted)!important;color:var(--shiki-dark)!important}.collaboration-carets__caret{border-left:1px solid #0d0d0d;border-right:1px solid #0d0d0d;margin-left:-1px;margin-right:-1px;opacity:0;pointer-events:none;position:relative;transition:opacity .3s ease;word-break:normal}.collaboration-carets__caret.is-hidden{display:none}.collaboration-carets__caret.is-active{opacity:1}.collaboration-carets__label{border-radius:3px 3px 3px 0;color:#0d0d0d;font-size:12px;font-style:normal;font-weight:600;left:-1px;line-height:normal;padding:.1rem .3rem;position:absolute;top:-1.4em;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.ProseMirror-yjs-selection,.collaboration-carets__selection{background-color:var(--collaboration-selection-color)!important;pointer-events:none}.search-highlight{background-color:color-mix(in srgb,var(--color-primary-400) 35%,transparent);border-radius:2px;padding:0 1px}.doc-passage-highlight{background-color:color-mix(in srgb,var(--color-success-400) 35%,transparent);border-radius:2px;padding:0 1px}
|
|
1
|
+
html.dark .tiptap .shiki,html.dark .tiptap .shiki span{background-color:var(--ui-bg-muted)!important;color:var(--shiki-dark)!important}.collaboration-carets__caret{border-left:1px solid #0d0d0d;border-right:1px solid #0d0d0d;margin-left:-1px;margin-right:-1px;opacity:0;pointer-events:none;position:relative;transition:opacity .3s ease;word-break:normal}.collaboration-carets__caret.is-hidden{display:none}.collaboration-carets__caret.is-active{opacity:1}.collaboration-carets__label{border-radius:3px 3px 3px 0;color:#0d0d0d;font-size:12px;font-style:normal;font-weight:600;left:-1px;line-height:normal;padding:.1rem .3rem;position:absolute;top:-1.4em;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.ProseMirror-yjs-selection,.collaboration-carets__selection{background-color:var(--collaboration-selection-color)!important;pointer-events:none}.search-highlight{background-color:color-mix(in srgb,var(--color-primary-400) 35%,transparent);border-radius:2px;padding:0 1px}.doc-passage-highlight{background-color:color-mix(in srgb,var(--color-success-400) 35%,transparent);border-radius:2px;padding:0 1px}.tiptap{min-height:100%;padding-bottom:8rem}.tiptap.file-drop-active{border-radius:4px;outline:2px dashed var(--ui-primary);outline-offset:4px}.tiptap .document-header{font-size:2.5rem;font-weight:800;letter-spacing:-.025em;line-height:1.2;margin-bottom:1rem}.tiptap [data-type=document-meta]{align-items:center;display:flex;flex-wrap:wrap;font-size:.875rem;gap:.375rem;line-height:1.75rem;margin-bottom:1.5rem;min-height:1.75rem}.tiptap [data-type=document-meta][data-cursor-in-meta=true][data-empty=true]:after{color:var(--ui-text-dimmed);content:"Type '/' to add a property…";pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.prose-variant .tiptap [data-type=document-meta]{display:none}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** The document's child provider (AbracadabraProvider or a local wrapper). */
|
|
3
|
+
provider?: any;
|
|
4
|
+
/**
|
|
5
|
+
* Override the four status strings. `label` is the short status word
|
|
6
|
+
* (also the aria-label); `tooltip` is the longer hover explanation.
|
|
7
|
+
*/
|
|
8
|
+
labels?: Partial<{
|
|
9
|
+
authFailedCached: {
|
|
10
|
+
label: string;
|
|
11
|
+
tooltip: string;
|
|
12
|
+
};
|
|
13
|
+
authFailedNoCache: {
|
|
14
|
+
label: string;
|
|
15
|
+
tooltip: string;
|
|
16
|
+
};
|
|
17
|
+
offlineCached: {
|
|
18
|
+
label: string;
|
|
19
|
+
tooltip: string;
|
|
20
|
+
};
|
|
21
|
+
offlineNoCache: {
|
|
22
|
+
label: string;
|
|
23
|
+
tooltip: string;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
provider: { type: null, required: false },
|
|
5
|
+
labels: { type: Object, required: false }
|
|
6
|
+
});
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
authFailedCached: {
|
|
9
|
+
label: "Cached copy",
|
|
10
|
+
tooltip: "Server rejected the connection \u2014 showing the last cached copy."
|
|
11
|
+
},
|
|
12
|
+
authFailedNoCache: {
|
|
13
|
+
label: "No access",
|
|
14
|
+
tooltip: "Server rejected the connection and no cached copy is available."
|
|
15
|
+
},
|
|
16
|
+
offlineCached: {
|
|
17
|
+
label: "Offline",
|
|
18
|
+
tooltip: "Server is unreachable \u2014 showing the last cached copy. Edits will sync when you reconnect."
|
|
19
|
+
},
|
|
20
|
+
offlineNoCache: {
|
|
21
|
+
label: "Not yet synced",
|
|
22
|
+
tooltip: "Server is unreachable and this document hasn't been synced to this device yet. Reconnect to load it."
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const isRemoteProvider = computed(
|
|
26
|
+
() => !!props.provider && typeof props.provider.connectionStatus === "string"
|
|
27
|
+
);
|
|
28
|
+
const connStatus = ref("connecting");
|
|
29
|
+
const authFailed = ref(false);
|
|
30
|
+
watch(
|
|
31
|
+
() => props.provider,
|
|
32
|
+
(p, _old, onCleanup) => {
|
|
33
|
+
if (!p || typeof p.connectionStatus !== "string") return;
|
|
34
|
+
connStatus.value = p.connectionStatus ?? "disconnected";
|
|
35
|
+
authFailed.value = false;
|
|
36
|
+
const onStatus = (e) => {
|
|
37
|
+
connStatus.value = e?.status ?? "disconnected";
|
|
38
|
+
if (e?.status === "connected") authFailed.value = false;
|
|
39
|
+
};
|
|
40
|
+
const onAuthFail = () => {
|
|
41
|
+
authFailed.value = true;
|
|
42
|
+
};
|
|
43
|
+
p.on?.("status", onStatus);
|
|
44
|
+
p.on?.("authenticationFailed", onAuthFail);
|
|
45
|
+
onCleanup(() => {
|
|
46
|
+
p.off?.("status", onStatus);
|
|
47
|
+
p.off?.("authenticationFailed", onAuthFail);
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
{ immediate: true }
|
|
51
|
+
);
|
|
52
|
+
const isOffline = computed(
|
|
53
|
+
() => isRemoteProvider.value && (authFailed.value || connStatus.value !== "connected")
|
|
54
|
+
);
|
|
55
|
+
const badge = computed(() => {
|
|
56
|
+
if (!isRemoteProvider.value || !isOffline.value) return null;
|
|
57
|
+
const hasCache = !!props.provider?.hasCachedContent;
|
|
58
|
+
const strings = { ...DEFAULTS, ...props.labels };
|
|
59
|
+
if (authFailed.value) {
|
|
60
|
+
return hasCache ? strings.authFailedCached : strings.authFailedNoCache;
|
|
61
|
+
}
|
|
62
|
+
return hasCache ? strings.offlineCached : strings.offlineNoCache;
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<UTooltip
|
|
68
|
+
v-if="badge"
|
|
69
|
+
:text="badge.tooltip"
|
|
70
|
+
:content="{ side: 'bottom' }"
|
|
71
|
+
>
|
|
72
|
+
<span
|
|
73
|
+
class="size-2 rounded-full shrink-0 ring-1 ring-inset ring-black/10"
|
|
74
|
+
:class="authFailed ? 'bg-(--ui-color-error-500)' : 'bg-(--ui-color-warning-500)'"
|
|
75
|
+
role="status"
|
|
76
|
+
:aria-label="badge.label"
|
|
77
|
+
/>
|
|
78
|
+
</UTooltip>
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** The document's child provider (AbracadabraProvider or a local wrapper). */
|
|
3
|
+
provider?: any;
|
|
4
|
+
/**
|
|
5
|
+
* Override the four status strings. `label` is the short status word
|
|
6
|
+
* (also the aria-label); `tooltip` is the longer hover explanation.
|
|
7
|
+
*/
|
|
8
|
+
labels?: Partial<{
|
|
9
|
+
authFailedCached: {
|
|
10
|
+
label: string;
|
|
11
|
+
tooltip: string;
|
|
12
|
+
};
|
|
13
|
+
authFailedNoCache: {
|
|
14
|
+
label: string;
|
|
15
|
+
tooltip: string;
|
|
16
|
+
};
|
|
17
|
+
offlineCached: {
|
|
18
|
+
label: string;
|
|
19
|
+
tooltip: string;
|
|
20
|
+
};
|
|
21
|
+
offlineNoCache: {
|
|
22
|
+
label: string;
|
|
23
|
+
tooltip: string;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open: boolean;
|
|
3
|
+
/** Modal heading. */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Confirm button label. */
|
|
6
|
+
confirmLabel?: string;
|
|
7
|
+
/** Doc to exclude as a target along with its whole subtree (e.g. the doc being moved). */
|
|
8
|
+
excludeId?: string | null;
|
|
9
|
+
/** Extra ids to exclude as targets. */
|
|
10
|
+
excludeIds?: string[];
|
|
11
|
+
/** Offer a "Top level" (root) option. */
|
|
12
|
+
allowRoot?: boolean;
|
|
13
|
+
/** Label for the root option. */
|
|
14
|
+
rootLabel?: string;
|
|
15
|
+
};
|
|
16
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
17
|
+
select: (targetId: string | null) => any;
|
|
18
|
+
"update:open": (v: boolean) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
20
|
+
onSelect?: ((targetId: string | null) => any) | undefined;
|
|
21
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
22
|
+
}>, {
|
|
23
|
+
title: string;
|
|
24
|
+
confirmLabel: string;
|
|
25
|
+
excludeId: string | null;
|
|
26
|
+
excludeIds: string[];
|
|
27
|
+
allowRoot: boolean;
|
|
28
|
+
rootLabel: string;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { useDocTree } from "../composables/useDocTree";
|
|
4
|
+
import { resolveDocType } from "../utils/docTypes";
|
|
5
|
+
import AModalShell from "./AModalShell.vue";
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
open: { type: Boolean, required: true },
|
|
8
|
+
title: { type: String, required: false, default: "Move to\u2026" },
|
|
9
|
+
confirmLabel: { type: String, required: false, default: "Move here" },
|
|
10
|
+
excludeId: { type: [String, null], required: false, default: null },
|
|
11
|
+
excludeIds: { type: Array, required: false, default: () => [] },
|
|
12
|
+
allowRoot: { type: Boolean, required: false, default: true },
|
|
13
|
+
rootLabel: { type: String, required: false, default: "Top level" }
|
|
14
|
+
});
|
|
15
|
+
const emit = defineEmits(["update:open", "select"]);
|
|
16
|
+
const { entries } = useDocTree();
|
|
17
|
+
const open = computed({
|
|
18
|
+
get: () => props.open,
|
|
19
|
+
set: (v) => emit("update:open", v)
|
|
20
|
+
});
|
|
21
|
+
const idSet = computed(() => new Set(entries.value.map((e) => e.id)));
|
|
22
|
+
const childrenOf = computed(() => {
|
|
23
|
+
const map = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const e of entries.value) {
|
|
25
|
+
if (e.trashed) continue;
|
|
26
|
+
const pid = e.parentId && idSet.value.has(e.parentId) ? e.parentId : null;
|
|
27
|
+
const arr = map.get(pid) ?? [];
|
|
28
|
+
arr.push(e);
|
|
29
|
+
map.set(pid, arr);
|
|
30
|
+
}
|
|
31
|
+
for (const arr of map.values()) arr.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
32
|
+
return map;
|
|
33
|
+
});
|
|
34
|
+
const excluded = computed(() => {
|
|
35
|
+
const set = new Set(props.excludeIds);
|
|
36
|
+
if (props.excludeId) {
|
|
37
|
+
const queue = [props.excludeId];
|
|
38
|
+
while (queue.length) {
|
|
39
|
+
const id = queue.shift();
|
|
40
|
+
set.add(id);
|
|
41
|
+
for (const child of childrenOf.value.get(id) ?? []) queue.push(child.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return set;
|
|
45
|
+
});
|
|
46
|
+
const expanded = ref(/* @__PURE__ */ new Set());
|
|
47
|
+
const selectedId = ref(null);
|
|
48
|
+
const search = ref("");
|
|
49
|
+
watch(() => props.open, (isOpen) => {
|
|
50
|
+
if (isOpen) {
|
|
51
|
+
selectedId.value = null;
|
|
52
|
+
search.value = "";
|
|
53
|
+
expanded.value = /* @__PURE__ */ new Set();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
function iconFor(entry) {
|
|
57
|
+
return entry?.meta?.icon ? entry.meta.icon.startsWith("i-") ? entry.meta.icon : `i-lucide-${entry.meta.icon}` : resolveDocType(entry?.type ?? "doc").icon;
|
|
58
|
+
}
|
|
59
|
+
const rows = computed(() => {
|
|
60
|
+
const q = search.value.trim().toLowerCase();
|
|
61
|
+
if (q) {
|
|
62
|
+
return entries.value.filter((e) => !e.trashed && !excluded.value.has(e.id) && (e.label || "").toLowerCase().includes(q)).sort((a, b) => (a.label || "").localeCompare(b.label || "")).slice(0, 100).map((e) => ({ id: e.id, label: e.label || "Untitled", icon: iconFor(e), depth: 0, hasChildren: false, expanded: false }));
|
|
63
|
+
}
|
|
64
|
+
const out = [];
|
|
65
|
+
const walk = (pid, depth) => {
|
|
66
|
+
for (const e of childrenOf.value.get(pid) ?? []) {
|
|
67
|
+
if (excluded.value.has(e.id)) continue;
|
|
68
|
+
const kids = (childrenOf.value.get(e.id) ?? []).filter((c) => !excluded.value.has(c.id));
|
|
69
|
+
const isExp = expanded.value.has(e.id);
|
|
70
|
+
out.push({ id: e.id, label: e.label || "Untitled", icon: iconFor(e), depth, hasChildren: kids.length > 0, expanded: isExp });
|
|
71
|
+
if (isExp) walk(e.id, depth + 1);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
walk(null, 0);
|
|
75
|
+
return out;
|
|
76
|
+
});
|
|
77
|
+
function toggle(id) {
|
|
78
|
+
const next = new Set(expanded.value);
|
|
79
|
+
if (next.has(id)) next.delete(id);
|
|
80
|
+
else next.add(id);
|
|
81
|
+
expanded.value = next;
|
|
82
|
+
}
|
|
83
|
+
function confirm() {
|
|
84
|
+
emit("select", selectedId.value);
|
|
85
|
+
emit("update:open", false);
|
|
86
|
+
}
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<AModalShell
|
|
91
|
+
:open="open"
|
|
92
|
+
:title="title"
|
|
93
|
+
max-width="sm:max-w-lg"
|
|
94
|
+
@update:open="open = $event"
|
|
95
|
+
>
|
|
96
|
+
<div class="flex flex-col gap-3">
|
|
97
|
+
<UInput
|
|
98
|
+
v-model="search"
|
|
99
|
+
icon="i-lucide-search"
|
|
100
|
+
placeholder="Search documents…"
|
|
101
|
+
size="sm"
|
|
102
|
+
class="w-full"
|
|
103
|
+
autofocus
|
|
104
|
+
/>
|
|
105
|
+
|
|
106
|
+
<div class="max-h-[50vh] overflow-y-auto rounded-md border border-(--ui-border) divide-y divide-(--ui-border)/60">
|
|
107
|
+
<!-- Root / top-level option -->
|
|
108
|
+
<button
|
|
109
|
+
v-if="allowRoot && !search"
|
|
110
|
+
type="button"
|
|
111
|
+
class="w-full flex items-center gap-2 px-3 py-2 text-left text-sm hover:bg-(--ui-bg-elevated) transition-colors"
|
|
112
|
+
:class="selectedId === null ? 'bg-(--ui-primary)/10 text-(--ui-primary)' : ''"
|
|
113
|
+
@click="selectedId = null"
|
|
114
|
+
>
|
|
115
|
+
<UIcon
|
|
116
|
+
name="i-lucide-home"
|
|
117
|
+
class="size-4 shrink-0 text-(--ui-text-muted)"
|
|
118
|
+
/>
|
|
119
|
+
<span class="flex-1 truncate">{{ rootLabel }}</span>
|
|
120
|
+
<UIcon
|
|
121
|
+
v-if="selectedId === null"
|
|
122
|
+
name="i-lucide-check"
|
|
123
|
+
class="size-4 shrink-0"
|
|
124
|
+
/>
|
|
125
|
+
</button>
|
|
126
|
+
|
|
127
|
+
<div
|
|
128
|
+
v-for="row in rows"
|
|
129
|
+
:key="row.id"
|
|
130
|
+
class="flex items-center hover:bg-(--ui-bg-elevated) transition-colors"
|
|
131
|
+
:class="selectedId === row.id ? 'bg-(--ui-primary)/10' : ''"
|
|
132
|
+
:style="{ paddingLeft: `${row.depth * 16}px` }"
|
|
133
|
+
>
|
|
134
|
+
<button
|
|
135
|
+
type="button"
|
|
136
|
+
class="size-6 shrink-0 flex items-center justify-center text-(--ui-text-dimmed) hover:text-(--ui-text)"
|
|
137
|
+
:class="row.hasChildren ? '' : 'invisible'"
|
|
138
|
+
@click="toggle(row.id)"
|
|
139
|
+
>
|
|
140
|
+
<UIcon
|
|
141
|
+
:name="row.expanded ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
|
|
142
|
+
class="size-4"
|
|
143
|
+
/>
|
|
144
|
+
</button>
|
|
145
|
+
<button
|
|
146
|
+
type="button"
|
|
147
|
+
class="flex-1 min-w-0 flex items-center gap-2 px-1 py-2 text-left text-sm"
|
|
148
|
+
:class="selectedId === row.id ? 'text-(--ui-primary)' : ''"
|
|
149
|
+
@click="selectedId = row.id"
|
|
150
|
+
>
|
|
151
|
+
<UIcon
|
|
152
|
+
:name="row.icon"
|
|
153
|
+
class="size-4 shrink-0 text-(--ui-text-muted)"
|
|
154
|
+
/>
|
|
155
|
+
<span class="flex-1 truncate">{{ row.label }}</span>
|
|
156
|
+
<UIcon
|
|
157
|
+
v-if="selectedId === row.id"
|
|
158
|
+
name="i-lucide-check"
|
|
159
|
+
class="size-4 shrink-0 mr-2"
|
|
160
|
+
/>
|
|
161
|
+
</button>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<p
|
|
165
|
+
v-if="rows.length === 0"
|
|
166
|
+
class="px-3 py-6 text-center text-sm text-(--ui-text-dimmed)"
|
|
167
|
+
>
|
|
168
|
+
{{ search ? "No matching documents." : "No documents." }}
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<template #footer>
|
|
174
|
+
<div class="flex items-center justify-end gap-2 w-full">
|
|
175
|
+
<UButton
|
|
176
|
+
label="Cancel"
|
|
177
|
+
color="neutral"
|
|
178
|
+
variant="ghost"
|
|
179
|
+
@click="emit('update:open', false)"
|
|
180
|
+
/>
|
|
181
|
+
<UButton
|
|
182
|
+
:label="confirmLabel"
|
|
183
|
+
color="primary"
|
|
184
|
+
icon="i-lucide-corner-down-right"
|
|
185
|
+
:disabled="selectedId === null && !allowRoot"
|
|
186
|
+
@click="confirm"
|
|
187
|
+
/>
|
|
188
|
+
</div>
|
|
189
|
+
</template>
|
|
190
|
+
</AModalShell>
|
|
191
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open: boolean;
|
|
3
|
+
/** Modal heading. */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Confirm button label. */
|
|
6
|
+
confirmLabel?: string;
|
|
7
|
+
/** Doc to exclude as a target along with its whole subtree (e.g. the doc being moved). */
|
|
8
|
+
excludeId?: string | null;
|
|
9
|
+
/** Extra ids to exclude as targets. */
|
|
10
|
+
excludeIds?: string[];
|
|
11
|
+
/** Offer a "Top level" (root) option. */
|
|
12
|
+
allowRoot?: boolean;
|
|
13
|
+
/** Label for the root option. */
|
|
14
|
+
rootLabel?: string;
|
|
15
|
+
};
|
|
16
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
17
|
+
select: (targetId: string | null) => any;
|
|
18
|
+
"update:open": (v: boolean) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
20
|
+
onSelect?: ((targetId: string | null) => any) | undefined;
|
|
21
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
22
|
+
}>, {
|
|
23
|
+
title: string;
|
|
24
|
+
confirmLabel: string;
|
|
25
|
+
excludeId: string | null;
|
|
26
|
+
excludeIds: string[];
|
|
27
|
+
allowRoot: boolean;
|
|
28
|
+
rootLabel: string;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -298,6 +298,45 @@ function deleteDoc(docId) {
|
|
|
298
298
|
if (!docId || !isReady.value) return;
|
|
299
299
|
moveToTrash(docId, userName.value);
|
|
300
300
|
}
|
|
301
|
+
const moveTargetId = ref(null);
|
|
302
|
+
const movePickerOpen = ref(false);
|
|
303
|
+
function openMovePicker(docId) {
|
|
304
|
+
moveTargetId.value = docId;
|
|
305
|
+
movePickerOpen.value = true;
|
|
306
|
+
}
|
|
307
|
+
function performMove(newParentId) {
|
|
308
|
+
const id = moveTargetId.value;
|
|
309
|
+
if (!id || !isReady.value) return;
|
|
310
|
+
const entry = treeMap.data[id];
|
|
311
|
+
if (!entry) return;
|
|
312
|
+
if ((entry.parentId ?? null) === newParentId) return;
|
|
313
|
+
treeMap.set(id, { ...entry, parentId: newParentId, order: Date.now() });
|
|
314
|
+
if (newParentId) {
|
|
315
|
+
client.value?.createChild(newParentId, { child_id: id, kind: "page" }).catch(() => {
|
|
316
|
+
});
|
|
317
|
+
expandedIds.value.add(newParentId);
|
|
318
|
+
expandedIds.value = new Set(expandedIds.value);
|
|
319
|
+
}
|
|
320
|
+
emit("navigate", id);
|
|
321
|
+
}
|
|
322
|
+
const tagsTargetId = ref(null);
|
|
323
|
+
const tagsEditorOpen = ref(false);
|
|
324
|
+
function openTagsEditor(docId) {
|
|
325
|
+
tagsTargetId.value = docId;
|
|
326
|
+
tagsEditorOpen.value = true;
|
|
327
|
+
}
|
|
328
|
+
const tagsTargetTags = computed(() => {
|
|
329
|
+
const id = tagsTargetId.value;
|
|
330
|
+
if (!id) return [];
|
|
331
|
+
return treeMap.data[id]?.meta?.tags ?? [];
|
|
332
|
+
});
|
|
333
|
+
function saveTags(tags) {
|
|
334
|
+
const id = tagsTargetId.value;
|
|
335
|
+
if (!id || !isReady.value) return;
|
|
336
|
+
const entry = treeMap.data[id];
|
|
337
|
+
if (!entry) return;
|
|
338
|
+
treeMap.set(id, { ...entry, meta: { ...entry.meta ?? {}, tags } });
|
|
339
|
+
}
|
|
301
340
|
const renameId = ref(null);
|
|
302
341
|
const renameValue = ref("");
|
|
303
342
|
const renameInputRef = ref(null);
|
|
@@ -770,6 +809,16 @@ function treeNodeMenuItems(item) {
|
|
|
770
809
|
label: "Add child page",
|
|
771
810
|
icon: "i-lucide-file-plus",
|
|
772
811
|
onSelect: () => createDirectly(item.id)
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
label: "Move to\u2026",
|
|
815
|
+
icon: "i-lucide-corner-down-right",
|
|
816
|
+
onSelect: () => openMovePicker(item.id)
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
label: "Edit tags\u2026",
|
|
820
|
+
icon: "i-lucide-tags",
|
|
821
|
+
onSelect: () => openTagsEditor(item.id)
|
|
773
822
|
}
|
|
774
823
|
],
|
|
775
824
|
[
|
|
@@ -1517,6 +1566,22 @@ defineExpose({
|
|
|
1517
1566
|
@close="closeOverlay"
|
|
1518
1567
|
/>
|
|
1519
1568
|
</div>
|
|
1569
|
+
|
|
1570
|
+
<!-- Move-to reparent picker -->
|
|
1571
|
+
<ADocPickerModal
|
|
1572
|
+
v-model:open="movePickerOpen"
|
|
1573
|
+
:exclude-id="moveTargetId"
|
|
1574
|
+
title="Move to…"
|
|
1575
|
+
confirm-label="Move here"
|
|
1576
|
+
@select="performMove"
|
|
1577
|
+
/>
|
|
1578
|
+
|
|
1579
|
+
<!-- Edit-tags editor -->
|
|
1580
|
+
<ATagsEditor
|
|
1581
|
+
v-model:open="tagsEditorOpen"
|
|
1582
|
+
:tags="tagsTargetTags"
|
|
1583
|
+
@save="saveTags"
|
|
1584
|
+
/>
|
|
1520
1585
|
</template>
|
|
1521
1586
|
|
|
1522
1587
|
<style scoped>
|
|
@@ -35,12 +35,18 @@ type __VLS_Props = {
|
|
|
35
35
|
* Useful for inspecting CRDT state during development. Default: false.
|
|
36
36
|
*/
|
|
37
37
|
showSourceToggle?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Show the in-canvas ancestor breadcrumb above the document (matching
|
|
40
|
+
* cou-sh's DocRenderer). Only renders when the doc actually has ancestors,
|
|
41
|
+
* so root/space docs show nothing. Set false for embeds/previews.
|
|
42
|
+
*/
|
|
43
|
+
showBreadcrumb?: boolean;
|
|
38
44
|
};
|
|
39
45
|
type __VLS_ModelProps = {
|
|
40
46
|
modelValue?: any;
|
|
41
47
|
};
|
|
42
48
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
43
|
-
declare var
|
|
49
|
+
declare var __VLS_58: {
|
|
44
50
|
editor: any;
|
|
45
51
|
connectedUsers: {
|
|
46
52
|
name: string;
|
|
@@ -49,40 +55,40 @@ declare var __VLS_42: {
|
|
|
49
55
|
docId?: string | undefined;
|
|
50
56
|
}[];
|
|
51
57
|
ready: boolean;
|
|
52
|
-
},
|
|
58
|
+
}, __VLS_67: {
|
|
53
59
|
editor: any;
|
|
54
|
-
},
|
|
60
|
+
}, __VLS_75: {
|
|
55
61
|
editor: any;
|
|
56
|
-
},
|
|
62
|
+
}, __VLS_83: {
|
|
57
63
|
editor: any;
|
|
58
|
-
},
|
|
64
|
+
}, __VLS_86: {
|
|
59
65
|
editor: any;
|
|
60
66
|
};
|
|
61
67
|
type __VLS_Slots = {} & {
|
|
62
|
-
default?: (props: typeof
|
|
68
|
+
default?: (props: typeof __VLS_58) => any;
|
|
63
69
|
} & {
|
|
64
|
-
link?: (props: typeof
|
|
70
|
+
link?: (props: typeof __VLS_67) => any;
|
|
65
71
|
} & {
|
|
66
|
-
'doc-link'?: (props: typeof
|
|
72
|
+
'doc-link'?: (props: typeof __VLS_75) => any;
|
|
67
73
|
} & {
|
|
68
|
-
'create-child-doc'?: (props: typeof
|
|
74
|
+
'create-child-doc'?: (props: typeof __VLS_83) => any;
|
|
69
75
|
} & {
|
|
70
|
-
'send-to-chat'?: (props: typeof
|
|
76
|
+
'send-to-chat'?: (props: typeof __VLS_86) => any;
|
|
71
77
|
};
|
|
72
78
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
73
79
|
editor: import("vue").ComputedRef<any>;
|
|
74
80
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
75
81
|
rename: (label: string) => any;
|
|
82
|
+
ready: () => any;
|
|
76
83
|
update: (content: any) => any;
|
|
77
84
|
"update:modelValue": (value: any) => any;
|
|
78
85
|
updateMeta: (patch: Partial<DocPageMeta>) => any;
|
|
79
|
-
ready: () => any;
|
|
80
86
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
81
87
|
onRename?: ((label: string) => any) | undefined;
|
|
88
|
+
onReady?: (() => any) | undefined;
|
|
82
89
|
onUpdate?: ((content: any) => any) | undefined;
|
|
83
90
|
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
84
91
|
onUpdateMeta?: ((patch: Partial<DocPageMeta>) => any) | undefined;
|
|
85
|
-
onReady?: (() => any) | undefined;
|
|
86
92
|
}>, {
|
|
87
93
|
contentType: "json" | "html" | "markdown";
|
|
88
94
|
editable: boolean;
|
|
@@ -91,6 +97,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
91
97
|
showDragHandle: boolean;
|
|
92
98
|
variant: "doc" | "prose";
|
|
93
99
|
showSourceToggle: boolean;
|
|
100
|
+
showBreadcrumb: boolean;
|
|
94
101
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
95
102
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
96
103
|
declare const _default: typeof __VLS_export;
|