camox 0.41.1 → 0.42.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 (49) hide show
  1. package/dist/core/components/lexical/SidebarLexicalEditor.js +42 -39
  2. package/dist/core/createApp.d.ts +18 -4
  3. package/dist/core/createLayout.d.ts +1 -1
  4. package/dist/core/editing/createEditableBlock.d.ts +8 -1
  5. package/dist/core/editing/createEditableBlock.js +636 -459
  6. package/dist/core/hooks/useOverlayState.js +11 -0
  7. package/dist/core/lib/fieldTypes.js +5 -5
  8. package/dist/core/lib/lexicalState.js +17 -1
  9. package/dist/features/preview/CamoxPreview.js +80 -73
  10. package/dist/features/preview/commentsEnabled.js +8 -0
  11. package/dist/features/preview/components/AddBlockSidebar.js +79 -89
  12. package/dist/features/preview/components/AssetLightbox.js +4 -11
  13. package/dist/features/preview/components/AttachedComments.js +194 -0
  14. package/dist/features/preview/components/BlockActionsPopover.js +13 -64
  15. package/dist/features/preview/components/CommentHeader.js +122 -0
  16. package/dist/features/preview/components/CommentSidebar.js +29 -0
  17. package/dist/features/preview/components/CommentTargetQuote.js +166 -0
  18. package/dist/features/preview/components/CreatePageModal.js +2 -8
  19. package/dist/features/preview/components/ItemFieldsEditor.js +275 -204
  20. package/dist/features/preview/components/LeftSidebar.js +18 -18
  21. package/dist/features/preview/components/OverlayTracker.js +14 -20
  22. package/dist/features/preview/components/Overlays.js +26 -35
  23. package/dist/features/preview/components/PageEditorSidebar.js +89 -90
  24. package/dist/features/preview/components/PageInfoSidebar.js +126 -157
  25. package/dist/features/preview/components/PagePicker.js +13 -8
  26. package/dist/features/preview/components/PageTree.js +158 -156
  27. package/dist/features/preview/components/PreviewComments.js +56 -0
  28. package/dist/features/preview/components/PreviewPanel.js +122 -78
  29. package/dist/features/preview/components/PreviewToolbar.js +280 -231
  30. package/dist/features/preview/components/PublicationRow.js +4 -11
  31. package/dist/features/preview/components/RightSidebar.js +14 -11
  32. package/dist/features/preview/components/SidebarSection.js +121 -0
  33. package/dist/features/preview/previewCommentsStore.js +115 -0
  34. package/dist/features/preview/previewSelection.js +75 -0
  35. package/dist/features/preview/previewStore.js +19 -39
  36. package/dist/features/provider/AuthenticatedCamoxProvider.js +46 -34
  37. package/dist/features/provider/components/CommandPalette.js +142 -58
  38. package/dist/features/provider/useAdminShortcuts.js +19 -8
  39. package/dist/features/routes/pageRuntime.js +0 -6
  40. package/dist/features/runtime/RuntimeChrome.js +40 -37
  41. package/dist/features/studio/CamoxStudio.js +30 -50
  42. package/dist/features/vite/runtimeDev.js +4 -1
  43. package/dist/features/vite/vite.d.ts +3 -2
  44. package/dist/features/vite/vite.js +9 -5
  45. package/dist/hooks/use-file-upload.js +0 -2
  46. package/dist/studio.css +1 -1
  47. package/package.json +5 -7
  48. package/dist/lib/telemetry-client.js +0 -66
  49. package/dist/lib/telemetry.js +0 -26
@@ -0,0 +1,194 @@
1
+ import { useAuthContext } from "../../../lib/auth.js";
2
+ import { previewStore } from "../previewStore.js";
3
+ import { previewCommentsStore, revealCommentTarget } from "../previewCommentsStore.js";
4
+ import { CommentHeader } from "./CommentHeader.js";
5
+ import { CommentTargetQuote } from "./CommentTargetQuote.js";
6
+ import { SidebarSection, SidebarSectionContent, SidebarSectionHeader } from "./SidebarSection.js";
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { useSelector } from "@xstate/store-react";
10
+ import { Button } from "@camox/ui/button";
11
+ import { ArrowUp, X } from "lucide-react";
12
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@camox/ui/input-group";
13
+
14
+ //#region src/features/preview/components/AttachedComments.tsx
15
+ function resizeComposer(element) {
16
+ element.style.height = "auto";
17
+ element.style.height = `${element.scrollHeight}px`;
18
+ }
19
+ /** Shared comment list and composer for editors and the Feedback sidebar. */
20
+ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPageComments = false }) {
21
+ const { authClient } = useAuthContext();
22
+ const { data: session } = authClient.useSession();
23
+ const { comments, draft, activeId, focusTarget } = useSelector(previewCommentsStore, (state) => state.context);
24
+ const matches = (entry) => entry.pageId === pageId && (allPageComments || entry.target.blockId === blockId && entry.target.itemId === itemId && entry.target.fieldName === fieldName);
25
+ const attached = comments.filter(matches);
26
+ const currentDraft = draft && matches(draft) ? draft : null;
27
+ const selected = attached.find((comment) => comment.id === activeId);
28
+ const textarea = React.useRef(null);
29
+ const activeComment = React.useRef(null);
30
+ const draftTarget = currentDraft?.target;
31
+ const message = currentDraft?.message ?? "";
32
+ React.useLayoutEffect(() => {
33
+ if (textarea.current) resizeComposer(textarea.current);
34
+ }, [message, pageId]);
35
+ React.useEffect(() => {
36
+ const element = textarea.current;
37
+ if (!element) return;
38
+ let width = element.clientWidth;
39
+ const observer = new ResizeObserver(() => {
40
+ if (element.clientWidth === width) return;
41
+ width = element.clientWidth;
42
+ resizeComposer(element);
43
+ });
44
+ observer.observe(element);
45
+ return () => observer.disconnect();
46
+ }, [pageId]);
47
+ const submit = () => {
48
+ if (!message.trim()) return;
49
+ previewCommentsStore.send({
50
+ type: "postComment",
51
+ id: crypto.randomUUID(),
52
+ author: {
53
+ name: session?.user.name || "You",
54
+ image: session?.user.image ?? null
55
+ },
56
+ createdAt: Date.now()
57
+ });
58
+ textarea.current?.focus({ preventScroll: true });
59
+ };
60
+ React.useEffect(() => {
61
+ if (!draftTarget || focusTarget !== draftTarget || !textarea.current) return;
62
+ textarea.current?.scrollIntoView({ block: "nearest" });
63
+ textarea.current?.focus({ preventScroll: true });
64
+ previewCommentsStore.send({ type: "composerFocused" });
65
+ }, [draftTarget, focusTarget]);
66
+ React.useEffect(() => {
67
+ if (!selected) return;
68
+ activeComment.current?.scrollIntoView({ block: "nearest" });
69
+ }, [selected]);
70
+ if (pageId == null) return null;
71
+ return /* @__PURE__ */ jsxs(SidebarSection, {
72
+ "aria-label": allPageComments ? "Feedback" : blockId == null ? "Page comments" : fieldName ? `Comments on ${fieldName}` : itemId == null ? "Block comments" : "Item comments",
73
+ divider: allPageComments ? "none" : "top",
74
+ children: [allPageComments ? /* @__PURE__ */ jsxs("div", {
75
+ className: "flex items-center justify-between gap-2",
76
+ children: [/* @__PURE__ */ jsx("h2", {
77
+ className: "text-base font-semibold",
78
+ children: "Feedback"
79
+ }), /* @__PURE__ */ jsx(Button, {
80
+ type: "button",
81
+ variant: "ghost",
82
+ size: "icon-sm",
83
+ "aria-label": "End comment mode",
84
+ onClick: () => previewStore.send({
85
+ type: "setCommentMode",
86
+ enabled: false
87
+ }),
88
+ children: /* @__PURE__ */ jsx(X, { className: "text-muted-foreground" })
89
+ })]
90
+ }) : /* @__PURE__ */ jsx(SidebarSectionHeader, { children: "Feedback" }), /* @__PURE__ */ jsxs(SidebarSectionContent, { children: [
91
+ allPageComments && attached.length === 0 && /* @__PURE__ */ jsx("p", {
92
+ className: "text-muted-foreground text-sm",
93
+ children: "No feedback yet. Select something on the page to comment on it."
94
+ }),
95
+ attached.map((comment_0) => /* @__PURE__ */ jsxs("div", {
96
+ ref: comment_0.id === activeId ? activeComment : void 0,
97
+ ...allPageComments && {
98
+ role: "button",
99
+ tabIndex: 0,
100
+ className: "hover:bg-card focus-visible:ring-ring rounded-md p-1 outline-none focus-visible:ring-2",
101
+ onClick: () => {
102
+ previewCommentsStore.send({
103
+ type: "selectComment",
104
+ id: comment_0.id
105
+ });
106
+ revealCommentTarget(comment_0.target);
107
+ },
108
+ onKeyDown: (event) => {
109
+ if (event.key !== "Enter" && event.key !== " ") return;
110
+ event.preventDefault();
111
+ event.currentTarget.click();
112
+ }
113
+ },
114
+ children: [/* @__PURE__ */ jsx(CommentHeader, {
115
+ author: comment_0.author,
116
+ createdAt: comment_0.createdAt
117
+ }), /* @__PURE__ */ jsxs("div", {
118
+ className: "pl-8",
119
+ children: [allPageComments && /* @__PURE__ */ jsx(CommentTargetQuote, {
120
+ pageId,
121
+ target: comment_0.target
122
+ }), /* @__PURE__ */ jsx("p", {
123
+ className: "text-sm wrap-break-word whitespace-pre-wrap",
124
+ children: comment_0.message
125
+ })]
126
+ })]
127
+ }, comment_0.id)),
128
+ allPageComments && /* @__PURE__ */ jsx(Button, {
129
+ type: "button",
130
+ variant: "secondary",
131
+ className: "w-full",
132
+ disabled: attached.length === 0,
133
+ children: "Send feedback to agent..."
134
+ }),
135
+ !allPageComments && /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupTextarea, {
136
+ ref: textarea,
137
+ "aria-label": "Comment text",
138
+ placeholder: "Add a comment",
139
+ className: "block field-sizing-fixed min-h-0 flex-none overflow-hidden leading-6",
140
+ rows: 1,
141
+ value: message,
142
+ onKeyDown: (event_0) => {
143
+ if (event_0.key !== "Enter" || event_0.shiftKey || event_0.nativeEvent.isComposing) return;
144
+ event_0.preventDefault();
145
+ event_0.stopPropagation();
146
+ submit();
147
+ },
148
+ onChange: (event_1) => {
149
+ if (!currentDraft) {
150
+ const fieldId = [
151
+ blockId,
152
+ itemId,
153
+ fieldName
154
+ ].filter((part) => part != null).join("__");
155
+ previewCommentsStore.send({
156
+ type: "startComment",
157
+ pageId,
158
+ target: {
159
+ blockId,
160
+ itemId,
161
+ fieldName,
162
+ fieldType,
163
+ selector: blockId == null ? "body" : fieldName != null ? `[data-camox-field-id="${CSS.escape(fieldId)}"]` : itemId != null ? `[data-camox-repeater-item-id="${itemId}"]` : `[data-camox-block-id="${blockId}"]`,
164
+ label: blockId == null ? `Page · ${pageId}` : fieldName != null ? `Field · ${fieldName}` : itemId != null ? `Item · ${itemId}` : `Block · ${blockId}`,
165
+ x: .5,
166
+ y: .5
167
+ }
168
+ });
169
+ }
170
+ previewCommentsStore.send({
171
+ type: "setMessage",
172
+ message: event_1.target.value
173
+ });
174
+ }
175
+ }), /* @__PURE__ */ jsx(InputGroupAddon, {
176
+ align: "block-end",
177
+ className: "justify-end",
178
+ children: /* @__PURE__ */ jsx(InputGroupButton, {
179
+ type: "button",
180
+ size: "icon-sm",
181
+ variant: "default",
182
+ className: "rounded-full",
183
+ "aria-label": "Post comment",
184
+ disabled: !message.trim(),
185
+ onClick: submit,
186
+ children: /* @__PURE__ */ jsx(ArrowUp, { size: 16 })
187
+ })
188
+ })] })
189
+ ] })]
190
+ });
191
+ }
192
+
193
+ //#endregion
194
+ export { AttachedComments };
@@ -3,7 +3,6 @@ import { usePageBlocks } from "../../../lib/normalized-data.js";
3
3
  import { blockMutations, repeatableItemMutations } from "../../../lib/queries.js";
4
4
  import { formatShortcut } from "../../../lib/utils.js";
5
5
  import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
6
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
7
6
  import { previewStore, selectionItemId } from "../previewStore.js";
8
7
  import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
9
8
  import { useUpdateBlockPosition } from "./useUpdateBlockPosition.js";
@@ -13,7 +12,7 @@ import { useMutation } from "@tanstack/react-query";
13
12
  import * as React from "react";
14
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
14
  import { useSelector } from "@xstate/store-react";
16
- import { Copy, Pen, Settings, Trash2 } from "lucide-react";
15
+ import { Copy, Trash2 } from "lucide-react";
17
16
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
18
17
  import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
19
18
  import { toast } from "@camox/ui/toaster";
@@ -22,7 +21,6 @@ import { Command, CommandGroup, CommandInput, CommandItem, CommandList, CommandS
22
21
  //#region src/features/preview/components/BlockActionsPopover.tsx
23
22
  const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "start", isLayoutBlock, layoutPlacement }) => {
24
23
  const [blockToDelete, setBlockToDelete] = React.useState(null);
25
- const camoxApp = useCamoxApp();
26
24
  const page = usePreviewedPage();
27
25
  const { pageBlocks } = usePageBlocks(page);
28
26
  const deleteBlock = useMutation(blockMutations.delete());
@@ -31,10 +29,6 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
31
29
  const handleDeleteBlock = async (block_0) => {
32
30
  try {
33
31
  await deleteBlock.mutateAsync({ id: block_0.id });
34
- trackClientEvent("block_deleted", {
35
- projectId: page?.page.projectId,
36
- blockType: block_0.type
37
- });
38
32
  toast.success(`Deleted "${block_0.summary || block_0.type}" block`);
39
33
  } catch (error) {
40
34
  console.error("Failed to delete block:", error);
@@ -46,10 +40,6 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
46
40
  const handleDuplicateBlock = async (block_1) => {
47
41
  try {
48
42
  await duplicateBlock.mutateAsync({ id: block_1.id });
49
- trackClientEvent("block_duplicated", {
50
- projectId: page?.page.projectId,
51
- blockType: block_1.type
52
- });
53
43
  toast.success(`Duplicated "${block_1.summary}" block`);
54
44
  } catch (error_0) {
55
45
  console.error("Failed to duplicate block:", error_0);
@@ -62,15 +52,13 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
62
52
  const afterPosition = blockIndex > 0 ? pageBlocks[blockIndex - 1].position : "";
63
53
  previewStore.send({
64
54
  type: "openAddBlockSidebar",
65
- afterPosition,
66
- via: "popover-above"
55
+ afterPosition
67
56
  });
68
57
  };
69
58
  const handleAddBlockBelow = (block_3) => {
70
59
  previewStore.send({
71
60
  type: "openAddBlockSidebar",
72
- afterPosition: block_3.position,
73
- via: "popover-below"
61
+ afterPosition: block_3.position
74
62
  });
75
63
  };
76
64
  const getBlocksAbove = (block_4) => {
@@ -114,46 +102,11 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
114
102
  children: /* @__PURE__ */ jsxs(Command, { children: [/* @__PURE__ */ jsx(CommandInput, { placeholder: "Search actions..." }), /* @__PURE__ */ jsxs(CommandList, {
115
103
  className: "max-h-[350px]",
116
104
  children: [
117
- /* @__PURE__ */ jsxs(CommandGroup, { children: [/* @__PURE__ */ jsxs(CommandItem, {
118
- className: "justify-between",
119
- onSelect: () => {
120
- previewStore.send({
121
- type: "openBlockContentSheet",
122
- blockId: block.id
123
- });
124
- onOpenChange(false);
125
- },
126
- children: [/* @__PURE__ */ jsxs("div", {
127
- className: "flex items-center gap-2",
128
- children: [/* @__PURE__ */ jsx(Pen, { className: "h-4 w-4" }), "Edit in form"]
129
- }), /* @__PURE__ */ jsx(CommandShortcut, { children: formatShortcut({
130
- key: "j",
131
- withMeta: true
132
- }) })]
133
- }), !isLayoutBlock && (() => {
134
- const blockDef = camoxApp.getBlockById(block.type);
135
- if (!(blockDef?._internal.settingsSchema?.properties && Object.keys(blockDef._internal.settingsSchema.properties).length > 0)) return null;
136
- return /* @__PURE__ */ jsx(CommandItem, {
137
- className: "justify-between",
138
- onSelect: () => {
139
- previewStore.send({
140
- type: "openBlockContentSheet",
141
- blockId: block.id
142
- });
143
- onOpenChange(false);
144
- },
145
- children: /* @__PURE__ */ jsxs("div", {
146
- className: "flex items-center gap-2",
147
- children: [/* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }), "Open settings"]
148
- })
149
- });
150
- })()] }),
151
- isLayoutBlock && layoutPlacement === "before" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandSeparator, {}), /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(CommandItem, {
105
+ isLayoutBlock && layoutPlacement === "before" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(CommandItem, {
152
106
  onSelect: () => {
153
107
  previewStore.send({
154
108
  type: "openAddBlockSidebar",
155
- afterPosition: "",
156
- via: "layout-popover-below"
109
+ afterPosition: ""
157
110
  });
158
111
  onOpenChange(false);
159
112
  },
@@ -161,14 +114,13 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
161
114
  className: "flex items-center gap-2",
162
115
  children: [/* @__PURE__ */ jsx("span", { className: "w-4" }), "Add block below"]
163
116
  })
164
- }) })] }),
165
- isLayoutBlock && layoutPlacement === "after" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandSeparator, {}), /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(CommandItem, {
117
+ }) }) }),
118
+ isLayoutBlock && layoutPlacement === "after" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(CommandItem, {
166
119
  onSelect: () => {
167
120
  const lastPageBlock = pageBlocks[pageBlocks.length - 1];
168
121
  previewStore.send({
169
122
  type: "openAddBlockSidebar",
170
- afterPosition: lastPageBlock?.position,
171
- via: "layout-popover-above"
123
+ afterPosition: lastPageBlock?.position
172
124
  });
173
125
  onOpenChange(false);
174
126
  },
@@ -176,9 +128,8 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
176
128
  className: "flex items-center gap-2",
177
129
  children: [/* @__PURE__ */ jsx("span", { className: "w-4" }), "Add block above"]
178
130
  })
179
- }) })] }),
131
+ }) }) }),
180
132
  !isLayoutBlock && /* @__PURE__ */ jsxs(Fragment, { children: [
181
- /* @__PURE__ */ jsx(CommandSeparator, {}),
182
133
  /* @__PURE__ */ jsxs(CommandGroup, { children: [/* @__PURE__ */ jsxs(CommandItem, {
183
134
  className: "justify-between",
184
135
  onSelect: () => {
@@ -279,9 +230,9 @@ function isLayoutBlockId(page, blockId) {
279
230
  }
280
231
  function useBlockActionsShortcuts() {
281
232
  const $ = c(20);
282
- if ($[0] !== "2439a21a93e7dc68e5e2199bf795bec817fbc1286e567fde9de806e04fd01b64") {
233
+ if ($[0] !== "a91fc105ded90c35296c42adc5eec1823e26e305818bf9026d22b67a24a3ca04") {
283
234
  for (let $i = 0; $i < 20; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
284
- $[0] = "2439a21a93e7dc68e5e2199bf795bec817fbc1286e567fde9de806e04fd01b64";
235
+ $[0] = "a91fc105ded90c35296c42adc5eec1823e26e305818bf9026d22b67a24a3ca04";
285
236
  }
286
237
  const camoxApp = useCamoxApp();
287
238
  const page = usePreviewedPage();
@@ -465,8 +416,7 @@ function useBlockActionsShortcuts() {
465
416
  if (!block_2) return;
466
417
  previewStore.send({
467
418
  type: "openAddBlockSidebar",
468
- afterPosition: block_2.position,
469
- via: "shortcut-below"
419
+ afterPosition: block_2.position
470
420
  });
471
421
  }
472
422
  },
@@ -488,8 +438,7 @@ function useBlockActionsShortcuts() {
488
438
  const afterPosition_1 = blockIndex > 0 ? pageBlocks[blockIndex - 1].position : "";
489
439
  previewStore.send({
490
440
  type: "openAddBlockSidebar",
491
- afterPosition: afterPosition_1,
492
- via: "shortcut-above"
441
+ afterPosition: afterPosition_1
493
442
  });
494
443
  }
495
444
  }
@@ -0,0 +1,122 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import * as React from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
5
+
6
+ //#region src/features/preview/components/CommentHeader.tsx
7
+ function CommentHeader(t0) {
8
+ const $ = c(27);
9
+ if ($[0] !== "7228323105605d4be0594558d7e4fb389f5d49bc9cb13e6a90c0c2fc6f9ff60f") {
10
+ for (let $i = 0; $i < 27; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
11
+ $[0] = "7228323105605d4be0594558d7e4fb389f5d49bc9cb13e6a90c0c2fc6f9ff60f";
12
+ }
13
+ const { author, createdAt } = t0;
14
+ const [now, setNow] = React.useState(Date.now);
15
+ let t1;
16
+ let t2;
17
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
18
+ t1 = () => {
19
+ const timer = window.setInterval(() => setNow(Date.now()), 6e4);
20
+ return () => window.clearInterval(timer);
21
+ };
22
+ t2 = [];
23
+ $[1] = t1;
24
+ $[2] = t2;
25
+ } else {
26
+ t1 = $[1];
27
+ t2 = $[2];
28
+ }
29
+ React.useEffect(t1, t2);
30
+ const minutes = Math.max(0, Math.floor((now - createdAt) / 6e4));
31
+ const age = minutes < 1 ? "now" : minutes < 60 ? `${minutes}m` : minutes < 1440 ? `${Math.floor(minutes / 60)}h` : `${Math.floor(minutes / 1440)}d`;
32
+ let t3;
33
+ if ($[3] !== author.name) {
34
+ t3 = author.name.trim().split(/\s+/).map(_temp).join("").slice(0, 2).toUpperCase();
35
+ $[3] = author.name;
36
+ $[4] = t3;
37
+ } else t3 = $[4];
38
+ const initials = t3;
39
+ let t4;
40
+ if ($[5] !== author.image || $[6] !== author.name) {
41
+ t4 = author.image && /* @__PURE__ */ jsx(AvatarImage, {
42
+ src: author.image,
43
+ alt: author.name
44
+ });
45
+ $[5] = author.image;
46
+ $[6] = author.name;
47
+ $[7] = t4;
48
+ } else t4 = $[7];
49
+ let t5;
50
+ if ($[8] !== initials) {
51
+ t5 = /* @__PURE__ */ jsx(AvatarFallback, { children: initials });
52
+ $[8] = initials;
53
+ $[9] = t5;
54
+ } else t5 = $[9];
55
+ let t6;
56
+ if ($[10] !== t4 || $[11] !== t5) {
57
+ t6 = /* @__PURE__ */ jsxs(Avatar, {
58
+ size: "sm",
59
+ children: [t4, t5]
60
+ });
61
+ $[10] = t4;
62
+ $[11] = t5;
63
+ $[12] = t6;
64
+ } else t6 = $[12];
65
+ let t7;
66
+ if ($[13] !== author.name) {
67
+ t7 = /* @__PURE__ */ jsx("span", {
68
+ className: "truncate text-sm font-medium",
69
+ title: author.name,
70
+ children: author.name
71
+ });
72
+ $[13] = author.name;
73
+ $[14] = t7;
74
+ } else t7 = $[14];
75
+ let t8;
76
+ if ($[15] !== createdAt) {
77
+ t8 = new Date(createdAt).toISOString();
78
+ $[15] = createdAt;
79
+ $[16] = t8;
80
+ } else t8 = $[16];
81
+ let t9;
82
+ if ($[17] !== createdAt) {
83
+ t9 = new Date(createdAt).toLocaleString();
84
+ $[17] = createdAt;
85
+ $[18] = t9;
86
+ } else t9 = $[18];
87
+ let t10;
88
+ if ($[19] !== age || $[20] !== t8 || $[21] !== t9) {
89
+ t10 = /* @__PURE__ */ jsx("time", {
90
+ className: "text-muted-foreground shrink-0 text-xs",
91
+ dateTime: t8,
92
+ title: t9,
93
+ children: age
94
+ });
95
+ $[19] = age;
96
+ $[20] = t8;
97
+ $[21] = t9;
98
+ $[22] = t10;
99
+ } else t10 = $[22];
100
+ let t11;
101
+ if ($[23] !== t10 || $[24] !== t6 || $[25] !== t7) {
102
+ t11 = /* @__PURE__ */ jsxs("header", {
103
+ className: "mb-2 flex min-w-0 items-center gap-2",
104
+ children: [
105
+ t6,
106
+ t7,
107
+ t10
108
+ ]
109
+ });
110
+ $[23] = t10;
111
+ $[24] = t6;
112
+ $[25] = t7;
113
+ $[26] = t11;
114
+ } else t11 = $[26];
115
+ return t11;
116
+ }
117
+ function _temp(part) {
118
+ return part[0];
119
+ }
120
+
121
+ //#endregion
122
+ export { CommentHeader };
@@ -0,0 +1,29 @@
1
+ import { AttachedComments } from "./AttachedComments.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/features/preview/components/CommentSidebar.tsx
6
+ function CommentSidebar(t0) {
7
+ const $ = c(3);
8
+ if ($[0] !== "d6df60b689386423d40951e6785b3daf7545c90c2ab947b318a4d6c91e5fdf67") {
9
+ for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
10
+ $[0] = "d6df60b689386423d40951e6785b3daf7545c90c2ab947b318a4d6c91e5fdf67";
11
+ }
12
+ const { pageId } = t0;
13
+ let t1;
14
+ if ($[1] !== pageId) {
15
+ t1 = /* @__PURE__ */ jsx("div", {
16
+ className: "min-h-0 flex-1 overflow-auto",
17
+ children: /* @__PURE__ */ jsx(AttachedComments, {
18
+ pageId,
19
+ allPageComments: true
20
+ })
21
+ });
22
+ $[1] = pageId;
23
+ $[2] = t1;
24
+ } else t1 = $[2];
25
+ return t1;
26
+ }
27
+
28
+ //#endregion
29
+ export { CommentSidebar };
@@ -0,0 +1,166 @@
1
+ import { isLexicalState, lexicalStateToPlainText } from "../../../core/lib/lexicalState.js";
2
+ import { blockQueries, pageQueries } from "../../../lib/queries.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { useQuery } from "@tanstack/react-query";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region src/features/preview/components/CommentTargetQuote.tsx
8
+ function Quote(t0) {
9
+ const $ = c(3);
10
+ if ($[0] !== "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92") {
11
+ for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
12
+ $[0] = "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92";
13
+ }
14
+ const { children } = t0;
15
+ let t1;
16
+ if ($[1] !== children) {
17
+ t1 = /* @__PURE__ */ jsx("blockquote", {
18
+ className: "text-muted-foreground my-2 border-l-2 border-yellow-600 pl-2 text-sm wrap-break-word whitespace-pre-wrap",
19
+ children
20
+ });
21
+ $[1] = children;
22
+ $[2] = t1;
23
+ } else t1 = $[2];
24
+ return t1;
25
+ }
26
+ function PageQuote(t0) {
27
+ const $ = c(5);
28
+ if ($[0] !== "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92") {
29
+ for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
30
+ $[0] = "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92";
31
+ }
32
+ const { pageId } = t0;
33
+ let t1;
34
+ if ($[1] !== pageId) {
35
+ t1 = pageQueries.getById(pageId);
36
+ $[1] = pageId;
37
+ $[2] = t1;
38
+ } else t1 = $[2];
39
+ const { data: page, isPending } = useQuery(t1);
40
+ const t2 = page?.nickname || (isPending ? "Loading…" : "Page unavailable");
41
+ let t3;
42
+ if ($[3] !== t2) {
43
+ t3 = /* @__PURE__ */ jsx(Quote, { children: t2 });
44
+ $[3] = t2;
45
+ $[4] = t3;
46
+ } else t3 = $[4];
47
+ return t3;
48
+ }
49
+ function BlockQuote(t0) {
50
+ const $ = c(19);
51
+ if ($[0] !== "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92") {
52
+ for (let $i = 0; $i < 19; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
53
+ $[0] = "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92";
54
+ }
55
+ const { target } = t0;
56
+ let t1;
57
+ if ($[1] !== target.blockId) {
58
+ t1 = blockQueries.get(target.blockId);
59
+ $[1] = target.blockId;
60
+ $[2] = t1;
61
+ } else t1 = $[2];
62
+ const { data: bundle, isPending } = useQuery(t1);
63
+ if (!bundle) {
64
+ const t2 = isPending ? "Loading…" : "Content unavailable";
65
+ let t3;
66
+ if ($[3] !== t2) {
67
+ t3 = /* @__PURE__ */ jsx(Quote, { children: t2 });
68
+ $[3] = t2;
69
+ $[4] = t3;
70
+ } else t3 = $[4];
71
+ return t3;
72
+ }
73
+ let t2;
74
+ if ($[5] !== bundle.block || $[6] !== bundle.repeatableItems || $[7] !== target.itemId) {
75
+ t2 = target.itemId == null ? bundle.block : bundle.repeatableItems.find((item) => item.id === target.itemId);
76
+ $[5] = bundle.block;
77
+ $[6] = bundle.repeatableItems;
78
+ $[7] = target.itemId;
79
+ $[8] = t2;
80
+ } else t2 = $[8];
81
+ const subject = t2;
82
+ if (!subject) {
83
+ let t3;
84
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
85
+ t3 = /* @__PURE__ */ jsx(Quote, { children: "Content unavailable" });
86
+ $[9] = t3;
87
+ } else t3 = $[9];
88
+ return t3;
89
+ }
90
+ if (target.fieldName != null) {
91
+ const value = subject.content[target.fieldName];
92
+ if (target.fieldType === "String" || target.fieldType == null) {
93
+ if (typeof value === "string" || isLexicalState(value)) {
94
+ let t3;
95
+ if ($[10] !== value) {
96
+ t3 = lexicalStateToPlainText(value) || "Empty text";
97
+ $[10] = value;
98
+ $[11] = t3;
99
+ } else t3 = $[11];
100
+ let t4;
101
+ if ($[12] !== t3) {
102
+ t4 = /* @__PURE__ */ jsx(Quote, { children: t3 });
103
+ $[12] = t3;
104
+ $[13] = t4;
105
+ } else t4 = $[13];
106
+ return t4;
107
+ }
108
+ if (value == null && target.fieldType === "String") {
109
+ let t3;
110
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
111
+ t3 = /* @__PURE__ */ jsx(Quote, { children: "Empty text" });
112
+ $[14] = t3;
113
+ } else t3 = $[14];
114
+ return t3;
115
+ }
116
+ }
117
+ if (target.fieldType === "Link" && value && typeof value === "object" && "text" in value && typeof value.text === "string") {
118
+ const t3 = value.text || "Empty link text";
119
+ let t4;
120
+ if ($[15] !== t3) {
121
+ t4 = /* @__PURE__ */ jsx(Quote, { children: t3 });
122
+ $[15] = t3;
123
+ $[16] = t4;
124
+ } else t4 = $[16];
125
+ return t4;
126
+ }
127
+ }
128
+ const t3 = subject.summary || (target.itemId == null ? "Untitled block" : "Untitled item");
129
+ let t4;
130
+ if ($[17] !== t3) {
131
+ t4 = /* @__PURE__ */ jsx(Quote, { children: t3 });
132
+ $[17] = t3;
133
+ $[18] = t4;
134
+ } else t4 = $[18];
135
+ return t4;
136
+ }
137
+ function CommentTargetQuote(t0) {
138
+ const $ = c(5);
139
+ if ($[0] !== "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92") {
140
+ for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
141
+ $[0] = "c7d7da293bb0be577af3f96a804786ef95d893a2ac7e10598c27ec5225cf9e92";
142
+ }
143
+ const { pageId, target } = t0;
144
+ if (target.blockId == null) {
145
+ let t1;
146
+ if ($[1] !== pageId) {
147
+ t1 = /* @__PURE__ */ jsx(PageQuote, { pageId });
148
+ $[1] = pageId;
149
+ $[2] = t1;
150
+ } else t1 = $[2];
151
+ return t1;
152
+ }
153
+ let t1;
154
+ if ($[3] !== target) {
155
+ t1 = /* @__PURE__ */ jsx(BlockQuote, { target: {
156
+ ...target,
157
+ blockId: target.blockId
158
+ } });
159
+ $[3] = target;
160
+ $[4] = t1;
161
+ } else t1 = $[4];
162
+ return t1;
163
+ }
164
+
165
+ //#endregion
166
+ export { CommentTargetQuote };