camox 0.72.0 → 0.74.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/features/preview/components/PageInfo.js +121 -98
- package/dist/features/preview/components/SelectionEditor.js +1 -1
- package/dist/features/routes/pageRuntime.js +15 -4
- package/dist/features/runtime/ClaimCard.js +192 -0
- package/dist/features/runtime/pageApp.js +4 -3
- package/dist/features/runtime/runtime.js +26 -5
- package/dist/features/runtime/worker.js +2 -2
- package/dist/features/runtime/workerRequest.d.ts +6 -0
- package/dist/features/runtime/workerRequest.js +13 -1
- package/dist/features/runtime/workerRuntime.d.ts +2 -2
- package/dist/features/runtime/workerRuntime.js +2 -2
- package/dist/features/studio/components/AgentSidebar.js +7 -7
- package/dist/features/studio/components/ChatWidget.js +142 -106
- package/dist/features/studio/components/ContentFindings.js +127 -230
- package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
- package/dist/features/studio/components/DraftBar.js +98 -53
- package/dist/features/studio/components/DraftsControl.js +203 -190
- package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
- package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
- package/dist/features/studio/components/Squareling.js +5 -5
- package/dist/features/studio/components/ThreadComposer.js +106 -127
- package/dist/features/studio/components/ThreadMessages.js +94 -69
- package/dist/features/studio/findingSentence.js +14 -12
- package/dist/features/studio/fixMessage.js +23 -0
- package/dist/features/studio/reportSentence.js +1 -1
- package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
- package/dist/features/studio/studioStore.js +29 -15
- package/dist/features/studio/workingSentence.js +1 -1
- package/dist/lib/api-client.js +5 -1
- package/dist/lib/queries.js +5 -5
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -5
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/dist/features/studio/components/ReviewDraftSheet.js +0 -1587
|
@@ -16,6 +16,7 @@ import { useRendererAnswer } from "../../renderer/RendererFrames.js";
|
|
|
16
16
|
import { PageLocationFieldset } from "./PageLocationFieldset.js";
|
|
17
17
|
import { PageNicknameField } from "./PageNicknameField.js";
|
|
18
18
|
import { pageImageUrl } from "../../og/pageImage.js";
|
|
19
|
+
import { ContentFindings, useContentFindings } from "../../studio/components/ContentFindings.js";
|
|
19
20
|
import { ShikiMarkdown } from "./ShikiMarkdown.js";
|
|
20
21
|
import { c } from "react/compiler-runtime";
|
|
21
22
|
import * as React from "react";
|
|
@@ -1094,7 +1095,7 @@ const PageSeoContent = (t0) => {
|
|
|
1094
1095
|
return t1;
|
|
1095
1096
|
};
|
|
1096
1097
|
const PageSeoEditor = (t0) => {
|
|
1097
|
-
const $ = c(
|
|
1098
|
+
const $ = c(46);
|
|
1098
1099
|
const { page, metaTitle } = t0;
|
|
1099
1100
|
let t1;
|
|
1100
1101
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
@@ -1104,149 +1105,171 @@ const PageSeoEditor = (t0) => {
|
|
|
1104
1105
|
const setSeo = useMutation(t1);
|
|
1105
1106
|
const localized = useLocalizedPath();
|
|
1106
1107
|
let t2;
|
|
1107
|
-
if ($[1] !== page.id
|
|
1108
|
-
t2 =
|
|
1108
|
+
if ($[1] !== page.id) {
|
|
1109
|
+
t2 = {
|
|
1110
|
+
entity: "page",
|
|
1111
|
+
id: page.id
|
|
1112
|
+
};
|
|
1113
|
+
$[1] = page.id;
|
|
1114
|
+
$[2] = t2;
|
|
1115
|
+
} else t2 = $[2];
|
|
1116
|
+
const findings = useContentFindings(t2);
|
|
1117
|
+
let t3;
|
|
1118
|
+
if ($[3] !== page.id || $[4] !== setSeo) {
|
|
1119
|
+
t3 = (checked) => {
|
|
1109
1120
|
setSeo.mutate({
|
|
1110
1121
|
id: page.id,
|
|
1111
1122
|
aiSeo: checked
|
|
1112
1123
|
});
|
|
1113
1124
|
};
|
|
1114
|
-
$[
|
|
1115
|
-
$[
|
|
1116
|
-
$[
|
|
1117
|
-
} else
|
|
1118
|
-
let
|
|
1119
|
-
if ($[
|
|
1120
|
-
|
|
1125
|
+
$[3] = page.id;
|
|
1126
|
+
$[4] = setSeo;
|
|
1127
|
+
$[5] = t3;
|
|
1128
|
+
} else t3 = $[5];
|
|
1129
|
+
let t4;
|
|
1130
|
+
if ($[6] !== page.aiSeo || $[7] !== t3) {
|
|
1131
|
+
t4 = /* @__PURE__ */ jsx(Switch, {
|
|
1121
1132
|
id: "ai-seo",
|
|
1122
1133
|
checked: page.aiSeo,
|
|
1123
|
-
onCheckedChange:
|
|
1134
|
+
onCheckedChange: t3
|
|
1124
1135
|
});
|
|
1125
|
-
$[
|
|
1126
|
-
$[
|
|
1127
|
-
$[
|
|
1128
|
-
} else
|
|
1129
|
-
let
|
|
1130
|
-
if ($[
|
|
1131
|
-
|
|
1136
|
+
$[6] = page.aiSeo;
|
|
1137
|
+
$[7] = t3;
|
|
1138
|
+
$[8] = t4;
|
|
1139
|
+
} else t4 = $[8];
|
|
1140
|
+
let t5;
|
|
1141
|
+
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
|
|
1142
|
+
t5 = /* @__PURE__ */ jsx(Label, {
|
|
1132
1143
|
htmlFor: "ai-seo",
|
|
1133
1144
|
children: "AI metadata"
|
|
1134
1145
|
});
|
|
1135
|
-
$[7] = t4;
|
|
1136
|
-
} else t4 = $[7];
|
|
1137
|
-
let t5;
|
|
1138
|
-
if ($[8] !== t3) {
|
|
1139
|
-
t5 = /* @__PURE__ */ jsxs("div", {
|
|
1140
|
-
className: "flex items-center gap-2",
|
|
1141
|
-
children: [t3, t4]
|
|
1142
|
-
});
|
|
1143
|
-
$[8] = t3;
|
|
1144
1146
|
$[9] = t5;
|
|
1145
1147
|
} else t5 = $[9];
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1148
|
+
let t6;
|
|
1149
|
+
if ($[10] !== t4) {
|
|
1150
|
+
t6 = /* @__PURE__ */ jsxs("div", {
|
|
1151
|
+
className: "flex items-center gap-2",
|
|
1152
|
+
children: [t4, t5]
|
|
1153
|
+
});
|
|
1154
|
+
$[10] = t4;
|
|
1155
|
+
$[11] = t6;
|
|
1156
|
+
} else t6 = $[11];
|
|
1157
|
+
const t7 = page.metaTitle ?? "";
|
|
1158
|
+
let t8;
|
|
1159
|
+
if ($[12] !== page.id || $[13] !== setSeo) {
|
|
1160
|
+
t8 = (value) => setSeo.mutate({
|
|
1150
1161
|
id: page.id,
|
|
1151
1162
|
metaTitle: value
|
|
1152
1163
|
});
|
|
1153
|
-
$[
|
|
1154
|
-
$[
|
|
1155
|
-
$[
|
|
1156
|
-
} else
|
|
1157
|
-
let
|
|
1158
|
-
if ($[
|
|
1159
|
-
|
|
1164
|
+
$[12] = page.id;
|
|
1165
|
+
$[13] = setSeo;
|
|
1166
|
+
$[14] = t8;
|
|
1167
|
+
} else t8 = $[14];
|
|
1168
|
+
let t9;
|
|
1169
|
+
if ($[15] !== page.aiSeo || $[16] !== t7 || $[17] !== t8) {
|
|
1170
|
+
t9 = /* @__PURE__ */ jsx(DebouncedFieldEditor, {
|
|
1160
1171
|
label: "Page title",
|
|
1161
1172
|
placeholder: "Page title...",
|
|
1162
|
-
initialValue:
|
|
1173
|
+
initialValue: t7,
|
|
1163
1174
|
disabled: page.aiSeo,
|
|
1164
|
-
onSave:
|
|
1175
|
+
onSave: t8
|
|
1165
1176
|
});
|
|
1166
|
-
$[
|
|
1167
|
-
$[
|
|
1168
|
-
$[
|
|
1169
|
-
$[
|
|
1170
|
-
} else
|
|
1171
|
-
const t9 = page.metaDescription ?? "";
|
|
1177
|
+
$[15] = page.aiSeo;
|
|
1178
|
+
$[16] = t7;
|
|
1179
|
+
$[17] = t8;
|
|
1180
|
+
$[18] = t9;
|
|
1181
|
+
} else t9 = $[18];
|
|
1172
1182
|
let t10;
|
|
1173
|
-
if ($[
|
|
1174
|
-
t10 =
|
|
1183
|
+
if ($[19] !== findings) {
|
|
1184
|
+
t10 = /* @__PURE__ */ jsx(ContentFindings, {
|
|
1185
|
+
view: findings,
|
|
1186
|
+
field: "metaTitle",
|
|
1187
|
+
className: "space-y-2"
|
|
1188
|
+
});
|
|
1189
|
+
$[19] = findings;
|
|
1190
|
+
$[20] = t10;
|
|
1191
|
+
} else t10 = $[20];
|
|
1192
|
+
const t11 = page.metaDescription ?? "";
|
|
1193
|
+
let t12;
|
|
1194
|
+
if ($[21] !== page.id || $[22] !== setSeo) {
|
|
1195
|
+
t12 = (value_0) => setSeo.mutate({
|
|
1175
1196
|
id: page.id,
|
|
1176
1197
|
metaDescription: value_0
|
|
1177
1198
|
});
|
|
1178
|
-
$[
|
|
1179
|
-
$[
|
|
1180
|
-
$[
|
|
1181
|
-
} else
|
|
1182
|
-
let
|
|
1183
|
-
if ($[
|
|
1184
|
-
|
|
1199
|
+
$[21] = page.id;
|
|
1200
|
+
$[22] = setSeo;
|
|
1201
|
+
$[23] = t12;
|
|
1202
|
+
} else t12 = $[23];
|
|
1203
|
+
let t13;
|
|
1204
|
+
if ($[24] !== page.aiSeo || $[25] !== t11 || $[26] !== t12) {
|
|
1205
|
+
t13 = /* @__PURE__ */ jsx(DebouncedFieldEditor, {
|
|
1185
1206
|
label: "Page description",
|
|
1186
1207
|
placeholder: "Page description...",
|
|
1187
|
-
initialValue:
|
|
1208
|
+
initialValue: t11,
|
|
1188
1209
|
disabled: page.aiSeo,
|
|
1189
1210
|
rows: 2,
|
|
1190
|
-
onSave:
|
|
1211
|
+
onSave: t12
|
|
1191
1212
|
});
|
|
1192
|
-
$[
|
|
1193
|
-
$[
|
|
1194
|
-
$[22] = t9;
|
|
1195
|
-
$[23] = t11;
|
|
1196
|
-
} else t11 = $[23];
|
|
1197
|
-
let t12;
|
|
1198
|
-
if ($[24] !== localized || $[25] !== page.fullPath) {
|
|
1199
|
-
t12 = localized(page.fullPath);
|
|
1200
|
-
$[24] = localized;
|
|
1201
|
-
$[25] = page.fullPath;
|
|
1213
|
+
$[24] = page.aiSeo;
|
|
1214
|
+
$[25] = t11;
|
|
1202
1215
|
$[26] = t12;
|
|
1203
|
-
|
|
1204
|
-
|
|
1216
|
+
$[27] = t13;
|
|
1217
|
+
} else t13 = $[27];
|
|
1205
1218
|
let t14;
|
|
1206
|
-
if ($[
|
|
1207
|
-
t14 =
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
metaDescription: t13
|
|
1211
|
-
});
|
|
1212
|
-
$[27] = metaTitle;
|
|
1213
|
-
$[28] = t12;
|
|
1214
|
-
$[29] = t13;
|
|
1219
|
+
if ($[28] !== localized || $[29] !== page.fullPath) {
|
|
1220
|
+
t14 = localized(page.fullPath);
|
|
1221
|
+
$[28] = localized;
|
|
1222
|
+
$[29] = page.fullPath;
|
|
1215
1223
|
$[30] = t14;
|
|
1216
1224
|
} else t14 = $[30];
|
|
1217
1225
|
const t15 = page.metaDescription ?? "";
|
|
1218
1226
|
let t16;
|
|
1219
|
-
if ($[31] !== metaTitle || $[32] !==
|
|
1220
|
-
t16 = /* @__PURE__ */ jsx(
|
|
1221
|
-
|
|
1227
|
+
if ($[31] !== metaTitle || $[32] !== t14 || $[33] !== t15) {
|
|
1228
|
+
t16 = /* @__PURE__ */ jsx(SearchEnginePreview, {
|
|
1229
|
+
path: t14,
|
|
1222
1230
|
metaTitle,
|
|
1223
1231
|
metaDescription: t15
|
|
1224
1232
|
});
|
|
1225
1233
|
$[31] = metaTitle;
|
|
1226
|
-
$[32] =
|
|
1234
|
+
$[32] = t14;
|
|
1227
1235
|
$[33] = t15;
|
|
1228
1236
|
$[34] = t16;
|
|
1229
1237
|
} else t16 = $[34];
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1238
|
+
const t17 = page.metaDescription ?? "";
|
|
1239
|
+
let t18;
|
|
1240
|
+
if ($[35] !== metaTitle || $[36] !== page || $[37] !== t17) {
|
|
1241
|
+
t18 = /* @__PURE__ */ jsx(SocialPreviewSection, {
|
|
1242
|
+
page,
|
|
1243
|
+
metaTitle,
|
|
1244
|
+
metaDescription: t17
|
|
1245
|
+
});
|
|
1246
|
+
$[35] = metaTitle;
|
|
1247
|
+
$[36] = page;
|
|
1248
|
+
$[37] = t17;
|
|
1249
|
+
$[38] = t18;
|
|
1250
|
+
} else t18 = $[38];
|
|
1251
|
+
let t19;
|
|
1252
|
+
if ($[39] !== t10 || $[40] !== t13 || $[41] !== t16 || $[42] !== t18 || $[43] !== t6 || $[44] !== t9) {
|
|
1253
|
+
t19 = /* @__PURE__ */ jsxs("div", {
|
|
1233
1254
|
className: "space-y-4",
|
|
1234
1255
|
children: [
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
t16
|
|
1256
|
+
t6,
|
|
1257
|
+
t9,
|
|
1258
|
+
t10,
|
|
1259
|
+
t13,
|
|
1260
|
+
t16,
|
|
1261
|
+
t18
|
|
1240
1262
|
]
|
|
1241
1263
|
});
|
|
1242
|
-
$[
|
|
1243
|
-
$[
|
|
1244
|
-
$[
|
|
1245
|
-
$[
|
|
1246
|
-
$[
|
|
1247
|
-
$[
|
|
1248
|
-
|
|
1249
|
-
|
|
1264
|
+
$[39] = t10;
|
|
1265
|
+
$[40] = t13;
|
|
1266
|
+
$[41] = t16;
|
|
1267
|
+
$[42] = t18;
|
|
1268
|
+
$[43] = t6;
|
|
1269
|
+
$[44] = t9;
|
|
1270
|
+
$[45] = t19;
|
|
1271
|
+
} else t19 = $[45];
|
|
1272
|
+
return t19;
|
|
1250
1273
|
};
|
|
1251
1274
|
const PageMarkdownSheet = (t0) => {
|
|
1252
1275
|
const $ = c(8);
|
|
@@ -10,8 +10,8 @@ import { useEditingFrame } from "../editingFrame.js";
|
|
|
10
10
|
import { SelectionViewCount, SidebarStackHeader, SidebarStackView } from "./SidebarStack.js";
|
|
11
11
|
import { PreviewEditingOwnerContext } from "../previewSelection.js";
|
|
12
12
|
import { entityName } from "../entityName.js";
|
|
13
|
-
import { fieldTypesDictionary } from "../../../core/lib/fieldTypes.js";
|
|
14
13
|
import { ContentFindings, findingsHint, useContentFindings } from "../../studio/components/ContentFindings.js";
|
|
14
|
+
import { fieldTypesDictionary } from "../../../core/lib/fieldTypes.js";
|
|
15
15
|
import { usePageRecordPlacer } from "../pageRecord.js";
|
|
16
16
|
import { contentFieldNames, contentFieldSchema } from "./contentFieldSchema.js";
|
|
17
17
|
import { useRepeatableItemActions } from "./useRepeatableItemActions.js";
|
|
@@ -157,13 +157,24 @@ function createServerStudioCache(queryClient, { apiUrl, authCookieHeader, lookTo
|
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
159
159
|
* The locales of the scope a request reads: the URL's draft's for a session naming one, else
|
|
160
|
-
* Live's. A draft the API refuses reads Live's, as the request's other reads then do.
|
|
160
|
+
* Live's. A draft the API refuses reads Live's, as the request's other reads then do. Live's read
|
|
161
|
+
* keeps the session: a member's studio routes the locales Live doesn't serve yet, which visitors
|
|
162
|
+
* never see (ADR 0043), and a render with a session is private.
|
|
161
163
|
*/
|
|
162
164
|
async function readScopeLocales({ apiUrl, authCookieHeader, draftId, projectUuid }) {
|
|
163
|
-
const
|
|
164
|
-
authCookieHeader:
|
|
165
|
+
const list = (session, readDraftId) => createServerApiClient(apiUrl, {
|
|
166
|
+
authCookieHeader: session,
|
|
165
167
|
draftId: readDraftId
|
|
166
|
-
}).locales.list({ projectUuid })
|
|
168
|
+
}).locales.list({ projectUuid });
|
|
169
|
+
const { value } = await readDraftOrLive(draftId, !!authCookieHeader, async (readDraftId) => {
|
|
170
|
+
if (readDraftId || !authCookieHeader) return list(authCookieHeader, readDraftId);
|
|
171
|
+
try {
|
|
172
|
+
return await list(authCookieHeader, void 0);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (!isAuthSessionError(error)) throw error;
|
|
175
|
+
return list(void 0, void 0);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
167
178
|
return value;
|
|
168
179
|
}
|
|
169
180
|
/**
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { useOptionalDraftScope } from "../../lib/draft-scope.js";
|
|
2
|
+
import { useAuthContext, useSignInRedirect } from "../../lib/auth.js";
|
|
3
|
+
import { getApiClient } from "../../lib/api-client.js";
|
|
4
|
+
import { c } from "react/compiler-runtime";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { CLAIM_LINK_SEARCH_PARAM } from "@camox/api-contract/claim-links";
|
|
8
|
+
|
|
9
|
+
//#region src/features/runtime/ClaimCard.tsx
|
|
10
|
+
/** The page's URL without the Claim Link's token, which would reopen the card. */
|
|
11
|
+
function pageWithoutToken() {
|
|
12
|
+
const url = new URL(window.location.href);
|
|
13
|
+
url.searchParams.delete(CLAIM_LINK_SEARCH_PARAM);
|
|
14
|
+
return url.href;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The claim card, on a page opened from a Claim Link: who built the website for whom, with a
|
|
18
|
+
* button to claim it, or why it can't be claimed. A member of the website's organization sees it
|
|
19
|
+
* as a preview. Nothing shows without a token, or in a draft.
|
|
20
|
+
*/
|
|
21
|
+
function ClaimCard() {
|
|
22
|
+
const $ = c(15);
|
|
23
|
+
const [token, setToken] = React.useState(null);
|
|
24
|
+
const [opening, setOpening] = React.useState(null);
|
|
25
|
+
const [closed, setClosed] = React.useState(false);
|
|
26
|
+
const { authenticationUrl } = useAuthContext();
|
|
27
|
+
const signIn = useSignInRedirect(pageWithoutToken);
|
|
28
|
+
const inDraft = useOptionalDraftScope().draftId !== null;
|
|
29
|
+
let t0;
|
|
30
|
+
let t1;
|
|
31
|
+
if ($[0] !== inDraft) {
|
|
32
|
+
t0 = () => {
|
|
33
|
+
if (inDraft) return;
|
|
34
|
+
const found = new URL(window.location.href).searchParams.get(CLAIM_LINK_SEARCH_PARAM);
|
|
35
|
+
if (!found) return;
|
|
36
|
+
setToken(found);
|
|
37
|
+
let current = true;
|
|
38
|
+
getApiClient().claimLinks.open({ token: found }).then((opened) => current && setOpening(opened), _temp);
|
|
39
|
+
return () => {
|
|
40
|
+
current = false;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
t1 = [inDraft];
|
|
44
|
+
$[0] = inDraft;
|
|
45
|
+
$[1] = t0;
|
|
46
|
+
$[2] = t1;
|
|
47
|
+
} else {
|
|
48
|
+
t0 = $[1];
|
|
49
|
+
t1 = $[2];
|
|
50
|
+
}
|
|
51
|
+
React.useEffect(t0, t1);
|
|
52
|
+
if (inDraft || !token || !opening || closed) return null;
|
|
53
|
+
let t2;
|
|
54
|
+
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
|
55
|
+
t2 = () => {
|
|
56
|
+
window.history.replaceState(window.history.state, "", pageWithoutToken());
|
|
57
|
+
setClosed(true);
|
|
58
|
+
};
|
|
59
|
+
$[3] = t2;
|
|
60
|
+
} else t2 = $[3];
|
|
61
|
+
const close = t2;
|
|
62
|
+
let t3;
|
|
63
|
+
if ($[4] !== authenticationUrl || $[5] !== token) {
|
|
64
|
+
t3 = () => {
|
|
65
|
+
const destination = new URL("/claim", authenticationUrl);
|
|
66
|
+
destination.searchParams.set("token", token);
|
|
67
|
+
destination.searchParams.set("callback", pageWithoutToken());
|
|
68
|
+
window.location.href = destination.href;
|
|
69
|
+
};
|
|
70
|
+
$[4] = authenticationUrl;
|
|
71
|
+
$[5] = token;
|
|
72
|
+
$[6] = t3;
|
|
73
|
+
} else t3 = $[6];
|
|
74
|
+
const claim = t3;
|
|
75
|
+
let t4;
|
|
76
|
+
let t5;
|
|
77
|
+
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
78
|
+
t4 = /* @__PURE__ */ jsx("style", { children: claimCardStyles });
|
|
79
|
+
t5 = /* @__PURE__ */ jsx("button", {
|
|
80
|
+
type: "button",
|
|
81
|
+
className: "camox-claim-close",
|
|
82
|
+
"aria-label": "Close",
|
|
83
|
+
onClick: close,
|
|
84
|
+
children: "×"
|
|
85
|
+
});
|
|
86
|
+
$[7] = t4;
|
|
87
|
+
$[8] = t5;
|
|
88
|
+
} else {
|
|
89
|
+
t4 = $[7];
|
|
90
|
+
t5 = $[8];
|
|
91
|
+
}
|
|
92
|
+
let t6;
|
|
93
|
+
if ($[9] !== claim || $[10] !== opening.operatorName || $[11] !== opening.organizationName || $[12] !== opening.state || $[13] !== signIn) {
|
|
94
|
+
t6 = /* @__PURE__ */ jsxs("aside", {
|
|
95
|
+
className: "camox-claim-card",
|
|
96
|
+
"aria-label": "Claim this website",
|
|
97
|
+
children: [
|
|
98
|
+
t4,
|
|
99
|
+
t5,
|
|
100
|
+
opening.state === "open" || opening.state === "preview" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
101
|
+
opening.state === "preview" && /* @__PURE__ */ jsx("span", {
|
|
102
|
+
className: "camox-claim-preview",
|
|
103
|
+
children: "Preview: this is the card whoever you send the link to sees"
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
106
|
+
opening.operatorName,
|
|
107
|
+
" from Camox built this website for ",
|
|
108
|
+
opening.organizationName,
|
|
109
|
+
". Claim it to start editing."
|
|
110
|
+
] }),
|
|
111
|
+
opening.state === "open" && /* @__PURE__ */ jsx("button", {
|
|
112
|
+
type: "button",
|
|
113
|
+
className: "camox-claim-action",
|
|
114
|
+
onClick: claim,
|
|
115
|
+
children: "Claim website"
|
|
116
|
+
})
|
|
117
|
+
] }) : opening.state === "claimed" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", { children: "This website has been claimed." }), /* @__PURE__ */ jsx("button", {
|
|
118
|
+
type: "button",
|
|
119
|
+
className: "camox-claim-action",
|
|
120
|
+
onClick: signIn,
|
|
121
|
+
children: "Sign in"
|
|
122
|
+
})] }) : /* @__PURE__ */ jsx("p", { children: "This link no longer works. Ask whoever sent it for a new one." })
|
|
123
|
+
]
|
|
124
|
+
});
|
|
125
|
+
$[9] = claim;
|
|
126
|
+
$[10] = opening.operatorName;
|
|
127
|
+
$[11] = opening.organizationName;
|
|
128
|
+
$[12] = opening.state;
|
|
129
|
+
$[13] = signIn;
|
|
130
|
+
$[14] = t6;
|
|
131
|
+
} else t6 = $[14];
|
|
132
|
+
return t6;
|
|
133
|
+
}
|
|
134
|
+
function _temp(error) {
|
|
135
|
+
return console.error("The Claim Link couldn't be opened", error);
|
|
136
|
+
}
|
|
137
|
+
const claimCardStyles = `
|
|
138
|
+
.camox-claim-card {
|
|
139
|
+
background: #09090b;
|
|
140
|
+
border: 1px solid #27272a;
|
|
141
|
+
border-radius: 12px;
|
|
142
|
+
bottom: 24px;
|
|
143
|
+
box-shadow: 0 10px 30px rgb(0 0 0 / 0.35);
|
|
144
|
+
box-sizing: border-box;
|
|
145
|
+
color: #fafafa;
|
|
146
|
+
color-scheme: dark;
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: column;
|
|
149
|
+
font: 15px/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
|
|
150
|
+
gap: 12px;
|
|
151
|
+
max-width: min(24rem, calc(100vw - 32px));
|
|
152
|
+
padding: 20px 44px 20px 20px;
|
|
153
|
+
position: fixed;
|
|
154
|
+
right: 16px;
|
|
155
|
+
text-align: left;
|
|
156
|
+
z-index: 2147483647;
|
|
157
|
+
}
|
|
158
|
+
.camox-claim-card p { margin: 0; }
|
|
159
|
+
.camox-claim-card button { cursor: pointer; font: inherit; }
|
|
160
|
+
.camox-claim-card .camox-claim-close {
|
|
161
|
+
background: none;
|
|
162
|
+
border: 0;
|
|
163
|
+
color: #a1a1aa;
|
|
164
|
+
font-size: 20px;
|
|
165
|
+
line-height: 1;
|
|
166
|
+
padding: 4px 8px;
|
|
167
|
+
position: absolute;
|
|
168
|
+
right: 8px;
|
|
169
|
+
top: 8px;
|
|
170
|
+
}
|
|
171
|
+
.camox-claim-card .camox-claim-close:hover { color: #fafafa; }
|
|
172
|
+
.camox-claim-card .camox-claim-preview {
|
|
173
|
+
align-self: flex-start;
|
|
174
|
+
background: #27272a;
|
|
175
|
+
border-radius: 999px;
|
|
176
|
+
color: #d4d4d8;
|
|
177
|
+
font-size: 12px;
|
|
178
|
+
padding: 2px 10px;
|
|
179
|
+
}
|
|
180
|
+
.camox-claim-card .camox-claim-action {
|
|
181
|
+
align-self: flex-start;
|
|
182
|
+
background: #fafafa;
|
|
183
|
+
border: 0;
|
|
184
|
+
border-radius: 8px;
|
|
185
|
+
color: #09090b;
|
|
186
|
+
font-weight: 600;
|
|
187
|
+
padding: 8px 14px;
|
|
188
|
+
}
|
|
189
|
+
`;
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
export { ClaimCard };
|
|
@@ -11,12 +11,13 @@ import { CuratedPageContent } from "../page/CuratedPageContent.js";
|
|
|
11
11
|
import { DerivedPageContent } from "../page/DerivedPageContent.js";
|
|
12
12
|
import { UnplacedBlockContent } from "../page/UnplacedBlockContent.js";
|
|
13
13
|
import { UnplacedLayoutContent } from "../page/UnplacedLayoutContent.js";
|
|
14
|
+
import { ClaimCard } from "./ClaimCard.js";
|
|
14
15
|
import { EditingFallbackSlot } from "./editingFallback.js";
|
|
15
16
|
import { PageNavigationProvider } from "./pageNavigation.js";
|
|
16
17
|
import { RuntimeChromeSlot } from "./runtimeChromeLoader.js";
|
|
17
18
|
import { c } from "react/compiler-runtime";
|
|
18
19
|
import * as React from "react";
|
|
19
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
20
21
|
import { HydrationBoundary, QueryClientProvider } from "@tanstack/react-query";
|
|
21
22
|
|
|
22
23
|
//#region src/features/runtime/pageApp.tsx
|
|
@@ -43,12 +44,12 @@ function PageApp(t0) {
|
|
|
43
44
|
camoxApp,
|
|
44
45
|
input: currentInput
|
|
45
46
|
})
|
|
46
|
-
}) : /* @__PURE__ */ jsx(PageExperience, {
|
|
47
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PageExperience, {
|
|
47
48
|
camoxApp,
|
|
48
49
|
input: currentInput,
|
|
49
50
|
queryClient,
|
|
50
51
|
studioDocument: input.presentation === "studio"
|
|
51
|
-
})
|
|
52
|
+
}), /* @__PURE__ */ jsx(ClaimCard, {})] })
|
|
52
53
|
})
|
|
53
54
|
});
|
|
54
55
|
$[0] = camoxApp;
|
|
@@ -918,6 +918,25 @@ function visitorAnalytics(render, project) {
|
|
|
918
918
|
if (render.studio || render.draftId) return void 0;
|
|
919
919
|
return configuredProviders(project.analytics);
|
|
920
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* A project waiting to be claimed keeps search engines away from its pages, so the copy an
|
|
923
|
+
* operator built doesn't compete with the customer's current website. APIs older than Claim Links
|
|
924
|
+
* don't say, and their projects are indexed.
|
|
925
|
+
*/
|
|
926
|
+
function isHiddenFromSearchEngines(project) {
|
|
927
|
+
return project.hiddenFromSearchEngines === true;
|
|
928
|
+
}
|
|
929
|
+
/** A page's head, with the robots `noindex` meta tag when its project is hidden. */
|
|
930
|
+
function withSearchEngineMark(head, project) {
|
|
931
|
+
if (!head || !isHiddenFromSearchEngines(project)) return head;
|
|
932
|
+
return {
|
|
933
|
+
...head,
|
|
934
|
+
meta: [...head.meta ?? [], {
|
|
935
|
+
name: "robots",
|
|
936
|
+
content: "noindex"
|
|
937
|
+
}]
|
|
938
|
+
};
|
|
939
|
+
}
|
|
921
940
|
/** Whether a request is a preview link's token handoff, which signs in before reading anything. */
|
|
922
941
|
function isPreviewHandoff(request, options) {
|
|
923
942
|
const { searchParams } = new URL(request.url);
|
|
@@ -1247,13 +1266,14 @@ async function createPageHtmlResponse({ options, pathname, located, request, pag
|
|
|
1247
1266
|
if (result.shouldClearAuthCookie) headers.append("Set-Cookie", buildClearServerAuthCookieHeader());
|
|
1248
1267
|
const camoxApp = await options.getCamoxApp?.();
|
|
1249
1268
|
const document = await options.getDocument?.() ?? {};
|
|
1269
|
+
if (isHiddenFromSearchEngines(result.data.page.project)) headers.set("X-Robots-Tag", "noindex");
|
|
1250
1270
|
const { alternates, head } = await readAlternates(request, options, {
|
|
1251
1271
|
located,
|
|
1252
1272
|
identity: {
|
|
1253
1273
|
kind: "curated",
|
|
1254
1274
|
pageId: result.data.page.page.id
|
|
1255
1275
|
},
|
|
1256
|
-
head: camoxApp ? buildCamoxPageHead(camoxApp, result.data, located.locale) : {},
|
|
1276
|
+
head: withSearchEngineMark(camoxApp ? buildCamoxPageHead(camoxApp, result.data, located.locale) : {}, result.data.page.project),
|
|
1257
1277
|
described: curatedPageDescription(camoxApp, result.data.page, located.locale),
|
|
1258
1278
|
localeReads: localeReads(result.draftId)
|
|
1259
1279
|
});
|
|
@@ -1559,14 +1579,14 @@ async function createDerivedResponse(options, pathname, located, request, { data
|
|
|
1559
1579
|
layout: match.layout,
|
|
1560
1580
|
recordId: record.data.id
|
|
1561
1581
|
} : { kind: "code-owned" },
|
|
1562
|
-
head: buildPageHead({
|
|
1582
|
+
head: withSearchEngineMark(buildPageHead({
|
|
1563
1583
|
layout: match.layout._internal,
|
|
1564
1584
|
context,
|
|
1565
1585
|
origin: new URL(request.url).origin,
|
|
1566
1586
|
faviconUrl: buildFaviconUrl(options.apiUrl, shared.project),
|
|
1567
1587
|
hasMarkdown: match.layout._internal.toMarkdown !== void 0,
|
|
1568
1588
|
recordType: record?.structuredData?.node?.["@type"]
|
|
1569
|
-
}),
|
|
1589
|
+
}), shared.project),
|
|
1570
1590
|
described: {
|
|
1571
1591
|
project: {
|
|
1572
1592
|
...shared.project,
|
|
@@ -1638,7 +1658,8 @@ async function createDerivedResponse(options, pathname, located, request, { data
|
|
|
1638
1658
|
Vary: "Cookie",
|
|
1639
1659
|
Link: llmsTxtLinkHeader(options),
|
|
1640
1660
|
...isPrivateRender(request) ? { "Cache-Control": "private, no-store" } : {},
|
|
1641
|
-
...clearAuthCookie ? { "Set-Cookie": buildClearServerAuthCookieHeader() } : {}
|
|
1661
|
+
...clearAuthCookie ? { "Set-Cookie": buildClearServerAuthCookieHeader() } : {},
|
|
1662
|
+
...isHiddenFromSearchEngines(shared.project) && { "X-Robots-Tag": "noindex" }
|
|
1642
1663
|
} });
|
|
1643
1664
|
} catch (error) {
|
|
1644
1665
|
if (isNotFoundError(error)) return new Response("Page not found", { status: 404 });
|
|
@@ -1770,7 +1791,7 @@ async function createPageDataResponse({ options, pathname, located, request, pag
|
|
|
1770
1791
|
kind: "curated",
|
|
1771
1792
|
pageId: result.data.page.page.id
|
|
1772
1793
|
},
|
|
1773
|
-
head: camoxApp ? buildCamoxPageHead(camoxApp, result.data, located.locale) : null,
|
|
1794
|
+
head: withSearchEngineMark(camoxApp ? buildCamoxPageHead(camoxApp, result.data, located.locale) : null, result.data.page.project),
|
|
1774
1795
|
described: curatedPageDescription(camoxApp, result.data.page, located.locale),
|
|
1775
1796
|
localeReads: localeReads(result.draftId)
|
|
1776
1797
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PUBLIC_CACHE_NAME, fetchLocalhostOnLoopback, readLiveCacheKey, rememberPublishingDraft, respondThroughPublicCache, shouldHandleRequest, withDevHtml } from "camox/_internal/workerRuntime";
|
|
1
|
+
import { PUBLIC_CACHE_NAME, fetchLocalhostOnLoopback, readLiveCacheKey, rememberPublishingDraft, respondThroughPublicCache, shouldHandleRequest, withDevHtml, withoutClaimLinkToken } from "camox/_internal/workerRuntime";
|
|
2
2
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
3
3
|
import { devHtml, handleCamoxRequest, isPublicRequest, publicCacheSource, readDefinitionSet, runtimeBasePath } from "virtual:camox/server";
|
|
4
4
|
|
|
@@ -41,7 +41,7 @@ var CamoxDefinitionSet = class extends WorkerEntrypoint {
|
|
|
41
41
|
var worker_default = { async fetch(request, env, context) {
|
|
42
42
|
rememberPublishingDraft(env);
|
|
43
43
|
if (!shouldHandleRequest(request, runtimeBasePath)) return notFound();
|
|
44
|
-
const response = await respond(request, context);
|
|
44
|
+
const response = await respond(withoutClaimLinkToken(request), context);
|
|
45
45
|
if (!response) return notFound();
|
|
46
46
|
return withDevHtml(response, devHtml);
|
|
47
47
|
} };
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
//#region src/features/runtime/workerRequest.d.ts
|
|
2
2
|
export declare function shouldHandleRequest(request: Request, basePath: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The request without a Claim Link's token, which only the claim card reads, in the browser. The
|
|
5
|
+
* page renders and is kept in the edge cache as if the visitor came without it, so the token
|
|
6
|
+
* never reaches the cache key or the rendered page.
|
|
7
|
+
*/
|
|
8
|
+
export declare function withoutClaimLinkToken(request: Request): Request;
|
|
3
9
|
/** Adds what Vite injects into HTML in dev, such as its client and React Refresh. */
|
|
4
10
|
export declare function withDevHtml(response: Response, html: {
|
|
5
11
|
head: string;
|