camox 0.48.0 → 0.52.1
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/createApp.d.ts +1 -0
- package/dist/core/createApp.js +1 -0
- package/dist/core/editing/contentEdits.js +78 -0
- package/dist/core/editing/createEditableBlock.js +277 -311
- package/dist/core/layoutContext.d.ts +1 -0
- package/dist/core/lib/contentType.js +2 -2
- package/dist/core/recordItem.js +3 -3
- package/dist/features/canvas/CamoxCanvas.js +15 -15
- package/dist/features/canvas/CanvasLoadingScreen.js +15 -11
- package/dist/features/canvas/CanvasPageFrame.js +81 -87
- package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -1
- package/dist/features/canvas/DerivedPagePathInput.js +12 -12
- package/dist/features/canvas/canvasOverlayGeometry.js +1 -1
- package/dist/features/canvas/canvasStore.js +2 -2
- package/dist/features/canvas/sidebar/CanvasInspector.js +1 -1
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +1 -1
- package/dist/features/canvas/sidebar/LayoutPageBlocks.js +23 -31
- package/dist/features/canvas/useCanvasCamera.js +1 -1
- package/dist/features/canvas/useDiscoveredPreviewPaths.js +16 -9
- package/dist/features/content/ContentAssets.js +84 -88
- package/dist/features/page/CuratedPageContent.js +1 -1
- package/dist/features/preview/CamoxPreview.d.ts +8 -4
- package/dist/features/preview/CamoxPreview.js +258 -443
- package/dist/features/preview/EditablePageContent.js +244 -2
- package/dist/features/preview/EditablePageExperience.js +19 -13
- package/dist/features/preview/components/AddBlockSheet.js +55 -15
- package/dist/features/preview/components/BlockActionsPopover.js +23 -51
- package/dist/features/preview/components/BlockPeek.js +66 -0
- package/dist/features/preview/components/BlockThumbnail.js +134 -119
- package/dist/features/preview/components/CanvasPreview.js +1 -1
- package/dist/features/preview/components/CreatePageModal.js +150 -156
- package/dist/features/preview/components/FieldToolbar.js +1 -1
- package/dist/features/preview/components/Frame.js +27 -4
- package/dist/features/preview/components/MobilePreviewDrawer.js +6 -9
- package/dist/features/preview/components/PageInfo.js +161 -126
- package/dist/features/preview/components/PagePicker.js +2 -2
- package/dist/features/preview/components/PageTree.js +174 -190
- package/dist/features/preview/components/PreviewPanel.js +13 -67
- package/dist/features/preview/components/PreviewToolbar.js +1 -1
- package/dist/features/preview/components/ReferenceFieldEditor.js +4 -4
- package/dist/features/preview/components/ReferenceListFieldEditor.js +4 -4
- package/dist/features/preview/components/RemovedBlockPlaceholder.js +37 -70
- package/dist/features/preview/components/RepeatableItemsList.js +1 -1
- package/dist/features/preview/components/SelectionEditor.js +248 -256
- package/dist/features/preview/components/StudioEditingFallback.js +22 -26
- package/dist/features/preview/components/useFieldWriter.js +19 -19
- package/dist/features/preview/components/useRecordView.js +105 -147
- package/dist/features/preview/components/useRepeatableItemActions.js +0 -2
- package/dist/features/preview/pageRecord.js +30 -24
- package/dist/features/preview/previewConstants.js +2 -8
- package/dist/features/preview/previewStore.js +2 -0
- package/dist/features/preview/studioNotice.js +20 -0
- package/dist/features/preview/usePreviewViewportActions.js +1 -1
- package/dist/features/provider/AuthenticatedCamoxProvider.js +47 -31
- package/dist/features/provider/components/CommandPalette.js +2 -5
- package/dist/features/provider/signInShortcut.js +1 -2
- package/dist/features/provider/useAdminShortcuts.js +47 -53
- package/dist/features/renderer/RendererApp.js +542 -0
- package/dist/features/renderer/RendererFrames.js +450 -0
- package/dist/features/renderer/definitionAnswers.js +26 -0
- package/dist/features/renderer/protocol.js +35 -0
- package/dist/features/renderer/rendererHost.js +249 -0
- package/dist/features/renderer/studioConnection.js +186 -0
- package/dist/features/routes/pageRuntime.d.ts +2 -1
- package/dist/features/routes/pageRuntime.js +34 -22
- package/dist/features/runtime/RuntimeChrome.js +2 -5
- package/dist/features/runtime/assetPrefix.js +14 -0
- package/dist/features/runtime/breadcrumbs.js +1 -1
- package/dist/features/runtime/editingFallback.js +4 -8
- package/dist/features/runtime/livePages.js +1 -1
- package/dist/features/runtime/pageApp.js +57 -83
- package/dist/features/runtime/pageClient.js +1 -1
- package/dist/features/runtime/pageNavigation.js +3 -2
- package/dist/features/runtime/publicCache.js +95 -0
- package/dist/features/runtime/publishingDraft.js +23 -0
- package/dist/features/runtime/rendererClient.d.ts +8 -0
- package/dist/features/runtime/rendererClient.js +77 -0
- package/dist/features/runtime/runtime.d.ts +22 -3
- package/dist/features/runtime/runtime.js +209 -96
- package/dist/features/runtime/runtimeRoutes.d.ts +2 -0
- package/dist/features/runtime/runtimeRoutes.js +2 -0
- package/dist/features/runtime/worker.d.ts +14 -1
- package/dist/features/runtime/worker.js +34 -4
- package/dist/features/settings/AnalyticsSettings.js +622 -0
- package/dist/features/settings/CamoxSettings.js +95 -0
- package/dist/features/settings/FaviconSettings.js +254 -0
- package/dist/features/settings/ProjectNameSettings.js +145 -0
- package/dist/features/settings/SettingsPart.js +73 -0
- package/dist/features/settings/SocialProfilesSettings.js +245 -0
- package/dist/features/settings/useProjectMutation.js +61 -0
- package/dist/features/studio/FollowAgentProvider.js +10 -10
- package/dist/features/studio/components/DraftsControl.js +136 -131
- package/dist/features/studio/components/LocalePicker.js +178 -174
- package/dist/features/studio/components/Navbar.js +107 -66
- package/dist/features/studio/components/ProjectMenu.js +119 -171
- package/dist/features/studio/components/ReviewDraftSheet.js +1151 -991
- package/dist/features/studio/components/ThreadMessages.js +100 -65
- package/dist/features/studio/components/UserButton.js +2 -2
- package/dist/features/studio/routes.js +3 -1
- package/dist/features/studio/showInCanvas.js +129 -0
- package/dist/features/vite/definitionsSync.js +5 -6
- package/dist/features/vite/hostedChecks.js +127 -0
- package/dist/features/vite/runtimeDev.js +58 -17
- package/dist/features/vite/staticAssetHeaders.js +52 -0
- package/dist/features/vite/vite.d.ts +1 -1
- package/dist/features/vite/vite.js +49 -9
- package/dist/hooks/use-page-destinations.js +10 -10
- package/dist/lib/api-client-server.d.ts +1 -1
- package/dist/lib/api-client.d.ts +2 -1
- package/dist/lib/draft-scope.d.ts +1 -0
- package/dist/lib/locale-path.d.ts +3 -11
- package/dist/lib/locale-path.js +3 -27
- package/dist/lib/queries.js +7 -1
- package/dist/lib/revisions.js +20 -0
- package/dist/lib/shortcuts.js +29 -0
- package/dist/lib/studio-definitions.js +160 -0
- package/dist/lib/studio-reads.d.ts +1 -0
- package/dist/lib/studio-reads.js +65 -21
- package/dist/lib/use-project-room.js +16 -10
- package/dist/lib/utils.js +1 -104
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +9 -4
- package/skills/camox/SKILL.md +4 -0
- package/skills/camox/references/artifacts.md +1 -1
- package/dist/features/studio/components/FaviconDialog.js +0 -318
- package/dist/features/studio/components/SocialProfilesDialog.js +0 -342
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { getApiUrl } from "../../lib/api-client.js";
|
|
2
|
+
import { reads, useStudioCache } from "../../lib/studio-reads.js";
|
|
3
|
+
import { buildDefaultFaviconUrl, buildFaviconUrl } from "../routes/pageRuntime.js";
|
|
4
|
+
import { SettingsPart } from "./SettingsPart.js";
|
|
5
|
+
import { useProjectMutation } from "./useProjectMutation.js";
|
|
6
|
+
import { c } from "react/compiler-runtime";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { Button } from "@camox/ui/button";
|
|
10
|
+
import { Trash2 } from "lucide-react";
|
|
11
|
+
import { toast } from "@camox/ui/toaster";
|
|
12
|
+
import { Spinner } from "@camox/ui/spinner";
|
|
13
|
+
import { FaviconDropZone, validateFaviconFile } from "@camox/ui/favicon-drop-zone";
|
|
14
|
+
|
|
15
|
+
//#region src/features/settings/FaviconSettings.tsx
|
|
16
|
+
/** Points the studio tab's own icon at the saved favicon, so the change shows without a reload. */
|
|
17
|
+
function refreshDocumentFavicon(href) {
|
|
18
|
+
for (const link of document.querySelectorAll("link[rel~=\"icon\"]")) link.href = href;
|
|
19
|
+
}
|
|
20
|
+
function FaviconSettings(t0) {
|
|
21
|
+
const $ = c(51);
|
|
22
|
+
const { project } = t0;
|
|
23
|
+
const studioCache = useStudioCache();
|
|
24
|
+
const [pending, setPending] = React.useState(null);
|
|
25
|
+
const [hasCurrent, setHasCurrent] = React.useState(false);
|
|
26
|
+
let t1;
|
|
27
|
+
if ($[0] !== project) {
|
|
28
|
+
t1 = buildFaviconUrl(getApiUrl(), project, { withDefault: false });
|
|
29
|
+
$[0] = project;
|
|
30
|
+
$[1] = t1;
|
|
31
|
+
} else t1 = $[1];
|
|
32
|
+
const currentUrl = t1;
|
|
33
|
+
let t2;
|
|
34
|
+
let t3;
|
|
35
|
+
if ($[2] !== currentUrl) {
|
|
36
|
+
t2 = () => {
|
|
37
|
+
const probe = new Image();
|
|
38
|
+
probe.onload = () => setHasCurrent(true);
|
|
39
|
+
probe.onerror = () => setHasCurrent(false);
|
|
40
|
+
probe.src = currentUrl;
|
|
41
|
+
return () => {
|
|
42
|
+
probe.onload = null;
|
|
43
|
+
probe.onerror = null;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
t3 = [currentUrl];
|
|
47
|
+
$[2] = currentUrl;
|
|
48
|
+
$[3] = t2;
|
|
49
|
+
$[4] = t3;
|
|
50
|
+
} else {
|
|
51
|
+
t2 = $[3];
|
|
52
|
+
t3 = $[4];
|
|
53
|
+
}
|
|
54
|
+
React.useEffect(t2, t3);
|
|
55
|
+
const pendingFile = pending?.type === "upload" ? pending.file : null;
|
|
56
|
+
let t4;
|
|
57
|
+
if ($[5] !== pendingFile) {
|
|
58
|
+
t4 = pendingFile ? URL.createObjectURL(pendingFile) : null;
|
|
59
|
+
$[5] = pendingFile;
|
|
60
|
+
$[6] = t4;
|
|
61
|
+
} else t4 = $[6];
|
|
62
|
+
const pendingUrl = t4;
|
|
63
|
+
let t5;
|
|
64
|
+
let t6;
|
|
65
|
+
if ($[7] !== pendingUrl) {
|
|
66
|
+
t5 = () => {
|
|
67
|
+
if (!pendingUrl) return;
|
|
68
|
+
return () => URL.revokeObjectURL(pendingUrl);
|
|
69
|
+
};
|
|
70
|
+
t6 = [pendingUrl];
|
|
71
|
+
$[7] = pendingUrl;
|
|
72
|
+
$[8] = t5;
|
|
73
|
+
$[9] = t6;
|
|
74
|
+
} else {
|
|
75
|
+
t5 = $[8];
|
|
76
|
+
t6 = $[9];
|
|
77
|
+
}
|
|
78
|
+
React.useEffect(t5, t6);
|
|
79
|
+
let t7;
|
|
80
|
+
if ($[10] !== project || $[11] !== studioCache) {
|
|
81
|
+
t7 = () => {
|
|
82
|
+
const updated = studioCache.get(reads.project({ projectUuid: project.uuid }));
|
|
83
|
+
refreshDocumentFavicon(buildFaviconUrl(getApiUrl(), updated ?? project));
|
|
84
|
+
setPending(null);
|
|
85
|
+
};
|
|
86
|
+
$[10] = project;
|
|
87
|
+
$[11] = studioCache;
|
|
88
|
+
$[12] = t7;
|
|
89
|
+
} else t7 = $[12];
|
|
90
|
+
const onSuccess = t7;
|
|
91
|
+
let t8;
|
|
92
|
+
if ($[13] !== onSuccess) {
|
|
93
|
+
t8 = {
|
|
94
|
+
success: "Favicon updated",
|
|
95
|
+
failure: "Could not save the favicon",
|
|
96
|
+
onSuccess
|
|
97
|
+
};
|
|
98
|
+
$[13] = onSuccess;
|
|
99
|
+
$[14] = t8;
|
|
100
|
+
} else t8 = $[14];
|
|
101
|
+
const upload = useProjectMutation(project, "uploadFavicon", t8);
|
|
102
|
+
let t9;
|
|
103
|
+
if ($[15] !== onSuccess) {
|
|
104
|
+
t9 = {
|
|
105
|
+
success: "Favicon removed",
|
|
106
|
+
failure: "Could not save the favicon",
|
|
107
|
+
onSuccess
|
|
108
|
+
};
|
|
109
|
+
$[15] = onSuccess;
|
|
110
|
+
$[16] = t9;
|
|
111
|
+
} else t9 = $[16];
|
|
112
|
+
const remove = useProjectMutation(project, "deleteFavicon", t9);
|
|
113
|
+
const isSaving = upload.isPending || remove.isPending;
|
|
114
|
+
let t10;
|
|
115
|
+
if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
|
|
116
|
+
t10 = (file) => {
|
|
117
|
+
const error = validateFaviconFile(file);
|
|
118
|
+
if (error) {
|
|
119
|
+
toast.error(error);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
setPending({
|
|
123
|
+
type: "upload",
|
|
124
|
+
file
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
$[17] = t10;
|
|
128
|
+
} else t10 = $[17];
|
|
129
|
+
const choose = t10;
|
|
130
|
+
let t11;
|
|
131
|
+
if ($[18] !== pending || $[19] !== project || $[20] !== remove || $[21] !== upload) {
|
|
132
|
+
t11 = () => {
|
|
133
|
+
if (pending?.type === "upload") {
|
|
134
|
+
upload.mutate({
|
|
135
|
+
projectId: project.id,
|
|
136
|
+
file: pending.file
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (pending?.type === "remove") remove.mutate({ projectId: project.id });
|
|
141
|
+
};
|
|
142
|
+
$[18] = pending;
|
|
143
|
+
$[19] = project;
|
|
144
|
+
$[20] = remove;
|
|
145
|
+
$[21] = upload;
|
|
146
|
+
$[22] = t11;
|
|
147
|
+
} else t11 = $[22];
|
|
148
|
+
const save = t11;
|
|
149
|
+
const showsFavicon = pending ? pending.type === "upload" : hasCurrent;
|
|
150
|
+
let t12;
|
|
151
|
+
if ($[23] !== currentUrl || $[24] !== pendingUrl || $[25] !== showsFavicon) {
|
|
152
|
+
t12 = pendingUrl ?? (showsFavicon ? currentUrl : buildDefaultFaviconUrl(getApiUrl()));
|
|
153
|
+
$[23] = currentUrl;
|
|
154
|
+
$[24] = pendingUrl;
|
|
155
|
+
$[25] = showsFavicon;
|
|
156
|
+
$[26] = t12;
|
|
157
|
+
} else t12 = $[26];
|
|
158
|
+
const previewUrl = t12;
|
|
159
|
+
const prompt = pendingFile ? pendingFile.name : showsFavicon ? "Drop a new favicon, or click to browse" : "Drop your favicon here, or click to browse";
|
|
160
|
+
let t13;
|
|
161
|
+
if ($[27] !== isSaving || $[28] !== previewUrl || $[29] !== prompt) {
|
|
162
|
+
t13 = /* @__PURE__ */ jsx(FaviconDropZone, {
|
|
163
|
+
previewUrl,
|
|
164
|
+
prompt,
|
|
165
|
+
disabled: isSaving,
|
|
166
|
+
onFileSelected: choose
|
|
167
|
+
});
|
|
168
|
+
$[27] = isSaving;
|
|
169
|
+
$[28] = previewUrl;
|
|
170
|
+
$[29] = prompt;
|
|
171
|
+
$[30] = t13;
|
|
172
|
+
} else t13 = $[30];
|
|
173
|
+
const t14 = !pending || isSaving;
|
|
174
|
+
let t15;
|
|
175
|
+
if ($[31] !== isSaving) {
|
|
176
|
+
t15 = isSaving && /* @__PURE__ */ jsx(Spinner, {});
|
|
177
|
+
$[31] = isSaving;
|
|
178
|
+
$[32] = t15;
|
|
179
|
+
} else t15 = $[32];
|
|
180
|
+
let t16;
|
|
181
|
+
if ($[33] !== save || $[34] !== t14 || $[35] !== t15) {
|
|
182
|
+
t16 = /* @__PURE__ */ jsxs(Button, {
|
|
183
|
+
type: "button",
|
|
184
|
+
onClick: save,
|
|
185
|
+
disabled: t14,
|
|
186
|
+
children: [t15, "Save"]
|
|
187
|
+
});
|
|
188
|
+
$[33] = save;
|
|
189
|
+
$[34] = t14;
|
|
190
|
+
$[35] = t15;
|
|
191
|
+
$[36] = t16;
|
|
192
|
+
} else t16 = $[36];
|
|
193
|
+
let t17;
|
|
194
|
+
if ($[37] !== isSaving || $[38] !== pending) {
|
|
195
|
+
t17 = pending && /* @__PURE__ */ jsx(Button, {
|
|
196
|
+
type: "button",
|
|
197
|
+
variant: "outline",
|
|
198
|
+
disabled: isSaving,
|
|
199
|
+
onClick: () => setPending(null),
|
|
200
|
+
children: "Cancel"
|
|
201
|
+
});
|
|
202
|
+
$[37] = isSaving;
|
|
203
|
+
$[38] = pending;
|
|
204
|
+
$[39] = t17;
|
|
205
|
+
} else t17 = $[39];
|
|
206
|
+
let t18;
|
|
207
|
+
if ($[40] !== hasCurrent || $[41] !== isSaving || $[42] !== showsFavicon) {
|
|
208
|
+
t18 = showsFavicon && /* @__PURE__ */ jsxs(Button, {
|
|
209
|
+
type: "button",
|
|
210
|
+
variant: "ghost",
|
|
211
|
+
className: "ml-auto",
|
|
212
|
+
disabled: isSaving,
|
|
213
|
+
onClick: () => setPending(hasCurrent ? { type: "remove" } : null),
|
|
214
|
+
children: [/* @__PURE__ */ jsx(Trash2, {}), "Remove favicon"]
|
|
215
|
+
});
|
|
216
|
+
$[40] = hasCurrent;
|
|
217
|
+
$[41] = isSaving;
|
|
218
|
+
$[42] = showsFavicon;
|
|
219
|
+
$[43] = t18;
|
|
220
|
+
} else t18 = $[43];
|
|
221
|
+
let t19;
|
|
222
|
+
if ($[44] !== t16 || $[45] !== t17 || $[46] !== t18) {
|
|
223
|
+
t19 = /* @__PURE__ */ jsxs("div", {
|
|
224
|
+
className: "flex flex-wrap gap-2",
|
|
225
|
+
children: [
|
|
226
|
+
t16,
|
|
227
|
+
t17,
|
|
228
|
+
t18
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
$[44] = t16;
|
|
232
|
+
$[45] = t17;
|
|
233
|
+
$[46] = t18;
|
|
234
|
+
$[47] = t19;
|
|
235
|
+
} else t19 = $[47];
|
|
236
|
+
let t20;
|
|
237
|
+
if ($[48] !== t13 || $[49] !== t19) {
|
|
238
|
+
t20 = /* @__PURE__ */ jsx(SettingsPart, {
|
|
239
|
+
title: "Favicon",
|
|
240
|
+
description: "The icon shown in browser tabs and bookmarks.",
|
|
241
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
242
|
+
className: "flex flex-col gap-4",
|
|
243
|
+
children: [t13, t19]
|
|
244
|
+
})
|
|
245
|
+
});
|
|
246
|
+
$[48] = t13;
|
|
247
|
+
$[49] = t19;
|
|
248
|
+
$[50] = t20;
|
|
249
|
+
} else t20 = $[50];
|
|
250
|
+
return t20;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
//#endregion
|
|
254
|
+
export { FaviconSettings };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { SettingsPart } from "./SettingsPart.js";
|
|
2
|
+
import { useProjectMutation } from "./useProjectMutation.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Button } from "@camox/ui/button";
|
|
7
|
+
import { Input } from "@camox/ui/input";
|
|
8
|
+
import { Label } from "@camox/ui/label";
|
|
9
|
+
import { Spinner } from "@camox/ui/spinner";
|
|
10
|
+
|
|
11
|
+
//#region src/features/settings/ProjectNameSettings.tsx
|
|
12
|
+
function ProjectNameSettings(t0) {
|
|
13
|
+
const $ = c(27);
|
|
14
|
+
const { project } = t0;
|
|
15
|
+
const [name, setName] = React.useState(project.name);
|
|
16
|
+
const [error, setError] = React.useState(null);
|
|
17
|
+
let t1;
|
|
18
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
19
|
+
t1 = {
|
|
20
|
+
success: "Project name updated",
|
|
21
|
+
failure: "Could not update the project name"
|
|
22
|
+
};
|
|
23
|
+
$[0] = t1;
|
|
24
|
+
} else t1 = $[0];
|
|
25
|
+
const save = useProjectMutation(project, "update", t1);
|
|
26
|
+
let t2;
|
|
27
|
+
if ($[1] !== name) {
|
|
28
|
+
t2 = name.trim();
|
|
29
|
+
$[1] = name;
|
|
30
|
+
$[2] = t2;
|
|
31
|
+
} else t2 = $[2];
|
|
32
|
+
const trimmedName = t2;
|
|
33
|
+
let t3;
|
|
34
|
+
if ($[3] !== project.id || $[4] !== save || $[5] !== trimmedName) {
|
|
35
|
+
t3 = (event) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
if (!trimmedName) {
|
|
38
|
+
setError("Project name is required");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
save.mutate({
|
|
42
|
+
id: project.id,
|
|
43
|
+
name: trimmedName
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
$[3] = project.id;
|
|
47
|
+
$[4] = save;
|
|
48
|
+
$[5] = trimmedName;
|
|
49
|
+
$[6] = t3;
|
|
50
|
+
} else t3 = $[6];
|
|
51
|
+
const submit = t3;
|
|
52
|
+
let t4;
|
|
53
|
+
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
54
|
+
t4 = /* @__PURE__ */ jsx(Label, {
|
|
55
|
+
htmlFor: "camox-project-name",
|
|
56
|
+
children: "Project name"
|
|
57
|
+
});
|
|
58
|
+
$[7] = t4;
|
|
59
|
+
} else t4 = $[7];
|
|
60
|
+
const t5 = error ? true : void 0;
|
|
61
|
+
let t6;
|
|
62
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
63
|
+
t6 = (event_0) => {
|
|
64
|
+
setName(event_0.target.value);
|
|
65
|
+
setError(null);
|
|
66
|
+
};
|
|
67
|
+
$[8] = t6;
|
|
68
|
+
} else t6 = $[8];
|
|
69
|
+
let t7;
|
|
70
|
+
if ($[9] !== name || $[10] !== save.isPending || $[11] !== t5) {
|
|
71
|
+
t7 = /* @__PURE__ */ jsx(Input, {
|
|
72
|
+
id: "camox-project-name",
|
|
73
|
+
value: name,
|
|
74
|
+
"aria-invalid": t5,
|
|
75
|
+
disabled: save.isPending,
|
|
76
|
+
onChange: t6
|
|
77
|
+
});
|
|
78
|
+
$[9] = name;
|
|
79
|
+
$[10] = save.isPending;
|
|
80
|
+
$[11] = t5;
|
|
81
|
+
$[12] = t7;
|
|
82
|
+
} else t7 = $[12];
|
|
83
|
+
let t8;
|
|
84
|
+
if ($[13] !== error) {
|
|
85
|
+
t8 = error && /* @__PURE__ */ jsx("p", {
|
|
86
|
+
className: "text-destructive text-xs",
|
|
87
|
+
children: error
|
|
88
|
+
});
|
|
89
|
+
$[13] = error;
|
|
90
|
+
$[14] = t8;
|
|
91
|
+
} else t8 = $[14];
|
|
92
|
+
let t9;
|
|
93
|
+
if ($[15] !== t7 || $[16] !== t8) {
|
|
94
|
+
t9 = /* @__PURE__ */ jsxs("div", {
|
|
95
|
+
className: "flex flex-col gap-2",
|
|
96
|
+
children: [
|
|
97
|
+
t4,
|
|
98
|
+
t7,
|
|
99
|
+
t8
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
$[15] = t7;
|
|
103
|
+
$[16] = t8;
|
|
104
|
+
$[17] = t9;
|
|
105
|
+
} else t9 = $[17];
|
|
106
|
+
const t10 = trimmedName === project.name || save.isPending;
|
|
107
|
+
let t11;
|
|
108
|
+
if ($[18] !== save.isPending) {
|
|
109
|
+
t11 = save.isPending && /* @__PURE__ */ jsx(Spinner, {});
|
|
110
|
+
$[18] = save.isPending;
|
|
111
|
+
$[19] = t11;
|
|
112
|
+
} else t11 = $[19];
|
|
113
|
+
let t12;
|
|
114
|
+
if ($[20] !== t10 || $[21] !== t11) {
|
|
115
|
+
t12 = /* @__PURE__ */ jsxs(Button, {
|
|
116
|
+
type: "submit",
|
|
117
|
+
className: "self-start",
|
|
118
|
+
disabled: t10,
|
|
119
|
+
children: [t11, "Save changes"]
|
|
120
|
+
});
|
|
121
|
+
$[20] = t10;
|
|
122
|
+
$[21] = t11;
|
|
123
|
+
$[22] = t12;
|
|
124
|
+
} else t12 = $[22];
|
|
125
|
+
let t13;
|
|
126
|
+
if ($[23] !== submit || $[24] !== t12 || $[25] !== t9) {
|
|
127
|
+
t13 = /* @__PURE__ */ jsx(SettingsPart, {
|
|
128
|
+
title: "Project name",
|
|
129
|
+
description: "How the project is named in Camox.",
|
|
130
|
+
children: /* @__PURE__ */ jsxs("form", {
|
|
131
|
+
onSubmit: submit,
|
|
132
|
+
className: "flex flex-col gap-4",
|
|
133
|
+
children: [t9, t12]
|
|
134
|
+
})
|
|
135
|
+
});
|
|
136
|
+
$[23] = submit;
|
|
137
|
+
$[24] = t12;
|
|
138
|
+
$[25] = t9;
|
|
139
|
+
$[26] = t13;
|
|
140
|
+
} else t13 = $[26];
|
|
141
|
+
return t13;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//#endregion
|
|
145
|
+
export { ProjectNameSettings };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/features/settings/SettingsPart.tsx
|
|
5
|
+
/** One part of the Settings Section: what it sets, beside the form that sets it. */
|
|
6
|
+
function SettingsPart(t0) {
|
|
7
|
+
const $ = c(17);
|
|
8
|
+
const { title, description, children } = t0;
|
|
9
|
+
let t1;
|
|
10
|
+
if ($[0] !== title) {
|
|
11
|
+
let t2;
|
|
12
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
13
|
+
t2 = /\W+/g;
|
|
14
|
+
$[2] = t2;
|
|
15
|
+
} else t2 = $[2];
|
|
16
|
+
t1 = title.toLowerCase().replaceAll(t2, "-");
|
|
17
|
+
$[0] = title;
|
|
18
|
+
$[1] = t1;
|
|
19
|
+
} else t1 = $[1];
|
|
20
|
+
const id = `camox-settings-${t1}`;
|
|
21
|
+
let t2;
|
|
22
|
+
if ($[3] !== id || $[4] !== title) {
|
|
23
|
+
t2 = /* @__PURE__ */ jsx("h2", {
|
|
24
|
+
id,
|
|
25
|
+
className: "font-semibold",
|
|
26
|
+
children: title
|
|
27
|
+
});
|
|
28
|
+
$[3] = id;
|
|
29
|
+
$[4] = title;
|
|
30
|
+
$[5] = t2;
|
|
31
|
+
} else t2 = $[5];
|
|
32
|
+
let t3;
|
|
33
|
+
if ($[6] !== description) {
|
|
34
|
+
t3 = /* @__PURE__ */ jsx("p", {
|
|
35
|
+
className: "text-muted-foreground mt-1 text-sm",
|
|
36
|
+
children: description
|
|
37
|
+
});
|
|
38
|
+
$[6] = description;
|
|
39
|
+
$[7] = t3;
|
|
40
|
+
} else t3 = $[7];
|
|
41
|
+
let t4;
|
|
42
|
+
if ($[8] !== t2 || $[9] !== t3) {
|
|
43
|
+
t4 = /* @__PURE__ */ jsxs("div", { children: [t2, t3] });
|
|
44
|
+
$[8] = t2;
|
|
45
|
+
$[9] = t3;
|
|
46
|
+
$[10] = t4;
|
|
47
|
+
} else t4 = $[10];
|
|
48
|
+
let t5;
|
|
49
|
+
if ($[11] !== children) {
|
|
50
|
+
t5 = /* @__PURE__ */ jsx("div", {
|
|
51
|
+
className: "md:col-span-2",
|
|
52
|
+
children
|
|
53
|
+
});
|
|
54
|
+
$[11] = children;
|
|
55
|
+
$[12] = t5;
|
|
56
|
+
} else t5 = $[12];
|
|
57
|
+
let t6;
|
|
58
|
+
if ($[13] !== id || $[14] !== t4 || $[15] !== t5) {
|
|
59
|
+
t6 = /* @__PURE__ */ jsxs("section", {
|
|
60
|
+
"aria-labelledby": id,
|
|
61
|
+
className: "grid gap-4 md:grid-cols-3 md:gap-8",
|
|
62
|
+
children: [t4, t5]
|
|
63
|
+
});
|
|
64
|
+
$[13] = id;
|
|
65
|
+
$[14] = t4;
|
|
66
|
+
$[15] = t5;
|
|
67
|
+
$[16] = t6;
|
|
68
|
+
} else t6 = $[16];
|
|
69
|
+
return t6;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { SettingsPart };
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { SettingsPart } from "./SettingsPart.js";
|
|
2
|
+
import { useProjectMutation } from "./useProjectMutation.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Button } from "@camox/ui/button";
|
|
7
|
+
import { Input } from "@camox/ui/input";
|
|
8
|
+
import { ArrowDown, ArrowUp, Plus, Trash2 } from "lucide-react";
|
|
9
|
+
import { Spinner } from "@camox/ui/spinner";
|
|
10
|
+
import { socialProfileUrlSchema } from "@camox/api-contract/projects";
|
|
11
|
+
|
|
12
|
+
//#region src/features/settings/SocialProfilesSettings.tsx
|
|
13
|
+
let nextRowKey = 0;
|
|
14
|
+
const row = (url) => ({
|
|
15
|
+
key: nextRowKey++,
|
|
16
|
+
url
|
|
17
|
+
});
|
|
18
|
+
function SocialProfilesSettings(t0) {
|
|
19
|
+
const $ = c(33);
|
|
20
|
+
const { project } = t0;
|
|
21
|
+
let t1;
|
|
22
|
+
if ($[0] !== project) {
|
|
23
|
+
t1 = () => project.socialProfiles.map(row);
|
|
24
|
+
$[0] = project;
|
|
25
|
+
$[1] = t1;
|
|
26
|
+
} else t1 = $[1];
|
|
27
|
+
const [rows, setRows] = React.useState(t1);
|
|
28
|
+
const [showErrors, setShowErrors] = React.useState(false);
|
|
29
|
+
let t2;
|
|
30
|
+
if ($[2] !== rows) {
|
|
31
|
+
t2 = rows.map(_temp).filter(_temp2);
|
|
32
|
+
$[2] = rows;
|
|
33
|
+
$[3] = t2;
|
|
34
|
+
} else t2 = $[3];
|
|
35
|
+
const filled = t2;
|
|
36
|
+
let t3;
|
|
37
|
+
if ($[4] !== filled) {
|
|
38
|
+
t3 = {
|
|
39
|
+
success: "Social profiles updated",
|
|
40
|
+
failure: "Could not save the social profiles",
|
|
41
|
+
onSuccess: () => {
|
|
42
|
+
setRows(filled);
|
|
43
|
+
setShowErrors(false);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
$[4] = filled;
|
|
47
|
+
$[5] = t3;
|
|
48
|
+
} else t3 = $[5];
|
|
49
|
+
const save = useProjectMutation(project, "updateSocialProfiles", t3);
|
|
50
|
+
const errorOf = _temp3;
|
|
51
|
+
let t4;
|
|
52
|
+
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
|
53
|
+
t4 = (key, url_0) => setRows((current) => current.map((entry_0) => entry_0.key === key ? {
|
|
54
|
+
...entry_0,
|
|
55
|
+
url: url_0
|
|
56
|
+
} : entry_0));
|
|
57
|
+
$[6] = t4;
|
|
58
|
+
} else t4 = $[6];
|
|
59
|
+
const update = t4;
|
|
60
|
+
let t5;
|
|
61
|
+
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
62
|
+
t5 = (key_0) => setRows((current_0) => current_0.filter((entry_1) => entry_1.key !== key_0));
|
|
63
|
+
$[7] = t5;
|
|
64
|
+
} else t5 = $[7];
|
|
65
|
+
const remove = t5;
|
|
66
|
+
let t6;
|
|
67
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
68
|
+
t6 = (index, by) => setRows((current_1) => {
|
|
69
|
+
const next = [...current_1];
|
|
70
|
+
const [moved] = next.splice(index, 1);
|
|
71
|
+
next.splice(index + by, 0, moved);
|
|
72
|
+
return next;
|
|
73
|
+
});
|
|
74
|
+
$[8] = t6;
|
|
75
|
+
} else t6 = $[8];
|
|
76
|
+
const move = t6;
|
|
77
|
+
let t7;
|
|
78
|
+
if ($[9] !== filled || $[10] !== project || $[11] !== save) {
|
|
79
|
+
t7 = (event) => {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
if (filled.some((entry_2) => errorOf(entry_2.url))) {
|
|
82
|
+
setShowErrors(true);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
save.mutate({
|
|
86
|
+
id: project.id,
|
|
87
|
+
socialProfiles: filled.map(_temp4)
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
$[9] = filled;
|
|
91
|
+
$[10] = project;
|
|
92
|
+
$[11] = save;
|
|
93
|
+
$[12] = t7;
|
|
94
|
+
} else t7 = $[12];
|
|
95
|
+
const submit = t7;
|
|
96
|
+
let t8;
|
|
97
|
+
if ($[13] !== rows || $[14] !== save.isPending || $[15] !== showErrors) {
|
|
98
|
+
t8 = rows.length > 0 && /* @__PURE__ */ jsx("ol", {
|
|
99
|
+
className: "flex flex-col gap-2",
|
|
100
|
+
children: rows.map((entry_4, index_0) => {
|
|
101
|
+
const error = showErrors && entry_4.url.trim() ? errorOf(entry_4.url) : void 0;
|
|
102
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
103
|
+
className: "flex flex-col gap-1",
|
|
104
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
105
|
+
className: "flex items-center gap-1",
|
|
106
|
+
children: [
|
|
107
|
+
/* @__PURE__ */ jsx(Input, {
|
|
108
|
+
type: "url",
|
|
109
|
+
value: entry_4.url,
|
|
110
|
+
placeholder: "https://www.linkedin.com/company/…",
|
|
111
|
+
"aria-label": `Profile ${index_0 + 1}`,
|
|
112
|
+
"aria-invalid": error ? true : void 0,
|
|
113
|
+
disabled: save.isPending,
|
|
114
|
+
onChange: (event_0) => update(entry_4.key, event_0.target.value)
|
|
115
|
+
}),
|
|
116
|
+
/* @__PURE__ */ jsx(Button, {
|
|
117
|
+
type: "button",
|
|
118
|
+
variant: "ghost",
|
|
119
|
+
size: "icon",
|
|
120
|
+
"aria-label": "Move up",
|
|
121
|
+
disabled: index_0 === 0 || save.isPending,
|
|
122
|
+
onClick: () => move(index_0, -1),
|
|
123
|
+
children: /* @__PURE__ */ jsx(ArrowUp, {})
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ jsx(Button, {
|
|
126
|
+
type: "button",
|
|
127
|
+
variant: "ghost",
|
|
128
|
+
size: "icon",
|
|
129
|
+
"aria-label": "Move down",
|
|
130
|
+
disabled: index_0 === rows.length - 1 || save.isPending,
|
|
131
|
+
onClick: () => move(index_0, 1),
|
|
132
|
+
children: /* @__PURE__ */ jsx(ArrowDown, {})
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ jsx(Button, {
|
|
135
|
+
type: "button",
|
|
136
|
+
variant: "ghost",
|
|
137
|
+
size: "icon",
|
|
138
|
+
"aria-label": "Remove",
|
|
139
|
+
disabled: save.isPending,
|
|
140
|
+
onClick: () => remove(entry_4.key),
|
|
141
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
}), error && /* @__PURE__ */ jsx("p", {
|
|
145
|
+
className: "text-destructive text-xs",
|
|
146
|
+
children: error
|
|
147
|
+
})]
|
|
148
|
+
}, entry_4.key);
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
$[13] = rows;
|
|
152
|
+
$[14] = save.isPending;
|
|
153
|
+
$[15] = showErrors;
|
|
154
|
+
$[16] = t8;
|
|
155
|
+
} else t8 = $[16];
|
|
156
|
+
let t9;
|
|
157
|
+
if ($[17] !== save.isPending) {
|
|
158
|
+
t9 = save.isPending && /* @__PURE__ */ jsx(Spinner, {});
|
|
159
|
+
$[17] = save.isPending;
|
|
160
|
+
$[18] = t9;
|
|
161
|
+
} else t9 = $[18];
|
|
162
|
+
let t10;
|
|
163
|
+
if ($[19] !== save.isPending || $[20] !== t9) {
|
|
164
|
+
t10 = /* @__PURE__ */ jsxs(Button, {
|
|
165
|
+
type: "submit",
|
|
166
|
+
disabled: save.isPending,
|
|
167
|
+
children: [t9, "Save"]
|
|
168
|
+
});
|
|
169
|
+
$[19] = save.isPending;
|
|
170
|
+
$[20] = t9;
|
|
171
|
+
$[21] = t10;
|
|
172
|
+
} else t10 = $[21];
|
|
173
|
+
let t11;
|
|
174
|
+
let t12;
|
|
175
|
+
if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
|
|
176
|
+
t11 = () => setRows(_temp5);
|
|
177
|
+
t12 = /* @__PURE__ */ jsx(Plus, {});
|
|
178
|
+
$[22] = t11;
|
|
179
|
+
$[23] = t12;
|
|
180
|
+
} else {
|
|
181
|
+
t11 = $[22];
|
|
182
|
+
t12 = $[23];
|
|
183
|
+
}
|
|
184
|
+
let t13;
|
|
185
|
+
if ($[24] !== save.isPending) {
|
|
186
|
+
t13 = /* @__PURE__ */ jsxs(Button, {
|
|
187
|
+
type: "button",
|
|
188
|
+
variant: "ghost",
|
|
189
|
+
disabled: save.isPending,
|
|
190
|
+
onClick: t11,
|
|
191
|
+
children: [t12, "Add profile"]
|
|
192
|
+
});
|
|
193
|
+
$[24] = save.isPending;
|
|
194
|
+
$[25] = t13;
|
|
195
|
+
} else t13 = $[25];
|
|
196
|
+
let t14;
|
|
197
|
+
if ($[26] !== t10 || $[27] !== t13) {
|
|
198
|
+
t14 = /* @__PURE__ */ jsxs("div", {
|
|
199
|
+
className: "flex flex-wrap gap-2",
|
|
200
|
+
children: [t10, t13]
|
|
201
|
+
});
|
|
202
|
+
$[26] = t10;
|
|
203
|
+
$[27] = t13;
|
|
204
|
+
$[28] = t14;
|
|
205
|
+
} else t14 = $[28];
|
|
206
|
+
let t15;
|
|
207
|
+
if ($[29] !== submit || $[30] !== t14 || $[31] !== t8) {
|
|
208
|
+
t15 = /* @__PURE__ */ jsx(SettingsPart, {
|
|
209
|
+
title: "Social profiles",
|
|
210
|
+
description: "The project's accounts elsewhere, such as on LinkedIn, X or GitHub. Search engines and AI answer engines use them to tie the website to your organization.",
|
|
211
|
+
children: /* @__PURE__ */ jsxs("form", {
|
|
212
|
+
onSubmit: submit,
|
|
213
|
+
className: "flex flex-col gap-4",
|
|
214
|
+
children: [t8, t14]
|
|
215
|
+
})
|
|
216
|
+
});
|
|
217
|
+
$[29] = submit;
|
|
218
|
+
$[30] = t14;
|
|
219
|
+
$[31] = t8;
|
|
220
|
+
$[32] = t15;
|
|
221
|
+
} else t15 = $[32];
|
|
222
|
+
return t15;
|
|
223
|
+
}
|
|
224
|
+
function _temp5(current_2) {
|
|
225
|
+
return [...current_2, row("")];
|
|
226
|
+
}
|
|
227
|
+
function _temp4(entry_3) {
|
|
228
|
+
return entry_3.url;
|
|
229
|
+
}
|
|
230
|
+
function _temp3(url) {
|
|
231
|
+
const result = socialProfileUrlSchema.safeParse(url.trim());
|
|
232
|
+
return result.success ? void 0 : result.error.issues[0]?.message;
|
|
233
|
+
}
|
|
234
|
+
function _temp2(e) {
|
|
235
|
+
return e.url;
|
|
236
|
+
}
|
|
237
|
+
function _temp(entry) {
|
|
238
|
+
return {
|
|
239
|
+
...entry,
|
|
240
|
+
url: entry.url.trim()
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
export { SocialProfilesSettings };
|