@abraca/nuxt 2.9.0 → 2.11.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.
Files changed (70) hide show
  1. package/dist/module.d.mts +14 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -0
  4. package/dist/runtime/assets/editor.css +1 -1
  5. package/dist/runtime/components/AConnectionBadge.d.vue.ts +29 -0
  6. package/dist/runtime/components/AConnectionBadge.vue +79 -0
  7. package/dist/runtime/components/AConnectionBadge.vue.d.ts +29 -0
  8. package/dist/runtime/components/AEditor.d.vue.ts +2 -2
  9. package/dist/runtime/components/AEditor.vue +11 -1
  10. package/dist/runtime/components/AEditor.vue.d.ts +2 -2
  11. package/dist/runtime/components/AEncryptionModePicker.d.vue.ts +33 -0
  12. package/dist/runtime/components/AEncryptionModePicker.vue +211 -0
  13. package/dist/runtime/components/AEncryptionModePicker.vue.d.ts +33 -0
  14. package/dist/runtime/components/AModalShell.d.vue.ts +48 -0
  15. package/dist/runtime/components/AModalShell.vue +105 -0
  16. package/dist/runtime/components/AModalShell.vue.d.ts +48 -0
  17. package/dist/runtime/components/ANodePanel.d.vue.ts +8 -6
  18. package/dist/runtime/components/ANodePanel.vue +25 -0
  19. package/dist/runtime/components/ANodePanel.vue.d.ts +8 -6
  20. package/dist/runtime/components/ANodePanelHeader.d.vue.ts +20 -10
  21. package/dist/runtime/components/ANodePanelHeader.vue +17 -3
  22. package/dist/runtime/components/ANodePanelHeader.vue.d.ts +20 -10
  23. package/dist/runtime/components/ANodeSettingsPanel.d.vue.ts +2 -0
  24. package/dist/runtime/components/ANodeSettingsPanel.vue +21 -1
  25. package/dist/runtime/components/ANodeSettingsPanel.vue.d.ts +2 -0
  26. package/dist/runtime/components/ASnapshotPreviewModal.d.vue.ts +33 -0
  27. package/dist/runtime/components/ASnapshotPreviewModal.vue +430 -0
  28. package/dist/runtime/components/ASnapshotPreviewModal.vue.d.ts +33 -0
  29. package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +2 -2
  30. package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +2 -2
  31. package/dist/runtime/components/editor/ALocationPickerPopover.vue +28 -7
  32. package/dist/runtime/components/registry/APluginDetail.d.vue.ts +2 -2
  33. package/dist/runtime/components/registry/APluginDetail.vue.d.ts +2 -2
  34. package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
  35. package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
  36. package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +6 -0
  37. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +75 -3
  38. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +6 -0
  39. package/dist/runtime/components/shell/ADocPanelServerSettings.d.vue.ts +17 -0
  40. package/dist/runtime/components/shell/ADocPanelServerSettings.vue +253 -0
  41. package/dist/runtime/components/shell/ADocPanelServerSettings.vue.d.ts +17 -0
  42. package/dist/runtime/components/shell/ADocPanelSettings.d.vue.ts +2 -0
  43. package/dist/runtime/components/shell/ADocPanelSettings.vue +15 -4
  44. package/dist/runtime/components/shell/ADocPanelSettings.vue.d.ts +2 -0
  45. package/dist/runtime/components/shell/AUserMenu.d.vue.ts +2 -2
  46. package/dist/runtime/components/shell/AUserMenu.vue.d.ts +2 -2
  47. package/dist/runtime/composables/useDocBreadcrumb.d.ts +17 -2
  48. package/dist/runtime/composables/useDocBreadcrumb.js +17 -3
  49. package/dist/runtime/composables/useDocSnapshots.d.ts +2 -1
  50. package/dist/runtime/composables/useDocSnapshots.js +5 -0
  51. package/dist/runtime/composables/useEditor.d.ts +1 -1
  52. package/dist/runtime/composables/useEditor.js +120 -0
  53. package/dist/runtime/composables/useEditorToolbar.d.ts +12 -4
  54. package/dist/runtime/composables/useEditorToolbar.js +78 -56
  55. package/dist/runtime/composables/useNodeContextMenu.d.ts +10 -0
  56. package/dist/runtime/composables/useNodeContextMenu.js +41 -1
  57. package/dist/runtime/composables/useSwipeGesture.d.ts +48 -0
  58. package/dist/runtime/composables/useSwipeGesture.js +140 -0
  59. package/dist/runtime/extensions/document-header.js +16 -6
  60. package/dist/runtime/extensions/document-meta.js +344 -19
  61. package/dist/runtime/extensions/meta-field.js +42 -0
  62. package/dist/runtime/extensions/views/DocumentMetaView.vue +33 -7
  63. package/dist/runtime/extensions/views/FieldView.vue +51 -19
  64. package/dist/runtime/extensions/views/MetaFieldView.vue +30 -4
  65. package/dist/runtime/middleware/abracadabra-auth.d.ts +1 -1
  66. package/dist/runtime/plugin-abracadabra.client.d.ts +1 -1
  67. package/dist/runtime/plugin-abracadabra.client.js +12 -2
  68. package/dist/runtime/plugin-abracadabra.server.d.ts +1 -1
  69. package/dist/runtime/plugin-shared-globals.client.d.ts +1 -1
  70. package/package.json +1 -4
@@ -0,0 +1,105 @@
1
+ <script setup>
2
+ import { computed, ref } from "vue";
3
+ import { useResizeObserver } from "@vueuse/core";
4
+ import { useSwipeGesture } from "../composables/useSwipeGesture";
5
+ const props = defineProps({
6
+ open: { type: Boolean, required: true },
7
+ maxWidth: { type: String, required: false, default: "sm:max-w-xl" },
8
+ closeable: { type: Boolean, required: false, default: true },
9
+ title: { type: String, required: false },
10
+ subtitle: { type: String, required: false },
11
+ dismissible: { type: Boolean, required: false, default: true },
12
+ swipeable: { type: Boolean, required: false, default: false },
13
+ canSwipeForward: { type: Boolean, required: false, default: false },
14
+ canSwipeBack: { type: Boolean, required: false, default: false }
15
+ });
16
+ const emit = defineEmits(["update:open", "swipe-forward", "swipe-back"]);
17
+ const innerRef = ref();
18
+ const contentHeight = ref(void 0);
19
+ useResizeObserver(innerRef, (entries) => {
20
+ const entry = entries[0];
21
+ if (entry && entry.contentRect.height > 0) contentHeight.value = entry.contentRect.height;
22
+ });
23
+ const swipeRef = ref(null);
24
+ const swipeDirection = ref(null);
25
+ const { swipeOffset, isSwiping } = useSwipeGesture({
26
+ el: swipeRef,
27
+ axis: "x",
28
+ disabled: computed(() => !props.swipeable),
29
+ canSwipeLeft: computed(() => props.canSwipeForward),
30
+ canSwipeRight: computed(() => props.canSwipeBack),
31
+ onSwipeLeft() {
32
+ swipeDirection.value = "forward";
33
+ emit("swipe-forward");
34
+ },
35
+ onSwipeRight() {
36
+ swipeDirection.value = "back";
37
+ emit("swipe-back");
38
+ }
39
+ });
40
+ const transitionName = computed(
41
+ () => swipeDirection.value === "back" ? "ams-step-fade-reverse" : "ams-step-fade"
42
+ );
43
+ function onAfterLeave() {
44
+ swipeDirection.value = null;
45
+ }
46
+ </script>
47
+
48
+ <template>
49
+ <UModal
50
+ :open="props.open"
51
+ :closeable="closeable"
52
+ :dismissible="dismissible"
53
+ :ui="{
54
+ content: `${maxWidth} divide-y-0`,
55
+ header: 'hidden'
56
+ }"
57
+ @update:open="emit('update:open', $event)"
58
+ >
59
+ <template #body>
60
+ <div class="flex flex-col gap-6 p-4 sm:p-6">
61
+ <div
62
+ v-if="title || subtitle"
63
+ class="flex flex-col gap-1"
64
+ >
65
+ <h2
66
+ v-if="title"
67
+ class="text-base font-semibold text-(--ui-text-highlighted)"
68
+ >
69
+ {{ title }}
70
+ </h2>
71
+ <p
72
+ v-if="subtitle"
73
+ class="text-sm text-(--ui-text-muted)"
74
+ >
75
+ {{ subtitle }}
76
+ </p>
77
+ </div>
78
+ <div
79
+ ref="swipeRef"
80
+ class="ams-height-wrap"
81
+ :style="{
82
+ ...contentHeight !== void 0 ? { height: contentHeight + 'px' } : {},
83
+ ...isSwiping ? { transform: `translateX(${swipeOffset.x}px)`, transition: 'none' } : {}
84
+ }"
85
+ >
86
+ <div ref="innerRef">
87
+ <Transition
88
+ :name="transitionName"
89
+ mode="out-in"
90
+ @after-leave="onAfterLeave"
91
+ >
92
+ <slot />
93
+ </Transition>
94
+ </div>
95
+ </div>
96
+
97
+ <slot name="footer" />
98
+ </div>
99
+ </template>
100
+ </UModal>
101
+ </template>
102
+
103
+ <style scoped>
104
+ .ams-height-wrap{overflow:hidden;transition:height .35s cubic-bezier(.4,0,.2,1),transform .3s ease}.ams-step-fade-enter-active{transition:opacity .3s ease,transform .35s cubic-bezier(.4,0,.2,1)}.ams-step-fade-leave-active{transition:opacity .2s ease,transform .2s cubic-bezier(.4,0,.2,1)}.ams-step-fade-enter-from{opacity:0;transform:translateX(16px) scale(.97)}.ams-step-fade-leave-to{opacity:0;transform:translateX(-12px) scale(.98)}.ams-step-fade-reverse-enter-active{transition:opacity .3s ease,transform .35s cubic-bezier(.4,0,.2,1)}.ams-step-fade-reverse-leave-active{transition:opacity .2s ease,transform .2s cubic-bezier(.4,0,.2,1)}.ams-step-fade-reverse-enter-from{opacity:0;transform:translateX(-16px) scale(.97)}.ams-step-fade-reverse-leave-to{opacity:0;transform:translateX(12px) scale(.98)}
105
+ </style>
@@ -0,0 +1,48 @@
1
+ type __VLS_Props = {
2
+ open: boolean;
3
+ /** Tailwind max-width class for the modal content (e.g. `sm:max-w-3xl`). */
4
+ maxWidth?: string;
5
+ closeable?: boolean;
6
+ /** Standard modal heading — guarantees the canonical look every modal shares. */
7
+ title?: string;
8
+ /** Optional muted line under the title (e.g. a short description). */
9
+ subtitle?: string;
10
+ /** When false, Esc / overlay-click cannot dismiss the modal (forced choice). */
11
+ dismissible?: boolean;
12
+ /** Enable horizontal swipe gestures for multi-step navigation. */
13
+ swipeable?: boolean;
14
+ /** Whether forward (swipe left) navigation is available. */
15
+ canSwipeForward?: boolean;
16
+ /** Whether backward (swipe right) navigation is available. */
17
+ canSwipeBack?: boolean;
18
+ };
19
+ declare var __VLS_19: {}, __VLS_21: {};
20
+ type __VLS_Slots = {} & {
21
+ default?: (props: typeof __VLS_19) => any;
22
+ } & {
23
+ footer?: (props: typeof __VLS_21) => any;
24
+ };
25
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
26
+ "update:open": (v: boolean) => any;
27
+ "swipe-forward": () => any;
28
+ "swipe-back": () => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
30
+ "onUpdate:open"?: ((v: boolean) => any) | undefined;
31
+ "onSwipe-forward"?: (() => any) | undefined;
32
+ "onSwipe-back"?: (() => any) | undefined;
33
+ }>, {
34
+ maxWidth: string;
35
+ closeable: boolean;
36
+ dismissible: boolean;
37
+ swipeable: boolean;
38
+ canSwipeForward: boolean;
39
+ canSwipeBack: boolean;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
41
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
+ declare const _default: typeof __VLS_export;
43
+ export default _default;
44
+ type __VLS_WithSlots<T, S> = T & {
45
+ new (): {
46
+ $slots: S;
47
+ };
48
+ };
@@ -7,13 +7,15 @@ type __VLS_Props = {
7
7
  docType?: string;
8
8
  labels?: Partial<AbracadabraLocale['nodePanel']>;
9
9
  /** Tab to open initially. Defaults to 'editor'. */
10
- initialTab?: 'editor' | 'properties' | 'chat' | 'settings' | string;
10
+ initialTab?: 'editor' | 'properties' | 'chat' | 'settings' | 'serverSettings' | string;
11
11
  /**
12
- * Built-in tabs to render. Defaults to all-on; pass an array to limit which
13
- * tabs appear (useful when a developer wants only properties + chat).
14
- * Plugin-registered tab slots are unaffected.
12
+ * Built-in tabs to render. Defaults to editor/properties/chat/settings on;
13
+ * pass an array to limit which tabs appear (useful when a developer wants
14
+ * only properties + chat). `serverSettings` is OPT-IN only rendered when
15
+ * explicitly included (it targets a server hub doc). Plugin-registered tab
16
+ * slots are unaffected.
15
17
  */
16
- tabs?: Array<'editor' | 'properties' | 'chat' | 'settings'>;
18
+ tabs?: Array<'editor' | 'properties' | 'chat' | 'settings' | 'serverSettings'>;
17
19
  };
18
20
  declare var __VLS_11: {
19
21
  nodeId: string | null;
@@ -30,7 +32,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
30
32
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
31
33
  onClose?: (() => any) | undefined;
32
34
  }>, {
33
- initialTab: "editor" | "properties" | "chat" | "settings" | string;
35
+ initialTab: "editor" | "properties" | "chat" | "settings" | "serverSettings" | string;
34
36
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
37
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
38
  declare const _default: typeof __VLS_export;
@@ -12,6 +12,7 @@ import { useRuntimeConfig } from "#imports";
12
12
  import { useChat } from "../composables/useChat";
13
13
  const ANodeChatPanel = defineAsyncComponent(() => import("./chat/ANodeChatPanel.vue"));
14
14
  const ANodeSettingsPanel = defineAsyncComponent(() => import("./ANodeSettingsPanel.vue"));
15
+ const ADocPanelServerSettings = defineAsyncComponent(() => import("./shell/ADocPanelServerSettings.vue"));
15
16
  import { META_FIELD_DEFINITIONS } from "../utils/metaFieldDefinitions";
16
17
  import { resolveDocType } from "../utils/docTypes";
17
18
  const props = defineProps({
@@ -89,6 +90,7 @@ const showChatTab = computed(() => {
89
90
  const showEditorTab = computed(() => !props.tabs || props.tabs.includes("editor"));
90
91
  const showPropertiesTab = computed(() => !props.tabs || props.tabs.includes("properties"));
91
92
  const showSettingsTab = computed(() => !props.tabs || props.tabs.includes("settings"));
93
+ const showServerSettingsTab = computed(() => !!props.tabs && props.tabs.includes("serverSettings"));
92
94
  const _chat = useChat();
93
95
  const chatUnread = computed(() => {
94
96
  if (!props.nodeId) return 0;
@@ -204,6 +206,7 @@ const addFieldMenuItems = computed(
204
206
  :node-label="nodeLabel"
205
207
  :icon="meta.icon ?? docTypeDef.icon"
206
208
  :icon-color="meta.color"
209
+ :provider="childProvider"
207
210
  :editor="activeTab === 'editor' && !usesPageRenderer ? tiptapEditor : null"
208
211
  @expand="navigateTo(`/app/${nodeId}`)"
209
212
  >
@@ -256,6 +259,15 @@ const addFieldMenuItems = computed(
256
259
  :variant="activeTab === 'settings' ? 'soft' : 'ghost'"
257
260
  @click="activeTab = 'settings'"
258
261
  />
262
+ <UButton
263
+ v-if="showServerSettingsTab"
264
+ icon="i-lucide-server-cog"
265
+ label="Server"
266
+ size="xs"
267
+ :color="activeTab === 'serverSettings' ? 'primary' : 'neutral'"
268
+ :variant="activeTab === 'serverSettings' ? 'soft' : 'ghost'"
269
+ @click="activeTab = 'serverSettings'"
270
+ />
259
271
  <UButton
260
272
  v-for="slot in pluginSlots"
261
273
  :key="slot.id"
@@ -332,11 +344,24 @@ const addFieldMenuItems = computed(
332
344
  v-if="nodeId"
333
345
  :doc-id="nodeId"
334
346
  :doc-type-key="currentType"
347
+ :doc-label="nodeLabel"
335
348
  :doc-meta="meta"
336
349
  @update-meta="patchMeta"
337
350
  />
338
351
  </div>
339
352
 
353
+ <!-- Server-settings tab (opt-in via `tabs`) — hub-doc server status. -->
354
+ <div
355
+ v-if="showServerSettingsTab"
356
+ v-show="activeTab === 'serverSettings'"
357
+ class="min-h-[60vh] -mx-4 -mb-4 sm:-mx-6"
358
+ >
359
+ <ADocPanelServerSettings
360
+ v-if="nodeId"
361
+ :doc-id="nodeId"
362
+ />
363
+ </div>
364
+
340
365
  <!-- Properties tab -->
341
366
  <div
342
367
  v-show="activeTab === 'properties'"
@@ -7,13 +7,15 @@ type __VLS_Props = {
7
7
  docType?: string;
8
8
  labels?: Partial<AbracadabraLocale['nodePanel']>;
9
9
  /** Tab to open initially. Defaults to 'editor'. */
10
- initialTab?: 'editor' | 'properties' | 'chat' | 'settings' | string;
10
+ initialTab?: 'editor' | 'properties' | 'chat' | 'settings' | 'serverSettings' | string;
11
11
  /**
12
- * Built-in tabs to render. Defaults to all-on; pass an array to limit which
13
- * tabs appear (useful when a developer wants only properties + chat).
14
- * Plugin-registered tab slots are unaffected.
12
+ * Built-in tabs to render. Defaults to editor/properties/chat/settings on;
13
+ * pass an array to limit which tabs appear (useful when a developer wants
14
+ * only properties + chat). `serverSettings` is OPT-IN only rendered when
15
+ * explicitly included (it targets a server hub doc). Plugin-registered tab
16
+ * slots are unaffected.
15
17
  */
16
- tabs?: Array<'editor' | 'properties' | 'chat' | 'settings'>;
18
+ tabs?: Array<'editor' | 'properties' | 'chat' | 'settings' | 'serverSettings'>;
17
19
  };
18
20
  declare var __VLS_11: {
19
21
  nodeId: string | null;
@@ -30,7 +32,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
30
32
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
31
33
  onClose?: (() => any) | undefined;
32
34
  }>, {
33
- initialTab: "editor" | "properties" | "chat" | "settings" | string;
35
+ initialTab: "editor" | "properties" | "chat" | "settings" | "serverSettings" | string;
34
36
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
37
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
38
  declare const _default: typeof __VLS_export;
@@ -10,12 +10,19 @@ type __VLS_Props = {
10
10
  iconColor?: string;
11
11
  /** TipTap editor — when passed, default undo/redo buttons render */
12
12
  editor?: Editor | null;
13
+ /**
14
+ * The doc's child provider. When passed, the default `#status` slot renders
15
+ * an <AConnectionBadge> so an offline / auth-rejected doc shows a status dot.
16
+ */
17
+ provider?: any;
13
18
  /** Show undo/redo buttons in default slot. Default: true when editor passed */
14
19
  showUndoRedo?: boolean;
15
20
  /** Show expand-to-full-page button. Default: true when nodeId passed */
16
21
  showExpand?: boolean;
17
22
  /** Show presence facepile in default presence slot. Default: true when nodeId passed */
18
23
  showPresence?: boolean;
24
+ /** Show the connection badge in default `#status` slot. Default: true when provider passed */
25
+ showConnectionBadge?: boolean;
19
26
  /** Tooltip text for the expand button */
20
27
  expandTooltip?: string;
21
28
  };
@@ -24,34 +31,37 @@ declare var __VLS_1: {
24
31
  color: string | undefined;
25
32
  }, __VLS_8: {
26
33
  label: string | undefined;
27
- }, __VLS_10: {}, __VLS_12: {}, __VLS_19: {
34
+ }, __VLS_10: {}, __VLS_17: {}, __VLS_19: {}, __VLS_26: {
28
35
  editor: Editor | null | undefined;
29
- }, __VLS_31: {}, __VLS_33: {
30
- expand: () => void;
36
+ }, __VLS_38: {}, __VLS_40: {
37
+ expand: (e?: MouseEvent) => void;
31
38
  };
32
39
  type __VLS_Slots = {} & {
33
40
  icon?: (props: typeof __VLS_1) => any;
34
41
  } & {
35
42
  title?: (props: typeof __VLS_8) => any;
36
43
  } & {
37
- 'actions-left'?: (props: typeof __VLS_10) => any;
44
+ status?: (props: typeof __VLS_10) => any;
38
45
  } & {
39
- presence?: (props: typeof __VLS_12) => any;
46
+ 'actions-left'?: (props: typeof __VLS_17) => any;
40
47
  } & {
41
- 'undo-redo'?: (props: typeof __VLS_19) => any;
48
+ presence?: (props: typeof __VLS_19) => any;
42
49
  } & {
43
- 'actions-right'?: (props: typeof __VLS_31) => any;
50
+ 'undo-redo'?: (props: typeof __VLS_26) => any;
44
51
  } & {
45
- expand?: (props: typeof __VLS_33) => any;
52
+ 'actions-right'?: (props: typeof __VLS_38) => any;
53
+ } & {
54
+ expand?: (props: typeof __VLS_40) => any;
46
55
  };
47
56
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
48
- expand: () => any;
57
+ expand: (event?: MouseEvent | undefined) => any;
49
58
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
50
- onExpand?: (() => any) | undefined;
59
+ onExpand?: ((event?: MouseEvent | undefined) => any) | undefined;
51
60
  }>, {
52
61
  showUndoRedo: boolean;
53
62
  showExpand: boolean;
54
63
  showPresence: boolean;
64
+ showConnectionBadge: boolean;
55
65
  expandTooltip: string;
56
66
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
57
67
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
3
  import AFacepile from "./aware/AFacepile.vue";
4
+ import AConnectionBadge from "./AConnectionBadge.vue";
4
5
  import AEditorUndoButton from "./editor/AEditorUndoButton.vue";
5
6
  import AEditorRedoButton from "./editor/AEditorRedoButton.vue";
6
7
  const props = defineProps({
@@ -9,9 +10,11 @@ const props = defineProps({
9
10
  icon: { type: String, required: false },
10
11
  iconColor: { type: String, required: false },
11
12
  editor: { type: [Object, null], required: false },
13
+ provider: { type: null, required: false },
12
14
  showUndoRedo: { type: Boolean, required: false, default: void 0 },
13
15
  showExpand: { type: Boolean, required: false, default: void 0 },
14
16
  showPresence: { type: Boolean, required: false, default: void 0 },
17
+ showConnectionBadge: { type: Boolean, required: false, default: void 0 },
15
18
  expandTooltip: { type: String, required: false, default: "Open as full page" }
16
19
  });
17
20
  const emit = defineEmits(["expand"]);
@@ -29,6 +32,9 @@ const expandEnabled = computed(
29
32
  const presenceEnabled = computed(
30
33
  () => props.showPresence === void 0 ? !!props.nodeId : props.showPresence
31
34
  );
35
+ const connectionBadgeEnabled = computed(
36
+ () => props.showConnectionBadge === void 0 ? !!props.provider : props.showConnectionBadge
37
+ );
32
38
  </script>
33
39
 
34
40
  <template>
@@ -55,6 +61,14 @@ const presenceEnabled = computed(
55
61
  <span class="font-medium truncate flex-1">{{ nodeLabel || "Document" }}</span>
56
62
  </slot>
57
63
 
64
+ <!-- connection status dot (offline / auth-rejected) for this doc's provider -->
65
+ <slot name="status">
66
+ <AConnectionBadge
67
+ v-if="connectionBadgeEnabled"
68
+ :provider="provider"
69
+ />
70
+ </slot>
71
+
58
72
  <!-- left-of-presence actions (badges, status indicators, etc.) -->
59
73
  <slot name="actions-left" />
60
74
 
@@ -82,10 +96,10 @@ const presenceEnabled = computed(
82
96
  <!-- right-of-undo extension actions -->
83
97
  <slot name="actions-right" />
84
98
 
85
- <!-- expand to full page -->
99
+ <!-- expand to full page (modifier-aware: see the `expand` emit docs) -->
86
100
  <slot
87
101
  name="expand"
88
- :expand="() => emit('expand')"
102
+ :expand="(e) => emit('expand', e)"
89
103
  >
90
104
  <UTooltip
91
105
  v-if="expandEnabled"
@@ -97,7 +111,7 @@ const presenceEnabled = computed(
97
111
  size="xs"
98
112
  variant="ghost"
99
113
  color="neutral"
100
- @click="emit('expand')"
114
+ @click="(e) => emit('expand', e)"
101
115
  />
102
116
  </UTooltip>
103
117
  </slot>
@@ -10,12 +10,19 @@ type __VLS_Props = {
10
10
  iconColor?: string;
11
11
  /** TipTap editor — when passed, default undo/redo buttons render */
12
12
  editor?: Editor | null;
13
+ /**
14
+ * The doc's child provider. When passed, the default `#status` slot renders
15
+ * an <AConnectionBadge> so an offline / auth-rejected doc shows a status dot.
16
+ */
17
+ provider?: any;
13
18
  /** Show undo/redo buttons in default slot. Default: true when editor passed */
14
19
  showUndoRedo?: boolean;
15
20
  /** Show expand-to-full-page button. Default: true when nodeId passed */
16
21
  showExpand?: boolean;
17
22
  /** Show presence facepile in default presence slot. Default: true when nodeId passed */
18
23
  showPresence?: boolean;
24
+ /** Show the connection badge in default `#status` slot. Default: true when provider passed */
25
+ showConnectionBadge?: boolean;
19
26
  /** Tooltip text for the expand button */
20
27
  expandTooltip?: string;
21
28
  };
@@ -24,34 +31,37 @@ declare var __VLS_1: {
24
31
  color: string | undefined;
25
32
  }, __VLS_8: {
26
33
  label: string | undefined;
27
- }, __VLS_10: {}, __VLS_12: {}, __VLS_19: {
34
+ }, __VLS_10: {}, __VLS_17: {}, __VLS_19: {}, __VLS_26: {
28
35
  editor: Editor | null | undefined;
29
- }, __VLS_31: {}, __VLS_33: {
30
- expand: () => void;
36
+ }, __VLS_38: {}, __VLS_40: {
37
+ expand: (e?: MouseEvent) => void;
31
38
  };
32
39
  type __VLS_Slots = {} & {
33
40
  icon?: (props: typeof __VLS_1) => any;
34
41
  } & {
35
42
  title?: (props: typeof __VLS_8) => any;
36
43
  } & {
37
- 'actions-left'?: (props: typeof __VLS_10) => any;
44
+ status?: (props: typeof __VLS_10) => any;
38
45
  } & {
39
- presence?: (props: typeof __VLS_12) => any;
46
+ 'actions-left'?: (props: typeof __VLS_17) => any;
40
47
  } & {
41
- 'undo-redo'?: (props: typeof __VLS_19) => any;
48
+ presence?: (props: typeof __VLS_19) => any;
42
49
  } & {
43
- 'actions-right'?: (props: typeof __VLS_31) => any;
50
+ 'undo-redo'?: (props: typeof __VLS_26) => any;
44
51
  } & {
45
- expand?: (props: typeof __VLS_33) => any;
52
+ 'actions-right'?: (props: typeof __VLS_38) => any;
53
+ } & {
54
+ expand?: (props: typeof __VLS_40) => any;
46
55
  };
47
56
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
48
- expand: () => any;
57
+ expand: (event?: MouseEvent | undefined) => any;
49
58
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
50
- onExpand?: (() => any) | undefined;
59
+ onExpand?: ((event?: MouseEvent | undefined) => any) | undefined;
51
60
  }>, {
52
61
  showUndoRedo: boolean;
53
62
  showExpand: boolean;
54
63
  showPresence: boolean;
64
+ showConnectionBadge: boolean;
55
65
  expandTooltip: string;
56
66
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
57
67
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -4,6 +4,8 @@ type __VLS_Props = {
4
4
  docId: string;
5
5
  /** Document type key (drives metaSchema form). */
6
6
  docTypeKey?: string;
7
+ /** Document label — used as the title when serializing a snapshot preview. */
8
+ docLabel?: string;
7
9
  /** Document meta to read/write. */
8
10
  docMeta?: DocPageMeta | null;
9
11
  /** Permission entries — left to the consumer (varies per backend). */
@@ -1,11 +1,13 @@
1
1
  <script setup>
2
- import { computed, toRef } from "vue";
2
+ import { computed, ref, toRef, watch } from "vue";
3
3
  import { useDocSnapshots } from "../composables/useDocSnapshots";
4
4
  import { useAbracadabra } from "../composables/useAbracadabra";
5
5
  import ADocPanelSettings from "./shell/ADocPanelSettings.vue";
6
+ import ASnapshotPreviewModal from "./ASnapshotPreviewModal.vue";
6
7
  const props = defineProps({
7
8
  docId: { type: String, required: true },
8
9
  docTypeKey: { type: String, required: false },
10
+ docLabel: { type: String, required: false },
9
11
  docMeta: { type: [Object, null], required: false },
10
12
  permissions: { type: Array, required: false, default: () => [] },
11
13
  loadingPermissions: { type: Boolean, required: false, default: false },
@@ -16,6 +18,10 @@ const emit = defineEmits(["grant-permission", "change-role", "revoke-permission"
16
18
  const abra = useAbracadabra();
17
19
  const docIdRef = toRef(props, "docId");
18
20
  const snaps = useDocSnapshots(docIdRef);
21
+ watch(docIdRef, (id) => {
22
+ if (id) snaps.fetchList();
23
+ }, { immediate: true });
24
+ const previewVersion = ref(null);
19
25
  const effectiveRole = computed(() => abra.provider.value?.effectiveRole ?? null);
20
26
  const userName = computed(() => abra.userName?.value ?? "");
21
27
  const syncStatusIcon = computed(() => abra.provider.value ? "i-lucide-cloud" : "i-lucide-cloud-off");
@@ -54,6 +60,20 @@ const syncStatusLabel = computed(() => abra.provider.value ? "Connected" : "Disc
54
60
  @delete-snapshot="(v) => snaps.remove(v)"
55
61
  @restore-snapshot="(v) => snaps.restore(v)"
56
62
  @fork-snapshot="(v) => snaps.fork(v)"
63
+ @preview-snapshot="(v) => previewVersion = v"
57
64
  @load-more-snapshots="snaps.loadMore"
58
65
  />
66
+
67
+ <ASnapshotPreviewModal
68
+ v-model:version="previewVersion"
69
+ :snapshots="snaps.snapshots.value"
70
+ :get-snapshot="snaps.getSnapshot"
71
+ :doc-label="docLabel"
72
+ :doc-type="docTypeKey"
73
+ :doc-meta="docMeta"
74
+ :is-owner="isOwner"
75
+ @restore="(v) => snaps.restore(v)"
76
+ @fork="(v) => snaps.fork(v)"
77
+ @delete="(v) => snaps.remove(v)"
78
+ />
59
79
  </template>
@@ -4,6 +4,8 @@ type __VLS_Props = {
4
4
  docId: string;
5
5
  /** Document type key (drives metaSchema form). */
6
6
  docTypeKey?: string;
7
+ /** Document label — used as the title when serializing a snapshot preview. */
8
+ docLabel?: string;
7
9
  /** Document meta to read/write. */
8
10
  docMeta?: DocPageMeta | null;
9
11
  /** Permission entries — left to the consumer (varies per backend). */
@@ -0,0 +1,33 @@
1
+ import type { SnapshotData, SnapshotMeta } from '@abraca/dabra';
2
+ import type { DocPageMeta } from '../types.js';
3
+ type __VLS_Props = {
4
+ /** Selected version — null closes the modal. The parent owns this. */
5
+ version: number | null;
6
+ /** The loaded snapshot metadata list (compare-baseline candidates). */
7
+ snapshots?: SnapshotMeta[];
8
+ /** Fetch a single snapshot's data blob (e.g. `useDocSnapshots().getSnapshot`). */
9
+ getSnapshot: (version: number) => Promise<SnapshotData | null>;
10
+ /** Document label — used as the title when serializing. */
11
+ docLabel?: string;
12
+ /** Document page type — passed to the markdown serializer. */
13
+ docType?: string;
14
+ /** Document meta — passed to the markdown serializer. */
15
+ docMeta?: DocPageMeta | null;
16
+ /** Whether the current user may delete snapshots. */
17
+ isOwner?: boolean;
18
+ };
19
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ delete: (version: number) => any;
21
+ restore: (version: number) => any;
22
+ fork: (version: number) => any;
23
+ "update:version": (value: number | null) => any;
24
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
25
+ onDelete?: ((version: number) => any) | undefined;
26
+ onRestore?: ((version: number) => any) | undefined;
27
+ onFork?: ((version: number) => any) | undefined;
28
+ "onUpdate:version"?: ((value: number | null) => any) | undefined;
29
+ }>, {
30
+ snapshots: SnapshotMeta[];
31
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;