@abraca/nuxt 2.0.11 → 2.4.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 (135) hide show
  1. package/dist/module.d.mts +68 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +99 -4
  4. package/dist/runtime/components/ACodeEditor.d.vue.ts +26 -0
  5. package/dist/runtime/components/ACodeEditor.vue +268 -0
  6. package/dist/runtime/components/ACodeEditor.vue.d.ts +26 -0
  7. package/dist/runtime/components/ADocumentTree.vue +52 -20
  8. package/dist/runtime/components/AEditor.d.vue.ts +20 -13
  9. package/dist/runtime/components/AEditor.vue +55 -2
  10. package/dist/runtime/components/AEditor.vue.d.ts +20 -13
  11. package/dist/runtime/components/ANodePanel.vue +64 -60
  12. package/dist/runtime/components/ANotificationBell.d.vue.ts +1 -1
  13. package/dist/runtime/components/ANotificationBell.vue.d.ts +1 -1
  14. package/dist/runtime/components/ASpaceFormModal.d.vue.ts +2 -2
  15. package/dist/runtime/components/ASpaceFormModal.vue.d.ts +2 -2
  16. package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
  17. package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
  18. package/dist/runtime/components/aware/APresenceBlobs.d.vue.ts +29 -1
  19. package/dist/runtime/components/aware/APresenceBlobs.vue +54 -8
  20. package/dist/runtime/components/aware/APresenceBlobs.vue.d.ts +29 -1
  21. package/dist/runtime/components/aware/APresenceCursors.d.vue.ts +11 -0
  22. package/dist/runtime/components/aware/APresenceCursors.vue +74 -9
  23. package/dist/runtime/components/aware/APresenceCursors.vue.d.ts +11 -0
  24. package/dist/runtime/components/aware/AToggleGroup.d.vue.ts +28 -13
  25. package/dist/runtime/components/aware/AToggleGroup.vue +56 -20
  26. package/dist/runtime/components/aware/AToggleGroup.vue.d.ts +28 -13
  27. package/dist/runtime/components/docs/ADocsNavigation.d.vue.ts +1 -1
  28. package/dist/runtime/components/docs/ADocsNavigation.vue.d.ts +1 -1
  29. package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
  30. package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
  31. package/dist/runtime/components/docs/ADocsSearchButton.d.vue.ts +1 -1
  32. package/dist/runtime/components/docs/ADocsSearchButton.vue.d.ts +1 -1
  33. package/dist/runtime/components/docs/ADocsToc.d.vue.ts +2 -2
  34. package/dist/runtime/components/docs/ADocsToc.vue.d.ts +2 -2
  35. package/dist/runtime/components/editor/AEditorRedoButton.d.vue.ts +1 -1
  36. package/dist/runtime/components/editor/AEditorRedoButton.vue.d.ts +1 -1
  37. package/dist/runtime/components/editor/AEditorUndoButton.d.vue.ts +1 -1
  38. package/dist/runtime/components/editor/AEditorUndoButton.vue.d.ts +1 -1
  39. package/dist/runtime/components/editor/AFileGlbViewer.vue +27 -10
  40. package/dist/runtime/components/editor/ANodeInlineLabel.d.vue.ts +1 -1
  41. package/dist/runtime/components/editor/ANodeInlineLabel.vue.d.ts +1 -1
  42. package/dist/runtime/components/registry/APluginBrowser.d.vue.ts +23 -0
  43. package/dist/runtime/components/registry/APluginBrowser.vue +155 -0
  44. package/dist/runtime/components/registry/APluginBrowser.vue.d.ts +23 -0
  45. package/dist/runtime/components/registry/APluginCapabilityDialog.d.vue.ts +17 -0
  46. package/dist/runtime/components/registry/APluginCapabilityDialog.vue +159 -0
  47. package/dist/runtime/components/registry/APluginCapabilityDialog.vue.d.ts +17 -0
  48. package/dist/runtime/components/registry/APluginCard.d.vue.ts +20 -0
  49. package/dist/runtime/components/registry/APluginCard.vue +91 -0
  50. package/dist/runtime/components/registry/APluginCard.vue.d.ts +20 -0
  51. package/dist/runtime/components/registry/APluginDetail.d.vue.ts +18 -0
  52. package/dist/runtime/components/registry/APluginDetail.vue +252 -0
  53. package/dist/runtime/components/registry/APluginDetail.vue.d.ts +18 -0
  54. package/dist/runtime/components/renderers/ACodeRenderer.d.vue.ts +15 -0
  55. package/dist/runtime/components/renderers/ACodeRenderer.vue +68 -0
  56. package/dist/runtime/components/renderers/ACodeRenderer.vue.d.ts +15 -0
  57. package/dist/runtime/components/renderers/AGraphRenderer.vue +416 -120
  58. package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
  59. package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
  60. package/dist/runtime/components/renderers/sheets/ASheetsToolbar.d.vue.ts +4 -4
  61. package/dist/runtime/components/renderers/sheets/ASheetsToolbar.vue.d.ts +4 -4
  62. package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +11 -0
  63. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +16 -0
  64. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +11 -0
  65. package/dist/runtime/components/shell/ASettingsSection.d.vue.ts +35 -0
  66. package/dist/runtime/components/shell/ASettingsSection.vue +26 -0
  67. package/dist/runtime/components/shell/ASettingsSection.vue.d.ts +35 -0
  68. package/dist/runtime/components/shell/ASidebar.d.vue.ts +1 -1
  69. package/dist/runtime/components/shell/ASidebar.vue.d.ts +1 -1
  70. package/dist/runtime/components/shell/AUserMenu.d.vue.ts +3 -0
  71. package/dist/runtime/components/shell/AUserMenu.vue +4 -0
  72. package/dist/runtime/components/shell/AUserMenu.vue.d.ts +3 -0
  73. package/dist/runtime/composables/useAbracadabraSchema.d.ts +83 -0
  74. package/dist/runtime/composables/useAbracadabraSchema.js +52 -0
  75. package/dist/runtime/composables/useAggregatedPresence.d.ts +1 -6
  76. package/dist/runtime/composables/useCalendarView.d.ts +1 -1
  77. package/dist/runtime/composables/useChat.js +1 -0
  78. package/dist/runtime/composables/useDocBreadcrumb.d.ts +21 -0
  79. package/dist/runtime/composables/useDocBreadcrumb.js +33 -0
  80. package/dist/runtime/composables/useDocEntryTyped.d.ts +60 -0
  81. package/dist/runtime/composables/useDocEntryTyped.js +70 -0
  82. package/dist/runtime/composables/useEditorDragHandle.js +18 -0
  83. package/dist/runtime/composables/useEditorSuggestions.js +2 -1
  84. package/dist/runtime/composables/useInstalledPlugins.d.ts +3 -21
  85. package/dist/runtime/composables/useInstalledPlugins.js +2 -12
  86. package/dist/runtime/composables/useMetaMenuItems.d.ts +21 -0
  87. package/dist/runtime/composables/useMetaMenuItems.js +115 -0
  88. package/dist/runtime/composables/useMetaValidator.d.ts +27 -0
  89. package/dist/runtime/composables/useMetaValidator.js +10 -0
  90. package/dist/runtime/composables/usePluginCatalog.d.ts +161 -0
  91. package/dist/runtime/composables/usePluginCatalog.js +234 -0
  92. package/dist/runtime/composables/useQuery.d.ts +79 -0
  93. package/dist/runtime/composables/useQuery.js +97 -0
  94. package/dist/runtime/composables/useSpaces.js +4 -5
  95. package/dist/runtime/composables/useTableView.d.ts +3 -3
  96. package/dist/runtime/composables/useTypedDoc.d.ts +97 -0
  97. package/dist/runtime/composables/useTypedDoc.js +114 -0
  98. package/dist/runtime/composables/useWebRTC.js +44 -5
  99. package/dist/runtime/extensions/document-meta.js +5 -0
  100. package/dist/runtime/extensions/timeline.d.ts +11 -0
  101. package/dist/runtime/extensions/timeline.js +52 -0
  102. package/dist/runtime/extensions/views/DocumentMetaView.d.vue.ts +4 -0
  103. package/dist/runtime/extensions/views/DocumentMetaView.vue +63 -0
  104. package/dist/runtime/extensions/views/DocumentMetaView.vue.d.ts +4 -0
  105. package/dist/runtime/extensions/views/TimelineItemView.d.vue.ts +4 -0
  106. package/dist/runtime/extensions/views/TimelineItemView.vue +131 -0
  107. package/dist/runtime/extensions/views/TimelineItemView.vue.d.ts +4 -0
  108. package/dist/runtime/extensions/views/TimelineView.d.vue.ts +9 -0
  109. package/dist/runtime/extensions/views/TimelineView.vue +29 -0
  110. package/dist/runtime/extensions/views/TimelineView.vue.d.ts +9 -0
  111. package/dist/runtime/locale.d.ts +2 -0
  112. package/dist/runtime/locale.js +2 -0
  113. package/dist/runtime/plugin-abracadabra.client.js +107 -6
  114. package/dist/runtime/plugin-registry.d.ts +11 -30
  115. package/dist/runtime/plugin-registry.js +2 -82
  116. package/dist/runtime/plugins/core.plugin.js +10 -4
  117. package/dist/runtime/server/api/_abracadabra/spaces.get.d.ts +1 -1
  118. package/dist/runtime/server/plugins/abracadabra-service.js +28 -0
  119. package/dist/runtime/server/utils/docCache.js +24 -3
  120. package/dist/runtime/server/utils/schemaServerSupport.d.ts +52 -0
  121. package/dist/runtime/server/utils/schemaServerSupport.js +51 -0
  122. package/dist/runtime/types.d.ts +63 -46
  123. package/dist/runtime/utils/docTypes.d.ts +15 -0
  124. package/dist/runtime/utils/docTypes.js +20 -0
  125. package/dist/runtime/utils/loadCodeMirror.d.ts +32 -0
  126. package/dist/runtime/utils/loadCodeMirror.js +65 -0
  127. package/dist/runtime/utils/loadThree.d.ts +18 -0
  128. package/dist/runtime/utils/loadThree.js +46 -0
  129. package/dist/runtime/utils/markdownToYjs.d.ts +1 -23
  130. package/dist/runtime/utils/markdownToYjs.js +5 -440
  131. package/dist/runtime/utils/schemaSupport.d.ts +60 -0
  132. package/dist/runtime/utils/schemaSupport.js +40 -0
  133. package/dist/runtime/utils/yjsConvert.d.ts +1 -14
  134. package/dist/runtime/utils/yjsConvert.js +5 -331
  135. package/package.json +86 -21
@@ -18,18 +18,41 @@ function _wireEvents(rtc) {
18
18
  rtc.on(event, handler);
19
19
  _unbinds.push(() => rtc.off(event, handler));
20
20
  };
21
+ function normalizePeer(p) {
22
+ const peerId = p?.peerId ?? p?.peer_id;
23
+ return {
24
+ ...p,
25
+ peerId,
26
+ peer_id: peerId,
27
+ displayName: p?.displayName ?? p?.name,
28
+ color: p?.color
29
+ };
30
+ }
21
31
  on("connected", () => {
22
32
  isConnected.value = true;
23
33
  webrtcStatus.value = "connected";
24
- localPeerId.value = rtc.localPeerId;
34
+ const newLocalId = rtc.localPeerId;
35
+ localPeerId.value = newLocalId;
36
+ const next = /* @__PURE__ */ new Map();
37
+ const sdkPeers = rtc.peers instanceof Map ? rtc.peers : null;
38
+ if (sdkPeers) {
39
+ for (const [pid, p] of sdkPeers.entries()) {
40
+ if (!pid || pid === newLocalId) continue;
41
+ next.set(pid, normalizePeer(p));
42
+ }
43
+ }
44
+ peers.value = next;
25
45
  });
26
46
  on("disconnected", () => {
27
47
  isConnected.value = false;
28
48
  webrtcStatus.value = "disconnected";
29
49
  });
30
50
  on("peerJoined", (peer) => {
51
+ const norm = normalizePeer(peer);
52
+ if (!norm.peerId) return;
53
+ if (norm.peerId === localPeerId.value) return;
31
54
  const next = new Map(peers.value);
32
- next.set(peer.peerId, peer);
55
+ next.set(norm.peerId, norm);
33
56
  peers.value = next;
34
57
  });
35
58
  on("peerLeft", ({ peerId }) => {
@@ -40,6 +63,13 @@ function _wireEvents(rtc) {
40
63
  nextE2ee.delete(peerId);
41
64
  e2eeEstablishedPeers.value = nextE2ee;
42
65
  });
66
+ on("peerProfile", ({ peerId, name, color }) => {
67
+ const existing = peers.value.get(peerId);
68
+ if (!existing) return;
69
+ const next = new Map(peers.value);
70
+ next.set(peerId, { ...existing, displayName: name, name, color });
71
+ peers.value = next;
72
+ });
43
73
  on("peerConnectionState", ({ peerId, state }) => {
44
74
  const existing = peers.value.get(peerId);
45
75
  if (existing) {
@@ -100,7 +130,7 @@ function fromBase64Url(str) {
100
130
  }
101
131
  async function connect(options) {
102
132
  if (_rtc && isConnected.value) return;
103
- const { provider, keystore, isClaimed } = useAbracadabra();
133
+ const { provider, keystore, isClaimed, userName, userColor } = useAbracadabra();
104
134
  if (!provider.value) return;
105
135
  const config = useRuntimeConfig();
106
136
  const webrtcConfig = config.public.abracadabra?.webrtc ?? {};
@@ -138,8 +168,17 @@ async function connect(options) {
138
168
  }
139
169
  const rtc = AbracadabraWebRTC.fromProvider(provider.value, {
140
170
  iceServers: resolvedIceServers,
141
- enableFileTransfer: webrtcConfig.fileTransfer ?? false,
142
- e2ee: e2eeIdentity
171
+ // Default file-transfer ON. The SDK's default (false) means
172
+ // `useFileTransfer().sendFile()` queues bytes onto a data channel that
173
+ // never gets created → silent 0 % stuck transfer. Apps that explicitly
174
+ // want to disable can pass `webrtc.fileTransfer: false` in nuxt.config.
175
+ enableFileTransfer: webrtcConfig.fileTransfer ?? true,
176
+ e2ee: e2eeIdentity,
177
+ // Pass identity through so peers can label each other in the mesh.
178
+ // Without these the SDK's `peerProfile` event never fires and the UI
179
+ // shows opaque peer IDs ("peer-jl0z7m" etc.) instead of usernames.
180
+ displayName: userName.value || void 0,
181
+ color: userColor.value || void 0
143
182
  });
144
183
  _initWebRTC(rtc);
145
184
  await rtc.connect();
@@ -1,5 +1,7 @@
1
1
  import { Node } from "@tiptap/core";
2
2
  import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
3
+ import { VueNodeViewRenderer } from "@tiptap/vue-3";
4
+ import DocumentMetaView from "./views/DocumentMetaView.vue";
3
5
  export const DocumentMeta = Node.create({
4
6
  name: "documentMeta",
5
7
  content: "inline*",
@@ -10,6 +12,9 @@ export const DocumentMeta = Node.create({
10
12
  renderHTML() {
11
13
  return ["div", { "data-type": "document-meta" }, 0];
12
14
  },
15
+ addNodeView() {
16
+ return VueNodeViewRenderer(DocumentMetaView);
17
+ },
13
18
  addKeyboardShortcuts() {
14
19
  return {
15
20
  Backspace: ({ editor }) => {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Timeline + TimelineItem TipTap nodes.
3
+ *
4
+ * Vertical event timeline with per-item icon, label, and freeform date.
5
+ * Optional builtin — disabled via `abracadabra.disabledBuiltins: ['timeline']`.
6
+ *
7
+ * Ported 1:1 from cou-sh/app/extensions/timeline.ts.
8
+ */
9
+ import { Node } from '@tiptap/core';
10
+ export declare const TimelineItem: Node<any, any>;
11
+ export declare const Timeline: Node<any, any>;
@@ -0,0 +1,52 @@
1
+ import { Node, mergeAttributes } from "@tiptap/core";
2
+ import { VueNodeViewRenderer } from "@tiptap/vue-3";
3
+ import TimelineView from "./views/TimelineView.vue";
4
+ import TimelineItemView from "./views/TimelineItemView.vue";
5
+ export const TimelineItem = Node.create({
6
+ name: "timelineItem",
7
+ content: "block+",
8
+ addAttributes() {
9
+ return {
10
+ date: { default: "" },
11
+ label: { default: "Event" },
12
+ icon: { default: "" }
13
+ };
14
+ },
15
+ parseHTML() {
16
+ return [
17
+ {
18
+ tag: "div[data-timeline-item]",
19
+ getAttrs: (el) => ({
20
+ date: el.getAttribute("data-date") || "",
21
+ label: el.getAttribute("data-label") || "Event",
22
+ icon: el.getAttribute("data-icon") || ""
23
+ })
24
+ }
25
+ ];
26
+ },
27
+ renderHTML({ HTMLAttributes }) {
28
+ return ["div", mergeAttributes({
29
+ "data-timeline-item": "",
30
+ "data-date": HTMLAttributes.date,
31
+ "data-label": HTMLAttributes.label,
32
+ "data-icon": HTMLAttributes.icon
33
+ }), 0];
34
+ },
35
+ addNodeView() {
36
+ return VueNodeViewRenderer(TimelineItemView);
37
+ }
38
+ });
39
+ export const Timeline = Node.create({
40
+ name: "timeline",
41
+ group: "block",
42
+ content: "timelineItem+",
43
+ parseHTML() {
44
+ return [{ tag: "div[data-timeline]" }];
45
+ },
46
+ renderHTML() {
47
+ return ["div", { "data-timeline": "" }, 0];
48
+ },
49
+ addNodeView() {
50
+ return VueNodeViewRenderer(TimelineView);
51
+ }
52
+ });
@@ -0,0 +1,4 @@
1
+ import type { NodeViewProps } from '@tiptap/vue-3';
2
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,63 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { NodeViewWrapper, NodeViewContent } from "@tiptap/vue-3";
4
+ import { buildMetaMenuItems } from "../../composables/useMetaMenuItems";
5
+ const props = defineProps({
6
+ decorations: { type: Array, required: true },
7
+ selected: { type: Boolean, required: true },
8
+ updateAttributes: { type: Function, required: true },
9
+ deleteNode: { type: Function, required: true },
10
+ node: { type: null, required: true },
11
+ view: { type: null, required: true },
12
+ getPos: { type: null, required: true },
13
+ innerDecorations: { type: null, required: true },
14
+ editor: { type: Object, required: true },
15
+ extension: { type: Object, required: true },
16
+ HTMLAttributes: { type: Object, required: true }
17
+ });
18
+ const items = computed(() => {
19
+ void props.node.content.size;
20
+ return buildMetaMenuItems(props.editor);
21
+ });
22
+ </script>
23
+
24
+ <template>
25
+ <NodeViewWrapper
26
+ as="div"
27
+ data-type="document-meta"
28
+ class="group/meta"
29
+ :class="{ 'meta-empty': node.content.size === 0 && !props.editor.isEditable }"
30
+ draggable="false"
31
+ @dragstart.prevent.stop
32
+ >
33
+ <NodeViewContent
34
+ as="span"
35
+ style="display: contents"
36
+ />
37
+ <span
38
+ v-show="props.editor.isEditable"
39
+ contenteditable="false"
40
+ class="inline-flex items-center"
41
+ >
42
+ <UDropdownMenu
43
+ :items="items"
44
+ :content="{ side: 'bottom', align: 'start' }"
45
+ :ui="{ content: 'w-48' }"
46
+ >
47
+ <UButton
48
+ icon="i-lucide-plus"
49
+ size="2xs"
50
+ color="neutral"
51
+ variant="ghost"
52
+ class="opacity-0 group-hover/meta:opacity-40 hover:!opacity-100 transition-opacity"
53
+ />
54
+ </UDropdownMenu>
55
+ </span>
56
+ <span
57
+ v-if="node.content.size === 0 && props.editor.isEditable"
58
+ class="text-sm text-(--ui-text-muted) pointer-events-none opacity-60"
59
+ >
60
+ Type '/' to add a property…
61
+ </span>
62
+ </NodeViewWrapper>
63
+ </template>
@@ -0,0 +1,4 @@
1
+ import type { NodeViewProps } from '@tiptap/vue-3';
2
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import type { NodeViewProps } from '@tiptap/vue-3';
2
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,131 @@
1
+ <script setup>
2
+ import { computed, ref, watch } from "vue";
3
+ import { NodeViewWrapper, NodeViewContent } from "@tiptap/vue-3";
4
+ import ANodeInlineLabel from "../../components/editor/ANodeInlineLabel.vue";
5
+ import AIconPickerPopover from "../../components/editor/AIconPickerPopover.vue";
6
+ const props = defineProps({
7
+ decorations: { type: Array, required: true },
8
+ selected: { type: Boolean, required: true },
9
+ updateAttributes: { type: Function, required: true },
10
+ deleteNode: { type: Function, required: true },
11
+ node: { type: null, required: true },
12
+ view: { type: null, required: true },
13
+ getPos: { type: null, required: true },
14
+ innerDecorations: { type: null, required: true },
15
+ editor: { type: Object, required: true },
16
+ extension: { type: Object, required: true },
17
+ HTMLAttributes: { type: Object, required: true }
18
+ });
19
+ const date = computed(() => props.node.attrs.date || "");
20
+ const label = computed(() => props.node.attrs.label || "");
21
+ const icon = computed(() => props.node.attrs.icon || "");
22
+ const iconShort = computed(() => icon.value.replace(/^i-lucide-/, ""));
23
+ const iconPopoverOpen = ref(false);
24
+ const datePopoverOpen = ref(false);
25
+ const dateDraft = ref("");
26
+ watch(datePopoverOpen, (open) => {
27
+ if (open) dateDraft.value = date.value;
28
+ });
29
+ function setLabel(v) {
30
+ props.updateAttributes({ label: v });
31
+ }
32
+ function setIcon(name) {
33
+ props.updateAttributes({ icon: name ? `i-lucide-${name}` : "" });
34
+ iconPopoverOpen.value = false;
35
+ }
36
+ function commitDate() {
37
+ props.updateAttributes({ date: dateDraft.value.trim() });
38
+ datePopoverOpen.value = false;
39
+ }
40
+ function onDateKeydown(e) {
41
+ if (e.key === "Enter") {
42
+ e.preventDefault();
43
+ commitDate();
44
+ }
45
+ }
46
+ </script>
47
+
48
+ <template>
49
+ <NodeViewWrapper
50
+ as="div"
51
+ class="group/item relative ps-8 pb-5 last:pb-0"
52
+ >
53
+ <div
54
+ class="absolute left-0 top-1.5 size-4 rounded-full bg-(--ui-bg) border-2 border-(--ui-border-accented) flex items-center justify-center"
55
+ contenteditable="false"
56
+ >
57
+ <UIcon
58
+ v-if="icon"
59
+ :name="icon"
60
+ class="size-2.5 text-(--ui-primary)"
61
+ />
62
+ <div
63
+ v-else
64
+ class="size-1.5 rounded-full bg-(--ui-primary)"
65
+ />
66
+ </div>
67
+ <div
68
+ class="flex items-center gap-2 text-sm"
69
+ contenteditable="false"
70
+ >
71
+ <AIconPickerPopover
72
+ :model-value="iconShort"
73
+ :open="iconPopoverOpen"
74
+ @update:model-value="setIcon"
75
+ @update:open="iconPopoverOpen = $event"
76
+ >
77
+ <button
78
+ class="shrink-0 size-5 flex items-center justify-center rounded-sm hover:bg-(--ui-bg-elevated)/60 text-(--ui-text-muted)"
79
+ :title="icon ? 'Change icon' : 'Add icon'"
80
+ @click.stop="iconPopoverOpen = true"
81
+ >
82
+ <UIcon
83
+ :name="icon || 'i-lucide-plus'"
84
+ class="size-4"
85
+ :class="!icon ? 'opacity-0 group-hover/item:opacity-60 transition-opacity' : ''"
86
+ />
87
+ </button>
88
+ </AIconPickerPopover>
89
+ <ANodeInlineLabel
90
+ :model-value="label"
91
+ placeholder="Event"
92
+ variant="title"
93
+ @update:model-value="setLabel"
94
+ />
95
+ <UPopover
96
+ v-model:open="datePopoverOpen"
97
+ :content="{ align: 'end' }"
98
+ >
99
+ <button
100
+ class="text-xs text-(--ui-text-muted) hover:text-(--ui-text) rounded-sm hover:bg-(--ui-bg-elevated)/60 px-1.5 py-0.5 inline-flex items-center gap-1"
101
+ type="button"
102
+ >
103
+ <UIcon
104
+ name="i-lucide-calendar"
105
+ class="size-3"
106
+ />
107
+ <span v-if="date">{{ date }}</span>
108
+ <span
109
+ v-else
110
+ class="italic"
111
+ >Add date</span>
112
+ </button>
113
+ <template #content>
114
+ <div class="p-2 w-56 flex flex-col gap-1">
115
+ <UInput
116
+ v-model="dateDraft"
117
+ autofocus
118
+ size="sm"
119
+ placeholder="e.g. 2026-04-20 or April 2026"
120
+ @keydown="onDateKeydown"
121
+ @blur="commitDate"
122
+ />
123
+ </div>
124
+ </template>
125
+ </UPopover>
126
+ </div>
127
+ <div class="mt-1 text-sm text-(--ui-text-muted)">
128
+ <NodeViewContent class="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&>*]:my-1" />
129
+ </div>
130
+ </NodeViewWrapper>
131
+ </template>
@@ -0,0 +1,4 @@
1
+ import type { NodeViewProps } from '@tiptap/vue-3';
2
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * NodeView for the `timeline` block — renders the vertical guide line.
3
+ *
4
+ * Ported 1:1 from cou-sh/app/components/editor/TimelineView.vue.
5
+ */
6
+ import type { NodeViewProps } from '@tiptap/vue-3';
7
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,29 @@
1
+ <script setup>
2
+ import { NodeViewWrapper, NodeViewContent } from "@tiptap/vue-3";
3
+ defineProps({
4
+ decorations: { type: Array, required: true },
5
+ selected: { type: Boolean, required: true },
6
+ updateAttributes: { type: Function, required: true },
7
+ deleteNode: { type: Function, required: true },
8
+ node: { type: null, required: true },
9
+ view: { type: null, required: true },
10
+ getPos: { type: null, required: true },
11
+ innerDecorations: { type: null, required: true },
12
+ editor: { type: Object, required: true },
13
+ extension: { type: Object, required: true },
14
+ HTMLAttributes: { type: Object, required: true }
15
+ });
16
+ </script>
17
+
18
+ <template>
19
+ <NodeViewWrapper
20
+ as="div"
21
+ class="my-5 ms-2 relative"
22
+ >
23
+ <div
24
+ class="absolute left-2 top-2 bottom-2 w-px bg-(--ui-border)"
25
+ contenteditable="false"
26
+ />
27
+ <NodeViewContent />
28
+ </NodeViewWrapper>
29
+ </template>
@@ -0,0 +1,9 @@
1
+ /**
2
+ * NodeView for the `timeline` block — renders the vertical guide line.
3
+ *
4
+ * Ported 1:1 from cou-sh/app/components/editor/TimelineView.vue.
5
+ */
6
+ import type { NodeViewProps } from '@tiptap/vue-3';
7
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -232,6 +232,8 @@ export interface AbracadabraLocale {
232
232
  graph: {
233
233
  addNode: string;
234
234
  empty: string;
235
+ loading: string;
236
+ untitled: string;
235
237
  pin: string;
236
238
  unpin: string;
237
239
  openAsDoc: string;
@@ -218,6 +218,8 @@ export const DEFAULT_LOCALE = {
218
218
  graph: {
219
219
  addNode: "Add node",
220
220
  empty: "No nodes yet",
221
+ loading: "Loading graph\u2026",
222
+ untitled: "New node",
221
223
  pin: "Pin position",
222
224
  unpin: "Unpin",
223
225
  openAsDoc: "Open as document",