camox 0.26.0 → 0.27.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/core/components/lexical/InlineLexicalEditor.js +14 -11
- package/dist/core/components/lexical/SidebarLexicalEditor.js +10 -7
- package/dist/features/preview/CamoxPreview.d.ts +1 -0
- package/dist/features/preview/CamoxPreview.js +507 -147
- package/dist/features/preview/components/AssetLightbox.js +1 -1
- package/dist/features/preview/components/BlockActionsPopover.js +1 -1
- package/dist/features/preview/components/CreatePageModal.js +23 -8
- package/dist/features/preview/components/FieldToolbar.js +1 -1
- package/dist/features/preview/components/LinkFieldEditor.js +192 -204
- package/dist/features/preview/components/PageContentSheet.js +1 -1
- package/dist/features/preview/components/PageLocationFieldset.js +3 -4
- package/dist/features/preview/components/{EditPageModal.js → PageMetadataModal.js} +413 -229
- package/dist/features/preview/components/PageNicknameField.js +69 -0
- package/dist/features/preview/components/PagePicker.js +21 -84
- package/dist/features/preview/components/PageStatusBadge.js +97 -0
- package/dist/features/preview/components/PreviewToolbar.js +1 -1
- package/dist/features/preview/components/PublishDialog.js +1 -1
- package/dist/features/preview/components/UnlinkAssetButton.js +1 -1
- package/dist/features/routes/pageRoute.d.ts +3 -1
- package/dist/features/routes/pageRoute.js +34 -11
- package/dist/features/studio/components/EnvironmentMenu.js +1 -1
- package/dist/features/studio/components/ProjectMenu.js +1 -1
- package/dist/features/studio/components/UserButton.js +1 -1
- package/dist/lib/auth.js +43 -15
- package/dist/lib/queries.js +1 -0
- package/dist/lib/utils.js +1 -11
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/skills/camox-cli/SKILL.md +71 -12
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { Input } from "@camox/ui/input";
|
|
3
|
+
import { Label } from "@camox/ui/label";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/features/preview/components/PageNicknameField.tsx
|
|
7
|
+
const PAGE_NICKNAME_MAX_LENGTH = 80;
|
|
8
|
+
const PageNicknameField = (t0) => {
|
|
9
|
+
const $ = c(11);
|
|
10
|
+
if ($[0] !== "162dc2b9b16d70dc0796d14680eaaca4d0c3fb2e642401f82c11c475d9d72a71") {
|
|
11
|
+
for (let $i = 0; $i < 11; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
12
|
+
$[0] = "162dc2b9b16d70dc0796d14680eaaca4d0c3fb2e642401f82c11c475d9d72a71";
|
|
13
|
+
}
|
|
14
|
+
const { value, onChange, autoFocus } = t0;
|
|
15
|
+
let t1;
|
|
16
|
+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
17
|
+
t1 = /* @__PURE__ */ jsx(Label, {
|
|
18
|
+
htmlFor: "pageNickname",
|
|
19
|
+
children: "Nickname"
|
|
20
|
+
});
|
|
21
|
+
$[1] = t1;
|
|
22
|
+
} else t1 = $[1];
|
|
23
|
+
let t2;
|
|
24
|
+
if ($[2] !== onChange) {
|
|
25
|
+
t2 = (e) => onChange(e.target.value);
|
|
26
|
+
$[2] = onChange;
|
|
27
|
+
$[3] = t2;
|
|
28
|
+
} else t2 = $[3];
|
|
29
|
+
let t3;
|
|
30
|
+
if ($[4] !== autoFocus || $[5] !== t2 || $[6] !== value) {
|
|
31
|
+
t3 = /* @__PURE__ */ jsx(Input, {
|
|
32
|
+
id: "pageNickname",
|
|
33
|
+
value,
|
|
34
|
+
onChange: t2,
|
|
35
|
+
placeholder: "e.g. Home, Pricing, About",
|
|
36
|
+
maxLength: 80,
|
|
37
|
+
autoFocus
|
|
38
|
+
});
|
|
39
|
+
$[4] = autoFocus;
|
|
40
|
+
$[5] = t2;
|
|
41
|
+
$[6] = value;
|
|
42
|
+
$[7] = t3;
|
|
43
|
+
} else t3 = $[7];
|
|
44
|
+
let t4;
|
|
45
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
46
|
+
t4 = /* @__PURE__ */ jsx("p", {
|
|
47
|
+
className: "text-muted-foreground text-xs",
|
|
48
|
+
children: "A short internal name used in Camox Studio. It does not affect the public page or SEO."
|
|
49
|
+
});
|
|
50
|
+
$[8] = t4;
|
|
51
|
+
} else t4 = $[8];
|
|
52
|
+
let t5;
|
|
53
|
+
if ($[9] !== t3) {
|
|
54
|
+
t5 = /* @__PURE__ */ jsxs("div", {
|
|
55
|
+
className: "space-y-2",
|
|
56
|
+
children: [
|
|
57
|
+
t1,
|
|
58
|
+
t3,
|
|
59
|
+
t4
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
$[9] = t3;
|
|
63
|
+
$[10] = t5;
|
|
64
|
+
} else t5 = $[10];
|
|
65
|
+
return t5;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
export { PageNicknameField };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { previewStore } from "../previewStore.js";
|
|
2
2
|
import { useProjectSlug } from "../../../lib/auth.js";
|
|
3
3
|
import { pageMutations, pageQueries, projectQueries } from "../../../lib/queries.js";
|
|
4
|
-
import { cn
|
|
5
|
-
import {
|
|
4
|
+
import { cn } from "../../../lib/utils.js";
|
|
5
|
+
import { PageStatusBadge } from "./PageStatusBadge.js";
|
|
6
6
|
import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
|
|
7
7
|
import { toast } from "@camox/ui/toaster";
|
|
8
8
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
@@ -10,87 +10,13 @@ import { useLocation, useNavigate } from "@tanstack/react-router";
|
|
|
10
10
|
import { useSelector } from "@xstate/store-react";
|
|
11
11
|
import * as React from "react";
|
|
12
12
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
13
14
|
import { Button } from "@camox/ui/button";
|
|
14
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
|
|
15
15
|
import { Check, ChevronsUpDown, Pencil, Plus, Trash2 } from "lucide-react";
|
|
16
|
-
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
17
|
-
import { Badge } from "@camox/ui/badge";
|
|
18
16
|
import { Skeleton } from "@camox/ui/skeleton";
|
|
19
17
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from "@camox/ui/command";
|
|
20
18
|
|
|
21
19
|
//#region src/features/preview/components/PagePicker.tsx
|
|
22
|
-
const StatusBadge = (t0) => {
|
|
23
|
-
const $ = c(9);
|
|
24
|
-
if ($[0] !== "b1d62d8bb85e72a5793231a5fd9f232264a809f20c92f8c88b773f51f15623ec") {
|
|
25
|
-
for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
26
|
-
$[0] = "b1d62d8bb85e72a5793231a5fd9f232264a809f20c92f8c88b773f51f15623ec";
|
|
27
|
-
}
|
|
28
|
-
const { page } = t0;
|
|
29
|
-
if (page.status === "draft") {
|
|
30
|
-
let t1;
|
|
31
|
-
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
32
|
-
t1 = /* @__PURE__ */ jsx(Badge, {
|
|
33
|
-
variant: "outline",
|
|
34
|
-
className: "h-4 shrink-0 px-1.5",
|
|
35
|
-
children: "Draft"
|
|
36
|
-
});
|
|
37
|
-
$[1] = t1;
|
|
38
|
-
} else t1 = $[1];
|
|
39
|
-
return t1;
|
|
40
|
-
}
|
|
41
|
-
if (page.status === "published") {
|
|
42
|
-
let t1;
|
|
43
|
-
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
44
|
-
t1 = /* @__PURE__ */ jsx(Badge, {
|
|
45
|
-
variant: "secondary",
|
|
46
|
-
className: "h-4 shrink-0 px-1.5",
|
|
47
|
-
children: "Published"
|
|
48
|
-
});
|
|
49
|
-
$[2] = t1;
|
|
50
|
-
} else t1 = $[2];
|
|
51
|
-
return t1;
|
|
52
|
-
}
|
|
53
|
-
const reason = page.modifiedReason;
|
|
54
|
-
let t1;
|
|
55
|
-
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
|
56
|
-
t1 = /* @__PURE__ */ jsx(Badge, {
|
|
57
|
-
variant: "default",
|
|
58
|
-
className: "h-4 shrink-0 px-1.5",
|
|
59
|
-
children: "Modified"
|
|
60
|
-
});
|
|
61
|
-
$[3] = t1;
|
|
62
|
-
} else t1 = $[3];
|
|
63
|
-
const badge = t1;
|
|
64
|
-
if (reason && (reason.reason === "layout" || reason.reason === "both")) {
|
|
65
|
-
const pluralized = reason.affectedPagesCount === 1 ? "page" : "pages";
|
|
66
|
-
const headline = reason.reason === "layout" ? `Layout ${reason.layoutHandle} has unpublished changes` : `This page and layout ${reason.layoutHandle} both have unpublished changes`;
|
|
67
|
-
let t2;
|
|
68
|
-
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
|
69
|
-
t2 = /* @__PURE__ */ jsx(TooltipTrigger, {
|
|
70
|
-
render: /* @__PURE__ */ jsx("span", { className: "shrink-0" }),
|
|
71
|
-
children: badge
|
|
72
|
-
});
|
|
73
|
-
$[4] = t2;
|
|
74
|
-
} else t2 = $[4];
|
|
75
|
-
let t3;
|
|
76
|
-
if ($[5] !== headline || $[6] !== pluralized || $[7] !== reason.affectedPagesCount) {
|
|
77
|
-
t3 = /* @__PURE__ */ jsxs(Tooltip, { children: [t2, /* @__PURE__ */ jsxs(TooltipContent, { children: [
|
|
78
|
-
headline,
|
|
79
|
-
" (affects ",
|
|
80
|
-
reason.affectedPagesCount,
|
|
81
|
-
" ",
|
|
82
|
-
pluralized,
|
|
83
|
-
")"
|
|
84
|
-
] })] });
|
|
85
|
-
$[5] = headline;
|
|
86
|
-
$[6] = pluralized;
|
|
87
|
-
$[7] = reason.affectedPagesCount;
|
|
88
|
-
$[8] = t3;
|
|
89
|
-
} else t3 = $[8];
|
|
90
|
-
return t3;
|
|
91
|
-
}
|
|
92
|
-
return badge;
|
|
93
|
-
};
|
|
94
20
|
const CREATE_PAGE_VALUE = "__create_page__";
|
|
95
21
|
const PagePicker = () => {
|
|
96
22
|
const [open, setOpen] = React.useState(false);
|
|
@@ -110,7 +36,7 @@ const PagePicker = () => {
|
|
|
110
36
|
setOpen(false);
|
|
111
37
|
};
|
|
112
38
|
const handleDeletePage = async (page) => {
|
|
113
|
-
const displayName = page.
|
|
39
|
+
const displayName = page.nickname;
|
|
114
40
|
try {
|
|
115
41
|
await deletePage.mutateAsync({ id: page.id });
|
|
116
42
|
toast.success(`Deleted ${displayName} page`);
|
|
@@ -145,9 +71,16 @@ const PagePicker = () => {
|
|
|
145
71
|
role: "combobox",
|
|
146
72
|
className: "min-w-0 flex-1 justify-between"
|
|
147
73
|
}),
|
|
148
|
-
children: [/* @__PURE__ */
|
|
149
|
-
className: "
|
|
150
|
-
children:
|
|
74
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
75
|
+
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
76
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
77
|
+
className: "truncate",
|
|
78
|
+
children: currentPage.nickname
|
|
79
|
+
}), /* @__PURE__ */ jsx(PageStatusBadge, {
|
|
80
|
+
size: "sm",
|
|
81
|
+
status: currentPage.status,
|
|
82
|
+
modifiedReason: currentPage.modifiedReason
|
|
83
|
+
})]
|
|
151
84
|
}), /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
|
|
152
85
|
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
153
86
|
className: "flex h-[300px] w-[400px] flex-col p-0",
|
|
@@ -187,13 +120,17 @@ const PagePicker = () => {
|
|
|
187
120
|
className: "flex min-w-0 flex-col",
|
|
188
121
|
children: [/* @__PURE__ */ jsx("p", {
|
|
189
122
|
className: "truncate",
|
|
190
|
-
children: page_1.
|
|
123
|
+
children: page_1.nickname
|
|
191
124
|
}), /* @__PURE__ */ jsxs("div", {
|
|
192
125
|
className: "flex min-w-0 items-center gap-1.5",
|
|
193
126
|
children: [/* @__PURE__ */ jsx("p", {
|
|
194
127
|
className: "text-muted-foreground truncate font-mono text-xs",
|
|
195
128
|
children: page_1.fullPath
|
|
196
|
-
}), /* @__PURE__ */ jsx(
|
|
129
|
+
}), /* @__PURE__ */ jsx(PageStatusBadge, {
|
|
130
|
+
size: "sm",
|
|
131
|
+
status: page_1.status,
|
|
132
|
+
modifiedReason: page_1.modifiedReason
|
|
133
|
+
})]
|
|
197
134
|
})]
|
|
198
135
|
})]
|
|
199
136
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -258,7 +195,7 @@ const PagePicker = () => {
|
|
|
258
195
|
children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: "Delete page" }), /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [
|
|
259
196
|
"Are you sure you want to delete",
|
|
260
197
|
" ",
|
|
261
|
-
/* @__PURE__ */ jsx("strong", { children: pageToDelete ? pageToDelete.
|
|
198
|
+
/* @__PURE__ */ jsx("strong", { children: pageToDelete ? pageToDelete.nickname : "" }),
|
|
262
199
|
"? This action cannot be undone."
|
|
263
200
|
] })] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
|
|
264
201
|
variant: "outline",
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
|
|
6
|
+
import { Badge } from "@camox/ui/badge";
|
|
7
|
+
|
|
8
|
+
//#region src/features/preview/components/PageStatusBadge.tsx
|
|
9
|
+
const statusStyles = {
|
|
10
|
+
draft: {
|
|
11
|
+
className: "bg-blue-500/10 text-blue-700 dark:bg-blue-500/20 dark:text-blue-400",
|
|
12
|
+
label: "Draft"
|
|
13
|
+
},
|
|
14
|
+
published: {
|
|
15
|
+
className: "bg-primary/10 text-primary dark:bg-primary/20",
|
|
16
|
+
label: "Published"
|
|
17
|
+
},
|
|
18
|
+
modified: {
|
|
19
|
+
className: "bg-purple-500/10 text-purple-700 dark:bg-purple-500/20 dark:text-purple-400",
|
|
20
|
+
label: "Modified"
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const PageStatusBadge = (t0) => {
|
|
24
|
+
const $ = c(18);
|
|
25
|
+
if ($[0] !== "9168a870b9514df0e89a2bb3f4bf1b341d85dcccf45743f1d6f9b68bbb30a7d4") {
|
|
26
|
+
for (let $i = 0; $i < 18; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
27
|
+
$[0] = "9168a870b9514df0e89a2bb3f4bf1b341d85dcccf45743f1d6f9b68bbb30a7d4";
|
|
28
|
+
}
|
|
29
|
+
const { status, modifiedReason, size: t1, className } = t0;
|
|
30
|
+
const size = t1 === void 0 ? "default" : t1;
|
|
31
|
+
const { className: statusClassName, label } = statusStyles[status];
|
|
32
|
+
let t2;
|
|
33
|
+
if ($[1] !== className || $[2] !== statusClassName) {
|
|
34
|
+
t2 = cn(statusClassName, className);
|
|
35
|
+
$[1] = className;
|
|
36
|
+
$[2] = statusClassName;
|
|
37
|
+
$[3] = t2;
|
|
38
|
+
} else t2 = $[3];
|
|
39
|
+
let t3;
|
|
40
|
+
if ($[4] !== label || $[5] !== size || $[6] !== t2) {
|
|
41
|
+
t3 = /* @__PURE__ */ jsx(Badge, {
|
|
42
|
+
size,
|
|
43
|
+
className: t2,
|
|
44
|
+
children: label
|
|
45
|
+
});
|
|
46
|
+
$[4] = label;
|
|
47
|
+
$[5] = size;
|
|
48
|
+
$[6] = t2;
|
|
49
|
+
$[7] = t3;
|
|
50
|
+
} else t3 = $[7];
|
|
51
|
+
const badge = t3;
|
|
52
|
+
if (status === "modified" && modifiedReason && (modifiedReason.reason === "layout" || modifiedReason.reason === "both")) {
|
|
53
|
+
const pluralized = modifiedReason.affectedPagesCount === 1 ? "page" : "pages";
|
|
54
|
+
const headline = modifiedReason.reason === "layout" ? `Layout ${modifiedReason.layoutHandle} has unpublished changes` : `This page and layout ${modifiedReason.layoutHandle} both have unpublished changes`;
|
|
55
|
+
let t4;
|
|
56
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
57
|
+
t4 = /* @__PURE__ */ jsx("span", { className: "shrink-0" });
|
|
58
|
+
$[8] = t4;
|
|
59
|
+
} else t4 = $[8];
|
|
60
|
+
let t5;
|
|
61
|
+
if ($[9] !== badge) {
|
|
62
|
+
t5 = /* @__PURE__ */ jsx(TooltipTrigger, {
|
|
63
|
+
render: t4,
|
|
64
|
+
children: badge
|
|
65
|
+
});
|
|
66
|
+
$[9] = badge;
|
|
67
|
+
$[10] = t5;
|
|
68
|
+
} else t5 = $[10];
|
|
69
|
+
let t6;
|
|
70
|
+
if ($[11] !== headline || $[12] !== modifiedReason.affectedPagesCount || $[13] !== pluralized) {
|
|
71
|
+
t6 = /* @__PURE__ */ jsxs(TooltipContent, { children: [
|
|
72
|
+
headline,
|
|
73
|
+
" (affects ",
|
|
74
|
+
modifiedReason.affectedPagesCount,
|
|
75
|
+
" ",
|
|
76
|
+
pluralized,
|
|
77
|
+
")"
|
|
78
|
+
] });
|
|
79
|
+
$[11] = headline;
|
|
80
|
+
$[12] = modifiedReason.affectedPagesCount;
|
|
81
|
+
$[13] = pluralized;
|
|
82
|
+
$[14] = t6;
|
|
83
|
+
} else t6 = $[14];
|
|
84
|
+
let t7;
|
|
85
|
+
if ($[15] !== t5 || $[16] !== t6) {
|
|
86
|
+
t7 = /* @__PURE__ */ jsxs(Tooltip, { children: [t5, t6] });
|
|
87
|
+
$[15] = t5;
|
|
88
|
+
$[16] = t6;
|
|
89
|
+
$[17] = t7;
|
|
90
|
+
} else t7 = $[17];
|
|
91
|
+
return t7;
|
|
92
|
+
}
|
|
93
|
+
return badge;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { PageStatusBadge };
|
|
@@ -6,9 +6,9 @@ import { Kbd } from "@camox/ui/kbd";
|
|
|
6
6
|
import { useSelector } from "@xstate/store-react";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Button } from "@camox/ui/button";
|
|
9
|
+
import { ButtonGroup } from "@camox/ui/button-group";
|
|
9
10
|
import * as Tooltip$1 from "@camox/ui/tooltip";
|
|
10
11
|
import { Lock, MonitorPlay, PanelRight, TabletSmartphone } from "lucide-react";
|
|
11
|
-
import { ButtonGroup } from "@camox/ui/button-group";
|
|
12
12
|
import { FloatingToolbar } from "@camox/ui/floating-toolbar";
|
|
13
13
|
import { Toggle } from "@camox/ui/toggle";
|
|
14
14
|
|
|
@@ -5,8 +5,8 @@ import { toast } from "@camox/ui/toaster";
|
|
|
5
5
|
import { useMutation } from "@tanstack/react-query";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { Switch } from "@camox/ui/switch";
|
|
9
8
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
9
|
+
import { Switch } from "@camox/ui/switch";
|
|
10
10
|
|
|
11
11
|
//#region src/features/preview/components/PublishDialog.tsx
|
|
12
12
|
/**
|
|
@@ -4,10 +4,10 @@ import { c } from "react/compiler-runtime";
|
|
|
4
4
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { AlertDialog, AlertDialogAction, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
7
8
|
import { Button } from "@camox/ui/button";
|
|
8
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
|
|
9
10
|
import { X } from "lucide-react";
|
|
10
|
-
import { AlertDialog, AlertDialogAction, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
11
11
|
|
|
12
12
|
//#region src/features/preview/components/UnlinkAssetButton.tsx
|
|
13
13
|
const UnlinkAssetButton = (t0) => {
|
|
@@ -8,6 +8,7 @@ import * as _$_tanstack_react_start0 from "@tanstack/react-start";
|
|
|
8
8
|
declare function parseQuality(part: string): number;
|
|
9
9
|
declare function prefersMarkdown(accept: string): boolean;
|
|
10
10
|
declare const getOrigin: _$_tanstack_react_start0.OptionalFetcher<undefined, undefined, Promise<string>>;
|
|
11
|
+
declare const getServerLoaderAuthCookieHeader: _$_tanstack_react_start0.OptionalFetcher<undefined, undefined, Promise<string>>;
|
|
11
12
|
declare function createMarkdownMiddleware(apiUrl: string, projectSlug: string, environmentName?: string): _$_tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>;
|
|
12
13
|
declare function createPageLoader(apiUrl: string, projectSlug: string, environmentName?: string): ({
|
|
13
14
|
location,
|
|
@@ -36,6 +37,7 @@ declare function createPageLoader(apiUrl: string, projectSlug: string, environme
|
|
|
36
37
|
layoutId: number;
|
|
37
38
|
livePublishedCheckpointId: number | null;
|
|
38
39
|
contentUpdatedAt: number;
|
|
40
|
+
nickname: string;
|
|
39
41
|
metaTitle: string | null;
|
|
40
42
|
metaDescription: string | null;
|
|
41
43
|
aiSeoEnabled: boolean | null;
|
|
@@ -77,4 +79,4 @@ declare function createPageHead(camoxApp: CamoxApp): ({
|
|
|
77
79
|
};
|
|
78
80
|
declare const PageRouteComponent: () => _$react_jsx_runtime0.JSX.Element;
|
|
79
81
|
//#endregion
|
|
80
|
-
export { PageRouteComponent, createMarkdownMiddleware, createPageHead, createPageLoader, getOrigin, parseQuality, prefersMarkdown };
|
|
82
|
+
export { PageRouteComponent, createMarkdownMiddleware, createPageHead, createPageLoader, getOrigin, getServerLoaderAuthCookieHeader, parseQuality, prefersMarkdown };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAuthCookieHeader, getServerAuthCookieHeader } from "../../lib/auth.js";
|
|
1
2
|
import { seedBlockCaches } from "../../lib/normalized-data.js";
|
|
2
3
|
import { CamoxPreview, PageContent } from "../preview/CamoxPreview.js";
|
|
3
4
|
import { trackEvent } from "../../lib/telemetry.js";
|
|
@@ -25,18 +26,25 @@ function prefersMarkdown(accept) {
|
|
|
25
26
|
}
|
|
26
27
|
return markdownQ > 0 && markdownQ >= htmlQ;
|
|
27
28
|
}
|
|
28
|
-
function createServerApiClient(apiUrl, environmentName) {
|
|
29
|
+
function createServerApiClient(apiUrl, environmentName, options) {
|
|
29
30
|
const headers = {};
|
|
30
31
|
if (environmentName) headers["x-environment-name"] = environmentName;
|
|
31
32
|
return createORPCClient(new RPCLink({
|
|
32
33
|
url: `${apiUrl}/rpc`,
|
|
33
|
-
headers
|
|
34
|
+
headers,
|
|
35
|
+
fetch: (request, init) => {
|
|
36
|
+
if (options?.authCookieHeader && request instanceof Request) request.headers.set("Better-Auth-Cookie", options.authCookieHeader);
|
|
37
|
+
return fetch(request, init);
|
|
38
|
+
}
|
|
34
39
|
}));
|
|
35
40
|
}
|
|
36
41
|
const getOrigin = createServerFn({ method: "GET" }).handler(async () => {
|
|
37
42
|
const request = getRequest();
|
|
38
43
|
return new URL(request.url).origin;
|
|
39
44
|
});
|
|
45
|
+
const getServerLoaderAuthCookieHeader = createServerFn({ method: "GET" }).handler(async () => {
|
|
46
|
+
return getServerAuthCookieHeader(getRequest().headers);
|
|
47
|
+
});
|
|
40
48
|
function createMarkdownMiddleware(apiUrl, projectSlug, environmentName) {
|
|
41
49
|
const api = createServerApiClient(apiUrl, environmentName);
|
|
42
50
|
return createMiddleware().server(async ({ next, request }) => {
|
|
@@ -65,20 +73,35 @@ function createMarkdownMiddleware(apiUrl, projectSlug, environmentName) {
|
|
|
65
73
|
});
|
|
66
74
|
}
|
|
67
75
|
function createPageLoader(apiUrl, projectSlug, environmentName) {
|
|
68
|
-
const serverApi = createServerApiClient(apiUrl, environmentName);
|
|
69
76
|
return async ({ location, context }) => {
|
|
70
77
|
try {
|
|
78
|
+
const authCookieHeader = typeof window !== "undefined" ? getAuthCookieHeader() : await getServerLoaderAuthCookieHeader();
|
|
79
|
+
const source = authCookieHeader ? "draft" : "live";
|
|
80
|
+
const serverApi = createServerApiClient(apiUrl, environmentName, { authCookieHeader });
|
|
71
81
|
const [page, origin] = await Promise.all([context.queryClient.ensureQueryData({
|
|
72
|
-
queryKey: queryKeys.pages.getByPath(location.pathname,
|
|
82
|
+
queryKey: queryKeys.pages.getByPath(location.pathname, source),
|
|
73
83
|
queryFn: async () => {
|
|
74
84
|
const [data, pagesList] = await Promise.all([serverApi.pages.getByPath({
|
|
75
85
|
path: location.pathname,
|
|
76
86
|
projectSlug,
|
|
77
|
-
source
|
|
87
|
+
source
|
|
78
88
|
}), serverApi.pages.listBySlug({ projectSlug }).catch(() => null)]);
|
|
79
|
-
seedBlockCaches(context.queryClient, data,
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
seedBlockCaches(context.queryClient, data, source);
|
|
90
|
+
context.queryClient.setQueryData(queryKeys.pages.getByPath(location.pathname, source), {
|
|
91
|
+
page: data.page,
|
|
92
|
+
layout: data.layout,
|
|
93
|
+
projectName: data.projectName,
|
|
94
|
+
project: data.project
|
|
95
|
+
});
|
|
96
|
+
if (source === "live") {
|
|
97
|
+
seedBlockCaches(context.queryClient, data, "draft");
|
|
98
|
+
context.queryClient.setQueryData(queryKeys.pages.getByPath(location.pathname, "draft"), {
|
|
99
|
+
page: data.page,
|
|
100
|
+
layout: data.layout,
|
|
101
|
+
projectName: data.projectName,
|
|
102
|
+
project: data.project
|
|
103
|
+
});
|
|
104
|
+
}
|
|
82
105
|
if (pagesList) context.queryClient.setQueryData(queryKeys.pages.list, pagesList);
|
|
83
106
|
return {
|
|
84
107
|
page: data.page,
|
|
@@ -156,9 +179,9 @@ function createPageHead(camoxApp) {
|
|
|
156
179
|
}
|
|
157
180
|
const PageRouteComponent = () => {
|
|
158
181
|
const $ = c(2);
|
|
159
|
-
if ($[0] !== "
|
|
182
|
+
if ($[0] !== "c7f5f058711714d2b4ce2a6ee4fb3259e56b272fafb972520b82049c0f52d9df") {
|
|
160
183
|
for (let $i = 0; $i < 2; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
161
|
-
$[0] = "
|
|
184
|
+
$[0] = "c7f5f058711714d2b4ce2a6ee4fb3259e56b272fafb972520b82049c0f52d9df";
|
|
162
185
|
}
|
|
163
186
|
let t0;
|
|
164
187
|
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
@@ -169,4 +192,4 @@ const PageRouteComponent = () => {
|
|
|
169
192
|
};
|
|
170
193
|
|
|
171
194
|
//#endregion
|
|
172
|
-
export { PageRouteComponent, createMarkdownMiddleware, createPageHead, createPageLoader, getOrigin, parseQuality, prefersMarkdown };
|
|
195
|
+
export { PageRouteComponent, createMarkdownMiddleware, createPageHead, createPageLoader, getOrigin, getServerLoaderAuthCookieHeader, parseQuality, prefersMarkdown };
|
|
@@ -6,9 +6,9 @@ import { toast } from "@camox/ui/toaster";
|
|
|
6
6
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
9
10
|
import { Button } from "@camox/ui/button";
|
|
10
11
|
import { ChevronDown, Download, Upload } from "lucide-react";
|
|
11
|
-
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
|
|
12
12
|
import { Badge } from "@camox/ui/badge";
|
|
13
13
|
import { Separator } from "@camox/ui/separator";
|
|
14
14
|
import { Spinner } from "@camox/ui/spinner";
|
|
@@ -6,8 +6,8 @@ import { Link } from "@tanstack/react-router";
|
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Button } from "@camox/ui/button";
|
|
9
|
-
import { ChevronDown, Globe, Info, Settings, Users } from "lucide-react";
|
|
10
9
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
|
|
10
|
+
import { ChevronDown, Globe, Info, Settings, Users } from "lucide-react";
|
|
11
11
|
import { Skeleton } from "@camox/ui/skeleton";
|
|
12
12
|
|
|
13
13
|
//#region src/features/studio/components/ProjectMenu.tsx
|
|
@@ -3,8 +3,8 @@ import { useApplyTheme } from "../useTheme.js";
|
|
|
3
3
|
import { c } from "react/compiler-runtime";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Button } from "@camox/ui/button";
|
|
6
|
-
import { Check, LogOut, Monitor, Moon, Settings, Sun, User } from "lucide-react";
|
|
7
6
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
|
|
7
|
+
import { Check, LogOut, Monitor, Moon, Settings, Sun, User } from "lucide-react";
|
|
8
8
|
import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
|
|
9
9
|
|
|
10
10
|
//#region src/features/studio/components/UserButton.tsx
|
package/dist/lib/auth.js
CHANGED
|
@@ -5,6 +5,26 @@ import { oneTimeTokenClient, organizationClient } from "better-auth/client/plugi
|
|
|
5
5
|
import { createAuthClient } from "better-auth/react";
|
|
6
6
|
|
|
7
7
|
//#region src/lib/auth.ts
|
|
8
|
+
const SERVER_AUTH_COOKIE_NAME = "camox_auth_cookie";
|
|
9
|
+
function writeServerAuthCookie(cookie) {
|
|
10
|
+
if (typeof document === "undefined") return;
|
|
11
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
12
|
+
if (!cookie) {
|
|
13
|
+
document.cookie = `${SERVER_AUTH_COOKIE_NAME}=; Path=/; SameSite=Lax; Max-Age=0${secure}`;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
document.cookie = `${SERVER_AUTH_COOKIE_NAME}=${encodeURIComponent(cookie)}; Path=/; SameSite=Lax; Max-Age=2592000${secure}`;
|
|
17
|
+
}
|
|
18
|
+
function getServerAuthCookieHeader(headers) {
|
|
19
|
+
const authCookie = (headers.get("Cookie") ?? headers.get("cookie") ?? "").split(";").map((part) => part.trim()).find((part) => part.startsWith(`${SERVER_AUTH_COOKIE_NAME}=`));
|
|
20
|
+
if (!authCookie) return "";
|
|
21
|
+
const value = authCookie.slice(18);
|
|
22
|
+
try {
|
|
23
|
+
return decodeURIComponent(value);
|
|
24
|
+
} catch {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
8
28
|
function parseSetCookieHeader(header) {
|
|
9
29
|
const cookieMap = /* @__PURE__ */ new Map();
|
|
10
30
|
header.split(", ").forEach((cookie) => {
|
|
@@ -59,7 +79,9 @@ function getCookie(cookie) {
|
|
|
59
79
|
*/
|
|
60
80
|
function getAuthCookieHeader() {
|
|
61
81
|
if (typeof window === "undefined") return "";
|
|
62
|
-
|
|
82
|
+
const cookie = getCookie(localStorage.getItem("better-auth_cookie") || "{}");
|
|
83
|
+
writeServerAuthCookie(cookie);
|
|
84
|
+
return cookie;
|
|
63
85
|
}
|
|
64
86
|
function crossDomainClient(opts = {}) {
|
|
65
87
|
let store = null;
|
|
@@ -101,6 +123,7 @@ function crossDomainClient(opts = {}) {
|
|
|
101
123
|
const prevCookie = storage.getItem(cookieName);
|
|
102
124
|
const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? void 0);
|
|
103
125
|
await storage.setItem(cookieName, toSetCookie);
|
|
126
|
+
writeServerAuthCookie(getCookie(toSetCookie));
|
|
104
127
|
if (setCookie.includes(".session_token=")) {
|
|
105
128
|
const parsed = parseSetCookieHeader(setCookie);
|
|
106
129
|
let prevParsed = {};
|
|
@@ -114,7 +137,10 @@ function crossDomainClient(opts = {}) {
|
|
|
114
137
|
if (context.request.url.toString().includes("/get-session") && !opts?.disableCache) {
|
|
115
138
|
const data = context.data;
|
|
116
139
|
storage.setItem(localCacheName, JSON.stringify(data));
|
|
117
|
-
if (data === null)
|
|
140
|
+
if (data === null) {
|
|
141
|
+
storage.setItem(cookieName, "{}");
|
|
142
|
+
writeServerAuthCookie("");
|
|
143
|
+
} else writeServerAuthCookie(getCookie(storage.getItem(cookieName) || "{}"));
|
|
118
144
|
}
|
|
119
145
|
} },
|
|
120
146
|
async init(url, options) {
|
|
@@ -124,6 +150,7 @@ function crossDomainClient(opts = {}) {
|
|
|
124
150
|
};
|
|
125
151
|
options = options || {};
|
|
126
152
|
const cookie = getCookie(storage.getItem(cookieName) || "{}");
|
|
153
|
+
writeServerAuthCookie(cookie);
|
|
127
154
|
options.credentials = "omit";
|
|
128
155
|
options.headers = {
|
|
129
156
|
...options.headers,
|
|
@@ -131,6 +158,7 @@ function crossDomainClient(opts = {}) {
|
|
|
131
158
|
};
|
|
132
159
|
if (url.includes("/sign-out")) {
|
|
133
160
|
await storage.setItem(cookieName, "{}");
|
|
161
|
+
writeServerAuthCookie("");
|
|
134
162
|
store?.atoms.session?.set({
|
|
135
163
|
data: null,
|
|
136
164
|
error: null,
|
|
@@ -164,9 +192,9 @@ function createCamoxAuthClient(apiUrl) {
|
|
|
164
192
|
*/
|
|
165
193
|
function useProcessOtt(authClient) {
|
|
166
194
|
const $ = c(5);
|
|
167
|
-
if ($[0] !== "
|
|
195
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
168
196
|
for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
169
|
-
$[0] = "
|
|
197
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
170
198
|
}
|
|
171
199
|
const [ready, setReady] = React.useState(_temp);
|
|
172
200
|
let t0;
|
|
@@ -209,9 +237,9 @@ function _temp() {
|
|
|
209
237
|
const AuthContext = React.createContext(null);
|
|
210
238
|
function useAuthContext() {
|
|
211
239
|
const $ = c(1);
|
|
212
|
-
if ($[0] !== "
|
|
240
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
213
241
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
214
|
-
$[0] = "
|
|
242
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
215
243
|
}
|
|
216
244
|
const ctx = React.useContext(AuthContext);
|
|
217
245
|
if (!ctx) throw new Error("Missing CamoxProvider");
|
|
@@ -219,9 +247,9 @@ function useAuthContext() {
|
|
|
219
247
|
}
|
|
220
248
|
function useProjectSlug() {
|
|
221
249
|
const $ = c(1);
|
|
222
|
-
if ($[0] !== "
|
|
250
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
223
251
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
224
|
-
$[0] = "
|
|
252
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
225
253
|
}
|
|
226
254
|
return useAuthContext().projectSlug;
|
|
227
255
|
}
|
|
@@ -235,18 +263,18 @@ function useAuthState() {
|
|
|
235
263
|
}
|
|
236
264
|
function useIsAuthenticated() {
|
|
237
265
|
const $ = c(1);
|
|
238
|
-
if ($[0] !== "
|
|
266
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
239
267
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
240
|
-
$[0] = "
|
|
268
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
241
269
|
}
|
|
242
270
|
const { isAuthenticated } = useAuthState();
|
|
243
271
|
return isAuthenticated;
|
|
244
272
|
}
|
|
245
273
|
function useSignInRedirect() {
|
|
246
274
|
const $ = c(3);
|
|
247
|
-
if ($[0] !== "
|
|
275
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
248
276
|
for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
249
|
-
$[0] = "
|
|
277
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
250
278
|
}
|
|
251
279
|
const { authenticationUrl } = useAuthContext();
|
|
252
280
|
let t0;
|
|
@@ -267,9 +295,9 @@ function useSignInRedirect() {
|
|
|
267
295
|
*/
|
|
268
296
|
function useAuthActions() {
|
|
269
297
|
const $ = c(5);
|
|
270
|
-
if ($[0] !== "
|
|
298
|
+
if ($[0] !== "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a") {
|
|
271
299
|
for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
272
|
-
$[0] = "
|
|
300
|
+
$[0] = "576010e4eb39afcae6f9e5e7fcb1b2de7558bf9039ed93e955c51d3fe8a38f1a";
|
|
273
301
|
}
|
|
274
302
|
const { authClient, authenticationUrl } = useAuthContext();
|
|
275
303
|
let t0;
|
|
@@ -321,4 +349,4 @@ function _temp2() {
|
|
|
321
349
|
}
|
|
322
350
|
|
|
323
351
|
//#endregion
|
|
324
|
-
export { AuthContext, createCamoxAuthClient, getAuthCookieHeader, useAuthActions, useAuthContext, useAuthState, useIsAuthenticated, useProcessOtt, useProjectSlug, useSignInRedirect };
|
|
352
|
+
export { AuthContext, createCamoxAuthClient, getAuthCookieHeader, getServerAuthCookieHeader, useAuthActions, useAuthContext, useAuthState, useIsAuthenticated, useProcessOtt, useProjectSlug, useSignInRedirect };
|
package/dist/lib/queries.js
CHANGED
|
@@ -145,6 +145,7 @@ const pageMutations = {
|
|
|
145
145
|
setMetaDescription: () => getOrpc().pages.setMetaDescription.mutationOptions(),
|
|
146
146
|
publish: () => getOrpc().pages.publish.mutationOptions(),
|
|
147
147
|
unpublish: () => getOrpc().pages.unpublish.mutationOptions(),
|
|
148
|
+
discardChanges: () => getOrpc().pages.discardChanges.mutationOptions(),
|
|
148
149
|
uploadCustomOgImage: () => ({ mutationFn: async ({ pageId, file }) => {
|
|
149
150
|
const formData = new FormData();
|
|
150
151
|
formData.append("file", file);
|