@blinkk/root-cms 1.0.0-beta.24 → 1.0.0-beta.26
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/plugin.js +42 -9
- package/dist/ui/ui.css +41 -0
- package/dist/ui/ui.js +494 -153
- package/package.json +6 -3
package/dist/ui/ui.js
CHANGED
|
@@ -38205,7 +38205,7 @@ ${this.customData.serverResponse}`;
|
|
|
38205
38205
|
// package.json
|
|
38206
38206
|
var package_default = {
|
|
38207
38207
|
name: "@blinkk/root-cms",
|
|
38208
|
-
version: "1.0.0-beta.
|
|
38208
|
+
version: "1.0.0-beta.26",
|
|
38209
38209
|
author: "s@blinkk.com",
|
|
38210
38210
|
license: "MIT",
|
|
38211
38211
|
engines: {
|
|
@@ -38254,12 +38254,14 @@ ${this.customData.serverResponse}`;
|
|
|
38254
38254
|
"body-parser": "^1.20.0",
|
|
38255
38255
|
commander: "^10.0.0",
|
|
38256
38256
|
"cookie-parser": "^1.4.6",
|
|
38257
|
+
"csv-parse": "^5.3.8",
|
|
38257
38258
|
"csv-stringify": "^6.3.2",
|
|
38258
38259
|
dotenv: "^16.0.0",
|
|
38259
38260
|
"dts-dom": "^3.7.0",
|
|
38260
38261
|
"firebase-admin": "^11.5.0",
|
|
38261
38262
|
"js-beautify": "^1.14.7",
|
|
38262
38263
|
kleur: "^4.1.5",
|
|
38264
|
+
multer: "1.4.5-lts.1",
|
|
38263
38265
|
"preact-render-to-string": "^5.2.3",
|
|
38264
38266
|
sirv: "^2.0.2",
|
|
38265
38267
|
"tiny-glob": "^0.2.9"
|
|
@@ -38281,6 +38283,7 @@ ${this.customData.serverResponse}`;
|
|
|
38281
38283
|
"@types/cookie-parser": "^1.4.3",
|
|
38282
38284
|
"@types/jsonwebtoken": "^9.0.1",
|
|
38283
38285
|
"@types/marked": "^4.0.8",
|
|
38286
|
+
"@types/multer": "^1.4.7",
|
|
38284
38287
|
"@types/node": "^18.11.8",
|
|
38285
38288
|
concurrently: "^7.6.0",
|
|
38286
38289
|
esbuild: "0.17.12",
|
|
@@ -38296,7 +38299,7 @@ ${this.customData.serverResponse}`;
|
|
|
38296
38299
|
vitest: "^0.18.1"
|
|
38297
38300
|
},
|
|
38298
38301
|
peerDependencies: {
|
|
38299
|
-
"@blinkk/root": "1.0.0-beta.
|
|
38302
|
+
"@blinkk/root": "1.0.0-beta.26",
|
|
38300
38303
|
"firebase-admin": ">=11",
|
|
38301
38304
|
preact: "*"
|
|
38302
38305
|
}
|
|
@@ -38417,6 +38420,19 @@ ${this.customData.serverResponse}`;
|
|
|
38417
38420
|
] }) });
|
|
38418
38421
|
}
|
|
38419
38422
|
|
|
38423
|
+
// ui/utils/l10n.ts
|
|
38424
|
+
async function sourceHash(str) {
|
|
38425
|
+
return sha1(str);
|
|
38426
|
+
}
|
|
38427
|
+
async function sha1(str) {
|
|
38428
|
+
const encoder = new TextEncoder();
|
|
38429
|
+
const data = encoder.encode(str);
|
|
38430
|
+
const hash5 = await crypto.subtle.digest("SHA-1", data);
|
|
38431
|
+
const hashArray = Array.from(new Uint8Array(hash5));
|
|
38432
|
+
const hex = hashArray.map((b6) => b6.toString(16).padStart(2, "0")).join("");
|
|
38433
|
+
return hex;
|
|
38434
|
+
}
|
|
38435
|
+
|
|
38420
38436
|
// ui/utils/doc.ts
|
|
38421
38437
|
async function cmsDeleteDoc(docId) {
|
|
38422
38438
|
const projectId = window.__ROOT_CTX.rootConfig.projectId;
|
|
@@ -38468,7 +38484,7 @@ ${this.customData.serverResponse}`;
|
|
|
38468
38484
|
slug
|
|
38469
38485
|
);
|
|
38470
38486
|
await lf(db3, async (transaction) => {
|
|
38471
|
-
const draftDoc = await
|
|
38487
|
+
const draftDoc = await transaction.get(draftDocRef);
|
|
38472
38488
|
if (!draftDoc.exists()) {
|
|
38473
38489
|
throw new Error(`${draftDocRef.id} does not exist`);
|
|
38474
38490
|
}
|
|
@@ -38484,6 +38500,114 @@ ${this.customData.serverResponse}`;
|
|
|
38484
38500
|
transaction.delete(publishedDocRef);
|
|
38485
38501
|
});
|
|
38486
38502
|
}
|
|
38503
|
+
async function cmsCopyDoc(fromDocId, toDocId) {
|
|
38504
|
+
const fromDocRef = getDocRef(fromDocId);
|
|
38505
|
+
const fromDoc = await Kl(fromDocRef);
|
|
38506
|
+
if (!fromDoc.exists()) {
|
|
38507
|
+
throw new Error(`doc ${fromDocId} does not exist`);
|
|
38508
|
+
}
|
|
38509
|
+
const fields = fromDoc.data().fields ?? {};
|
|
38510
|
+
await cmsCreateDoc(toDocId, { fields });
|
|
38511
|
+
}
|
|
38512
|
+
async function cmsCreateDoc(docId, options2) {
|
|
38513
|
+
const [collectionId, slug] = docId.split("/");
|
|
38514
|
+
const docRef = getDocRef(docId);
|
|
38515
|
+
const doc = await Kl(docRef);
|
|
38516
|
+
if (doc.exists()) {
|
|
38517
|
+
throw new Error(`${docId} already exists`);
|
|
38518
|
+
}
|
|
38519
|
+
const data = {
|
|
38520
|
+
id: docId,
|
|
38521
|
+
collection: collectionId,
|
|
38522
|
+
slug,
|
|
38523
|
+
sys: {
|
|
38524
|
+
createdAt: df(),
|
|
38525
|
+
createdBy: window.firebase.user.email,
|
|
38526
|
+
modifiedAt: df(),
|
|
38527
|
+
modifiedBy: window.firebase.user.email
|
|
38528
|
+
},
|
|
38529
|
+
fields: options2?.fields ?? {}
|
|
38530
|
+
};
|
|
38531
|
+
await Jl(docRef, data);
|
|
38532
|
+
}
|
|
38533
|
+
async function cmsDocImportCsv(docId, csvData) {
|
|
38534
|
+
const translationsDocRef = getTranslationsDocRef(docId);
|
|
38535
|
+
const translationsMap = {};
|
|
38536
|
+
const i18nConfig = window.__ROOT_CTX.rootConfig.i18n || {};
|
|
38537
|
+
const i18nLocales = i18nConfig.locales || ["en"];
|
|
38538
|
+
function normalizeStr(str) {
|
|
38539
|
+
return String(str).trim();
|
|
38540
|
+
}
|
|
38541
|
+
function normalizeLocale(locale) {
|
|
38542
|
+
for (const l6 of i18nLocales) {
|
|
38543
|
+
if (String(l6).toLowerCase() === locale.toLowerCase()) {
|
|
38544
|
+
return l6;
|
|
38545
|
+
}
|
|
38546
|
+
}
|
|
38547
|
+
return locale;
|
|
38548
|
+
}
|
|
38549
|
+
for (const row of csvData) {
|
|
38550
|
+
if (!row.source) {
|
|
38551
|
+
continue;
|
|
38552
|
+
}
|
|
38553
|
+
const translation = {
|
|
38554
|
+
source: normalizeStr(row.source)
|
|
38555
|
+
};
|
|
38556
|
+
Object.entries(row).forEach(([column3, str]) => {
|
|
38557
|
+
if (column3 === "source") {
|
|
38558
|
+
return;
|
|
38559
|
+
}
|
|
38560
|
+
const locale = normalizeLocale(column3);
|
|
38561
|
+
translation[locale] = normalizeStr(str || "");
|
|
38562
|
+
});
|
|
38563
|
+
const hash5 = await sourceHash(translation.source);
|
|
38564
|
+
translationsMap[hash5] = translation;
|
|
38565
|
+
}
|
|
38566
|
+
const db3 = window.firebase.db;
|
|
38567
|
+
await lf(db3, async (transaction) => {
|
|
38568
|
+
const translationsDoc = await transaction.get(translationsDocRef);
|
|
38569
|
+
const currentData = translationsDoc.data() || {};
|
|
38570
|
+
const data = { ...currentData };
|
|
38571
|
+
data.sys = {
|
|
38572
|
+
...data.sys ?? {},
|
|
38573
|
+
modifiedAt: df(),
|
|
38574
|
+
modifiedBy: window.firebase.user.email
|
|
38575
|
+
};
|
|
38576
|
+
data.translations = {
|
|
38577
|
+
...data.translations ?? {},
|
|
38578
|
+
...translationsMap
|
|
38579
|
+
};
|
|
38580
|
+
transaction.set(translationsDocRef, data);
|
|
38581
|
+
});
|
|
38582
|
+
}
|
|
38583
|
+
function getDocRef(docId) {
|
|
38584
|
+
const projectId = window.__ROOT_CTX.rootConfig.projectId;
|
|
38585
|
+
const db3 = window.firebase.db;
|
|
38586
|
+
const [collectionId, slug] = docId.split("/");
|
|
38587
|
+
return Za(
|
|
38588
|
+
db3,
|
|
38589
|
+
"Projects",
|
|
38590
|
+
projectId,
|
|
38591
|
+
"Collections",
|
|
38592
|
+
collectionId,
|
|
38593
|
+
"Drafts",
|
|
38594
|
+
slug
|
|
38595
|
+
);
|
|
38596
|
+
}
|
|
38597
|
+
function getTranslationsDocRef(docId) {
|
|
38598
|
+
const projectId = window.__ROOT_CTX.rootConfig.projectId;
|
|
38599
|
+
const db3 = window.firebase.db;
|
|
38600
|
+
const [collectionId, slug] = docId.split("/");
|
|
38601
|
+
return Za(
|
|
38602
|
+
db3,
|
|
38603
|
+
"Projects",
|
|
38604
|
+
projectId,
|
|
38605
|
+
"Collections",
|
|
38606
|
+
collectionId,
|
|
38607
|
+
"Translations",
|
|
38608
|
+
slug
|
|
38609
|
+
);
|
|
38610
|
+
}
|
|
38487
38611
|
|
|
38488
38612
|
// ui/components/DocActionsMenu/DocActionsMenu.tsx
|
|
38489
38613
|
function DocActionsMenu(props) {
|
|
@@ -38491,13 +38615,15 @@ ${this.customData.serverResponse}`;
|
|
|
38491
38615
|
const data = props.data || {};
|
|
38492
38616
|
const sys = data.sys || {};
|
|
38493
38617
|
const modals = useModals();
|
|
38618
|
+
const theme = useMantineTheme();
|
|
38494
38619
|
const onCopyDoc = () => {
|
|
38495
|
-
|
|
38496
|
-
|
|
38497
|
-
|
|
38498
|
-
|
|
38499
|
-
|
|
38500
|
-
|
|
38620
|
+
modals.openContextModal("copyDoc", {
|
|
38621
|
+
title: "Copy",
|
|
38622
|
+
overlayColor: theme.colorScheme === "dark" ? theme.colors.dark[9] : theme.colors.gray[2],
|
|
38623
|
+
innerProps: {
|
|
38624
|
+
fromDocId: docId
|
|
38625
|
+
}
|
|
38626
|
+
});
|
|
38501
38627
|
};
|
|
38502
38628
|
const onUnpublishDoc = () => {
|
|
38503
38629
|
const notificationId = `unpublish-doc-${docId}`;
|
|
@@ -40837,12 +40963,106 @@ ${content}</tr>
|
|
|
40837
40963
|
);
|
|
40838
40964
|
}
|
|
40839
40965
|
|
|
40840
|
-
// ui/
|
|
40966
|
+
// ui/utils/slug.ts
|
|
40841
40967
|
function isSlugValid(slug) {
|
|
40842
40968
|
return Boolean(slug && slug.match(/^[a-z0-9]+(?:--?[a-z0-9]+)*$/));
|
|
40843
40969
|
}
|
|
40844
40970
|
function normalizeSlug(slug) {
|
|
40845
|
-
return slug.replace(/^[\s/]*/g, "").replace(/[\s/]*$/g, "").toLowerCase().replaceAll("/", "--");
|
|
40971
|
+
return slug.replace(/^[\s/]*/g, "").replace(/[\s/]*$/g, "").replace(/^\/+|\/+$/g, "").toLowerCase().replaceAll("/", "--");
|
|
40972
|
+
}
|
|
40973
|
+
|
|
40974
|
+
// ui/components/SlugInput/SlugInput.tsx
|
|
40975
|
+
function SlugInput(props) {
|
|
40976
|
+
const [collectionId, setCollectionId] = y2(props.collectionId || "");
|
|
40977
|
+
const slugRef = A2(null);
|
|
40978
|
+
const [slug, setSlug] = y2("");
|
|
40979
|
+
const rootCollection = window.__ROOT_CTX.collections[collectionId];
|
|
40980
|
+
const collectionOptions = [];
|
|
40981
|
+
if (props.collectionId && props.collectionDisabled) {
|
|
40982
|
+
collectionOptions.push({
|
|
40983
|
+
value: props.collectionId,
|
|
40984
|
+
label: props.collectionId
|
|
40985
|
+
});
|
|
40986
|
+
} else {
|
|
40987
|
+
Object.keys(window.__ROOT_CTX.collections).forEach((id2) => {
|
|
40988
|
+
collectionOptions.push({
|
|
40989
|
+
value: id2,
|
|
40990
|
+
label: id2
|
|
40991
|
+
});
|
|
40992
|
+
});
|
|
40993
|
+
}
|
|
40994
|
+
const domain2 = window.__ROOT_CTX.rootConfig?.domain || "https://example.com";
|
|
40995
|
+
let urlHelp = "";
|
|
40996
|
+
if (rootCollection?.url) {
|
|
40997
|
+
if (slug) {
|
|
40998
|
+
const cleanSlug = normalizeSlug(slug);
|
|
40999
|
+
if (isSlugValid(cleanSlug)) {
|
|
41000
|
+
const cleanSlugPath = cleanSlug.replaceAll("--", "/");
|
|
41001
|
+
let urlPath = rootCollection.url.replace(/\[.*slug\]/, cleanSlugPath);
|
|
41002
|
+
if (urlPath === "/index") {
|
|
41003
|
+
urlPath = "/";
|
|
41004
|
+
}
|
|
41005
|
+
urlHelp = `${domain2}${urlPath}`;
|
|
41006
|
+
} else {
|
|
41007
|
+
urlHelp = "INVALID SLUG";
|
|
41008
|
+
}
|
|
41009
|
+
} else {
|
|
41010
|
+
urlHelp = `${domain2}${rootCollection.url}`;
|
|
41011
|
+
}
|
|
41012
|
+
}
|
|
41013
|
+
function onCollectionChange(newCollectionId) {
|
|
41014
|
+
setCollectionId(newCollectionId);
|
|
41015
|
+
if (props.onChange) {
|
|
41016
|
+
props.onChange({ collectionId: newCollectionId, slug });
|
|
41017
|
+
}
|
|
41018
|
+
}
|
|
41019
|
+
function onSlugChange(newSlug) {
|
|
41020
|
+
setSlug(newSlug);
|
|
41021
|
+
if (props.onChange) {
|
|
41022
|
+
props.onChange({ collectionId, slug: newSlug });
|
|
41023
|
+
}
|
|
41024
|
+
}
|
|
41025
|
+
return /* @__PURE__ */ o4("div", { className: joinClassNames(props.className, "SlugInput"), children: [
|
|
41026
|
+
/* @__PURE__ */ o4("div", { className: "SlugInput__inputs", children: [
|
|
41027
|
+
/* @__PURE__ */ o4(
|
|
41028
|
+
Select,
|
|
41029
|
+
{
|
|
41030
|
+
className: "SlugInput__collection",
|
|
41031
|
+
placeholder: "Collection",
|
|
41032
|
+
size: "xs",
|
|
41033
|
+
data: collectionOptions,
|
|
41034
|
+
onChange: (newValue) => onCollectionChange(newValue),
|
|
41035
|
+
value: collectionId,
|
|
41036
|
+
disabled: !!props.collectionDisabled
|
|
41037
|
+
}
|
|
41038
|
+
),
|
|
41039
|
+
/* @__PURE__ */ o4("div", { className: "SlugInput__divider", children: "/" }),
|
|
41040
|
+
/* @__PURE__ */ o4(
|
|
41041
|
+
TextInput,
|
|
41042
|
+
{
|
|
41043
|
+
className: "SlugInput__slug",
|
|
41044
|
+
name: "slug",
|
|
41045
|
+
ref: slugRef,
|
|
41046
|
+
value: slug,
|
|
41047
|
+
onChange: (event) => {
|
|
41048
|
+
onSlugChange(event.currentTarget.value);
|
|
41049
|
+
},
|
|
41050
|
+
placeholder: "slug",
|
|
41051
|
+
autoComplete: "off",
|
|
41052
|
+
size: "xs"
|
|
41053
|
+
}
|
|
41054
|
+
)
|
|
41055
|
+
] }),
|
|
41056
|
+
urlHelp && /* @__PURE__ */ o4(Text2, { className: "SlugInput__urlHelp", size: "body-sm", children: urlHelp })
|
|
41057
|
+
] });
|
|
41058
|
+
}
|
|
41059
|
+
|
|
41060
|
+
// ui/components/NewDocModal/NewDocModal.tsx
|
|
41061
|
+
function isSlugValid2(slug) {
|
|
41062
|
+
return Boolean(slug && slug.match(/^[a-z0-9]+(?:--?[a-z0-9]+)*$/));
|
|
41063
|
+
}
|
|
41064
|
+
function normalizeSlug2(slug) {
|
|
41065
|
+
return slug.replace(/^[\s/]*/g, "").replace(/[\s/]*$/g, "").replace(/^\/+|\/+$/g, "").toLowerCase().replaceAll("/", "--");
|
|
40846
41066
|
}
|
|
40847
41067
|
function getDefaultFields(collection) {
|
|
40848
41068
|
const fields = {};
|
|
@@ -40858,38 +41078,14 @@ ${content}</tr>
|
|
|
40858
41078
|
}
|
|
40859
41079
|
function NewDocModal(props) {
|
|
40860
41080
|
const collectionId = props.collection;
|
|
40861
|
-
const slugRef = A2(null);
|
|
40862
41081
|
const [slug, setSlug] = y2("");
|
|
40863
41082
|
const [loading, setLoading] = y2(false);
|
|
40864
41083
|
const [slugError, setSlugError] = y2("");
|
|
40865
|
-
const firebase = useFirebase();
|
|
40866
41084
|
const theme = useMantineTheme();
|
|
40867
|
-
const projectId = window.__ROOT_CTX.rootConfig.projectId;
|
|
40868
|
-
const dbCollection = Ja2(
|
|
40869
|
-
firebase.db,
|
|
40870
|
-
"Projects",
|
|
40871
|
-
projectId,
|
|
40872
|
-
"Collections",
|
|
40873
|
-
collectionId,
|
|
40874
|
-
"Drafts"
|
|
40875
|
-
);
|
|
40876
41085
|
const rootCollection = window.__ROOT_CTX.collections[collectionId];
|
|
40877
41086
|
if (!rootCollection) {
|
|
40878
41087
|
throw new Error(`collection not found: ${collectionId}`);
|
|
40879
41088
|
}
|
|
40880
|
-
const domain2 = window.__ROOT_CTX.rootConfig.domain || "https://example.com";
|
|
40881
|
-
let urlHelp = "";
|
|
40882
|
-
if (rootCollection?.url) {
|
|
40883
|
-
if (slug) {
|
|
40884
|
-
let urlPath = rootCollection.url.replace(/\[.*slug\]/, slug);
|
|
40885
|
-
if (urlPath === "/index") {
|
|
40886
|
-
urlPath = "/";
|
|
40887
|
-
}
|
|
40888
|
-
urlHelp = `${domain2}${urlPath}`;
|
|
40889
|
-
} else {
|
|
40890
|
-
urlHelp = `${domain2}${rootCollection.url}`;
|
|
40891
|
-
}
|
|
40892
|
-
}
|
|
40893
41089
|
function onClose() {
|
|
40894
41090
|
if (props.onClose) {
|
|
40895
41091
|
props.onClose();
|
|
@@ -40899,34 +41095,23 @@ ${content}</tr>
|
|
|
40899
41095
|
e3.preventDefault();
|
|
40900
41096
|
setLoading(true);
|
|
40901
41097
|
setSlugError("");
|
|
40902
|
-
const
|
|
40903
|
-
if (!
|
|
41098
|
+
const cleanSlug = normalizeSlug2(slug);
|
|
41099
|
+
if (!isSlugValid2(cleanSlug)) {
|
|
40904
41100
|
setSlugError('Please enter a valid slug (e.g. "foo-bar-123").');
|
|
40905
41101
|
setLoading(false);
|
|
40906
41102
|
return;
|
|
40907
41103
|
}
|
|
40908
|
-
const docId = `${collectionId}/${
|
|
40909
|
-
|
|
40910
|
-
|
|
40911
|
-
|
|
40912
|
-
|
|
41104
|
+
const docId = `${collectionId}/${cleanSlug}`;
|
|
41105
|
+
try {
|
|
41106
|
+
const fields = getDefaultFields(rootCollection);
|
|
41107
|
+
await cmsCreateDoc(docId, { fields });
|
|
41108
|
+
} catch (err) {
|
|
41109
|
+
setSlugError(String(err));
|
|
40913
41110
|
setLoading(false);
|
|
40914
41111
|
return;
|
|
40915
41112
|
}
|
|
40916
|
-
await Jl(docRef, {
|
|
40917
|
-
id: docId,
|
|
40918
|
-
slug: slug2,
|
|
40919
|
-
collection: collectionId,
|
|
40920
|
-
sys: {
|
|
40921
|
-
createdAt: df(),
|
|
40922
|
-
createdBy: window.firebase.user.email,
|
|
40923
|
-
modifiedAt: df(),
|
|
40924
|
-
modifiedBy: window.firebase.user.email
|
|
40925
|
-
},
|
|
40926
|
-
fields: getDefaultFields(rootCollection)
|
|
40927
|
-
});
|
|
40928
41113
|
setLoading(false);
|
|
40929
|
-
$4(`/cms/content/${props.collection}/${
|
|
41114
|
+
$4(`/cms/content/${props.collection}/${cleanSlug}?new=true`);
|
|
40930
41115
|
}
|
|
40931
41116
|
return /* @__PURE__ */ o4(
|
|
40932
41117
|
Modal,
|
|
@@ -40934,25 +41119,23 @@ ${content}</tr>
|
|
|
40934
41119
|
className: "NewDocModal",
|
|
40935
41120
|
opened: props.opened || false,
|
|
40936
41121
|
onClose: () => onClose(),
|
|
40937
|
-
title:
|
|
41122
|
+
title: "New",
|
|
41123
|
+
size: "500px",
|
|
40938
41124
|
overlayColor: theme.colorScheme === "dark" ? theme.colors.dark[9] : theme.colors.gray[2],
|
|
40939
41125
|
children: [
|
|
40940
41126
|
/* @__PURE__ */ o4("div", { className: "NewDocModal__body", children: "Enter a slug for the new doc. The slug is the ID of the page and is what's used in the URL. Use only lowercase letters, numbers, and dashes." }),
|
|
40941
41127
|
/* @__PURE__ */ o4("form", { onSubmit: (e3) => onSubmit(e3), children: [
|
|
40942
|
-
/* @__PURE__ */ o4(
|
|
40943
|
-
|
|
41128
|
+
/* @__PURE__ */ o4(
|
|
41129
|
+
SlugInput,
|
|
40944
41130
|
{
|
|
40945
|
-
|
|
40946
|
-
|
|
40947
|
-
|
|
40948
|
-
|
|
40949
|
-
|
|
40950
|
-
autoComplete: "off",
|
|
40951
|
-
size: "xs",
|
|
40952
|
-
description: urlHelp,
|
|
40953
|
-
error: slugError
|
|
41131
|
+
className: "NewDocModal__slug",
|
|
41132
|
+
collectionId,
|
|
41133
|
+
onChange: (newValue) => {
|
|
41134
|
+
setSlug(newValue.slug);
|
|
41135
|
+
}
|
|
40954
41136
|
}
|
|
40955
|
-
)
|
|
41137
|
+
),
|
|
41138
|
+
slugError && /* @__PURE__ */ o4("div", { className: "NewDocModal__slugError", children: slugError }),
|
|
40956
41139
|
/* @__PURE__ */ o4("div", { className: "NewDocModal__buttons", children: [
|
|
40957
41140
|
/* @__PURE__ */ o4(
|
|
40958
41141
|
Button,
|
|
@@ -41160,7 +41343,7 @@ ${content}</tr>
|
|
|
41160
41343
|
s2(() => {
|
|
41161
41344
|
setLoading(true);
|
|
41162
41345
|
listDocs();
|
|
41163
|
-
}, []);
|
|
41346
|
+
}, [Ja2, options2.orderBy]);
|
|
41164
41347
|
return [loading, listDocs, docs];
|
|
41165
41348
|
}
|
|
41166
41349
|
function CollectionPage(props) {
|
|
@@ -41646,10 +41829,39 @@ ${content}</tr>
|
|
|
41646
41829
|
};
|
|
41647
41830
|
}
|
|
41648
41831
|
|
|
41832
|
+
// ui/utils/events.ts
|
|
41833
|
+
var EventListener = class {
|
|
41834
|
+
constructor() {
|
|
41835
|
+
this.events = /* @__PURE__ */ new Map();
|
|
41836
|
+
}
|
|
41837
|
+
on(eventName, callback) {
|
|
41838
|
+
const callbacks = this.events.get(eventName) ?? [];
|
|
41839
|
+
this.events.set(eventName, [...callbacks, callback]);
|
|
41840
|
+
return () => {
|
|
41841
|
+
this.off(eventName, callback);
|
|
41842
|
+
};
|
|
41843
|
+
}
|
|
41844
|
+
off(eventName, callback) {
|
|
41845
|
+
const eventCallbacks = this.events.get(eventName) ?? [];
|
|
41846
|
+
const index3 = eventCallbacks.indexOf(callback);
|
|
41847
|
+
if (index3 >= 0) {
|
|
41848
|
+
eventCallbacks.splice(index3, 1);
|
|
41849
|
+
}
|
|
41850
|
+
}
|
|
41851
|
+
dispatch(eventName, ...args) {
|
|
41852
|
+
const eventCallbacks = this.events.get(eventName) ?? [];
|
|
41853
|
+
eventCallbacks.forEach((callback) => callback(...args));
|
|
41854
|
+
}
|
|
41855
|
+
dispose() {
|
|
41856
|
+
this.events.clear();
|
|
41857
|
+
}
|
|
41858
|
+
};
|
|
41859
|
+
|
|
41649
41860
|
// ui/hooks/useDraft.ts
|
|
41650
41861
|
var SAVE_DELAY_MS = 3 * 1e3;
|
|
41651
|
-
var DraftController = class {
|
|
41862
|
+
var DraftController = class extends EventListener {
|
|
41652
41863
|
constructor(docId) {
|
|
41864
|
+
super();
|
|
41653
41865
|
this.pendingUpdates = /* @__PURE__ */ new Map();
|
|
41654
41866
|
this.cachedData = {};
|
|
41655
41867
|
this.subscribers = {};
|
|
@@ -41683,7 +41895,6 @@ ${content}</tr>
|
|
|
41683
41895
|
if (this.started) {
|
|
41684
41896
|
return;
|
|
41685
41897
|
}
|
|
41686
|
-
console.log("start()");
|
|
41687
41898
|
this.started = true;
|
|
41688
41899
|
this.dbUnsubscribe = tf(this.docRef, (snapshot) => {
|
|
41689
41900
|
const data = snapshot.data();
|
|
@@ -41691,7 +41902,6 @@ ${content}</tr>
|
|
|
41691
41902
|
applyUpdates(data, Object.fromEntries(this.pendingUpdates));
|
|
41692
41903
|
}
|
|
41693
41904
|
this.cachedData = data;
|
|
41694
|
-
console.log("onSnapshot()", data, this.pendingUpdates);
|
|
41695
41905
|
this.notifySubscribers();
|
|
41696
41906
|
});
|
|
41697
41907
|
}
|
|
@@ -41702,7 +41912,6 @@ ${content}</tr>
|
|
|
41702
41912
|
if (!this.started) {
|
|
41703
41913
|
return;
|
|
41704
41914
|
}
|
|
41705
|
-
console.log("stop()");
|
|
41706
41915
|
if (this.dbUnsubscribe) {
|
|
41707
41916
|
this.dbUnsubscribe();
|
|
41708
41917
|
}
|
|
@@ -41710,16 +41919,22 @@ ${content}</tr>
|
|
|
41710
41919
|
this.started = false;
|
|
41711
41920
|
}
|
|
41712
41921
|
/**
|
|
41713
|
-
* Adds a listener for change events.
|
|
41922
|
+
* Adds a listener for data change events.
|
|
41714
41923
|
*/
|
|
41715
41924
|
onChange(callback) {
|
|
41716
|
-
this.
|
|
41925
|
+
return this.on("CHANGE" /* CHANGE */, callback);
|
|
41717
41926
|
}
|
|
41718
41927
|
/**
|
|
41719
41928
|
* Adds a listener for save state change events.
|
|
41720
41929
|
*/
|
|
41721
41930
|
onSaveStateChange(callback) {
|
|
41722
|
-
this.
|
|
41931
|
+
return this.on("SAVE_STATE_CHANGE" /* SAVE_STATE_CHANGE */, callback);
|
|
41932
|
+
}
|
|
41933
|
+
/**
|
|
41934
|
+
* Adds a listener for db write events.
|
|
41935
|
+
*/
|
|
41936
|
+
onFlush(callback) {
|
|
41937
|
+
return this.on("FLUSH" /* FLUSH */, callback);
|
|
41723
41938
|
}
|
|
41724
41939
|
/**
|
|
41725
41940
|
* Subscribes to remote changes for a given key. Returns a callback function
|
|
@@ -41727,7 +41942,6 @@ ${content}</tr>
|
|
|
41727
41942
|
*/
|
|
41728
41943
|
subscribe(key, callback) {
|
|
41729
41944
|
var _a2;
|
|
41730
|
-
console.log("subscribe()", key);
|
|
41731
41945
|
(_a2 = this.subscribers)[key] ?? (_a2[key] = /* @__PURE__ */ new Set());
|
|
41732
41946
|
this.subscribers[key].add(callback);
|
|
41733
41947
|
callback(getNestedValue(this.cachedData, key));
|
|
@@ -41743,11 +41957,8 @@ ${content}</tr>
|
|
|
41743
41957
|
* Notifies subscribers of changes.
|
|
41744
41958
|
*/
|
|
41745
41959
|
notifySubscribers() {
|
|
41746
|
-
console.log("notifySubscribers()");
|
|
41747
41960
|
const data = this.cachedData;
|
|
41748
|
-
|
|
41749
|
-
this.onChangeCallback(data);
|
|
41750
|
-
}
|
|
41961
|
+
this.dispatch("CHANGE" /* CHANGE */, data);
|
|
41751
41962
|
notify(this.subscribers, data);
|
|
41752
41963
|
}
|
|
41753
41964
|
/**
|
|
@@ -41765,9 +41976,7 @@ ${content}</tr>
|
|
|
41765
41976
|
this.pendingUpdates.set(key, updates[key]);
|
|
41766
41977
|
}
|
|
41767
41978
|
applyUpdates(this.cachedData, updates);
|
|
41768
|
-
|
|
41769
|
-
this.onChangeCallback(this.cachedData);
|
|
41770
|
-
}
|
|
41979
|
+
this.dispatch("CHANGE" /* CHANGE */, this.cachedData);
|
|
41771
41980
|
this.setSaveState("UPDATE_PENDING" /* UPDATES_PENDING */);
|
|
41772
41981
|
this.queueChanges();
|
|
41773
41982
|
}
|
|
@@ -41777,9 +41986,7 @@ ${content}</tr>
|
|
|
41777
41986
|
async removeKey(key) {
|
|
41778
41987
|
this.pendingUpdates.set(key, ff());
|
|
41779
41988
|
applyUpdates(this.cachedData, { [key]: void 0 });
|
|
41780
|
-
|
|
41781
|
-
this.onChangeCallback({ ...this.cachedData });
|
|
41782
|
-
}
|
|
41989
|
+
this.dispatch("CHANGE" /* CHANGE */, this.cachedData);
|
|
41783
41990
|
this.setSaveState("UPDATE_PENDING" /* UPDATES_PENDING */);
|
|
41784
41991
|
this.queueChanges();
|
|
41785
41992
|
}
|
|
@@ -41796,9 +42003,7 @@ ${content}</tr>
|
|
|
41796
42003
|
}
|
|
41797
42004
|
}, SAVE_DELAY_MS);
|
|
41798
42005
|
}
|
|
41799
|
-
|
|
41800
|
-
this.onSaveStateChangeCallback(newSaveState);
|
|
41801
|
-
}
|
|
42006
|
+
this.dispatch("SAVE_STATE_CHANGE" /* SAVE_STATE_CHANGE */, newSaveState);
|
|
41802
42007
|
}
|
|
41803
42008
|
/**
|
|
41804
42009
|
* Immediately write all queued data to the DB.
|
|
@@ -41816,10 +42021,17 @@ ${content}</tr>
|
|
|
41816
42021
|
this.setSaveState("SAVING" /* SAVING */);
|
|
41817
42022
|
await Yl(this.docRef, updates);
|
|
41818
42023
|
this.setSaveState("SAVED" /* SAVED */);
|
|
42024
|
+
this.dispatch("FLUSH" /* FLUSH */);
|
|
41819
42025
|
} catch (err) {
|
|
41820
42026
|
console.error("failed to update doc");
|
|
41821
42027
|
console.error(err);
|
|
41822
42028
|
this.setSaveState("ERROR" /* ERROR */);
|
|
42029
|
+
showNotification({
|
|
42030
|
+
title: "Failed to save",
|
|
42031
|
+
message: `Failed to save changes to ${this.slug}`,
|
|
42032
|
+
color: "red",
|
|
42033
|
+
autoClose: false
|
|
42034
|
+
});
|
|
41823
42035
|
for (const key in updates) {
|
|
41824
42036
|
if (key.startsWith("sys.")) {
|
|
41825
42037
|
continue;
|
|
@@ -41846,6 +42058,7 @@ ${content}</tr>
|
|
|
41846
42058
|
* Stops all listeners and disposes the controller.
|
|
41847
42059
|
*/
|
|
41848
42060
|
async dispose() {
|
|
42061
|
+
super.dispose();
|
|
41849
42062
|
this.stop();
|
|
41850
42063
|
}
|
|
41851
42064
|
};
|
|
@@ -41893,28 +42106,28 @@ ${content}</tr>
|
|
|
41893
42106
|
function useDraft(docId) {
|
|
41894
42107
|
const [loading, setLoading] = y2(true);
|
|
41895
42108
|
const [data, setData] = y2({});
|
|
41896
|
-
const
|
|
42109
|
+
const controller = T2(() => new DraftController(docId), []);
|
|
41897
42110
|
const [saveState, setSaveState] = y2("NO_CHANGES" /* NO_CHANGES */);
|
|
41898
42111
|
s2(() => {
|
|
41899
|
-
|
|
42112
|
+
controller.onChange((data2) => {
|
|
41900
42113
|
setData(data2);
|
|
41901
42114
|
setLoading(false);
|
|
41902
42115
|
});
|
|
41903
|
-
|
|
41904
|
-
|
|
42116
|
+
controller.onSaveStateChange((newSaveState) => setSaveState(newSaveState));
|
|
42117
|
+
controller.start();
|
|
41905
42118
|
document.addEventListener("visibilitychange", () => {
|
|
41906
42119
|
if (document.hidden || document.visibilityState !== "visible") {
|
|
41907
|
-
|
|
42120
|
+
controller.stop();
|
|
41908
42121
|
} else {
|
|
41909
|
-
if (!
|
|
42122
|
+
if (!controller.started) {
|
|
41910
42123
|
setLoading(true);
|
|
41911
|
-
|
|
42124
|
+
controller.start();
|
|
41912
42125
|
}
|
|
41913
42126
|
}
|
|
41914
42127
|
});
|
|
41915
|
-
return () =>
|
|
42128
|
+
return () => controller.dispose();
|
|
41916
42129
|
}, []);
|
|
41917
|
-
return { loading, saveState,
|
|
42130
|
+
return { loading, saveState, controller, data };
|
|
41918
42131
|
}
|
|
41919
42132
|
|
|
41920
42133
|
// ui/utils/str-format.ts
|
|
@@ -41961,11 +42174,11 @@ ${content}</tr>
|
|
|
41961
42174
|
LocalizationModal.ConfigLocales = (props) => {
|
|
41962
42175
|
const [enabledLocales, setEnabledLocales] = y2(["en"]);
|
|
41963
42176
|
const i18nConfig = window.__ROOT_CTX.rootConfig.i18n || {};
|
|
41964
|
-
const
|
|
42177
|
+
const i18nLocales = i18nConfig.locales || ["en"];
|
|
41965
42178
|
const localeGroups = i18nConfig.groups || {
|
|
41966
42179
|
default: {
|
|
41967
42180
|
label: "",
|
|
41968
|
-
locales:
|
|
42181
|
+
locales: i18nLocales
|
|
41969
42182
|
}
|
|
41970
42183
|
};
|
|
41971
42184
|
s2(() => {
|
|
@@ -42013,7 +42226,7 @@ ${content}</tr>
|
|
|
42013
42226
|
/* @__PURE__ */ o4(
|
|
42014
42227
|
LocalizationModal.AllNoneButtons,
|
|
42015
42228
|
{
|
|
42016
|
-
onAllClicked: () => updateEnabledLocales(
|
|
42229
|
+
onAllClicked: () => updateEnabledLocales(i18nLocales),
|
|
42017
42230
|
onNoneClicked: () => updateEnabledLocales([])
|
|
42018
42231
|
}
|
|
42019
42232
|
)
|
|
@@ -42121,6 +42334,7 @@ ${content}</tr>
|
|
|
42121
42334
|
const [loading, setLoading] = y2(true);
|
|
42122
42335
|
const [sourceStrings, setSourceStrings] = y2([]);
|
|
42123
42336
|
const [selectedLocale, setSelectedLocale] = y2("");
|
|
42337
|
+
const [localeTranslations, setLocaleTranslations] = y2({});
|
|
42124
42338
|
const locales = window.__ROOT_CTX.rootConfig.i18n.locales || [];
|
|
42125
42339
|
const localeOptions = locales.map((locale) => ({
|
|
42126
42340
|
value: locale,
|
|
@@ -42136,6 +42350,25 @@ ${content}</tr>
|
|
|
42136
42350
|
setLoading(false);
|
|
42137
42351
|
});
|
|
42138
42352
|
}, [props.opened]);
|
|
42353
|
+
s2(() => {
|
|
42354
|
+
if (!selectedLocale) {
|
|
42355
|
+
setLocaleTranslations({});
|
|
42356
|
+
return;
|
|
42357
|
+
}
|
|
42358
|
+
const translationsRef = getTranslationsDocRef(props.docId);
|
|
42359
|
+
Kl(translationsRef).then((translationsDoc) => {
|
|
42360
|
+
const data = translationsDoc.data() || {};
|
|
42361
|
+
return data.translations || {};
|
|
42362
|
+
}).then((translationsMap) => {
|
|
42363
|
+
const localeTranslations2 = {};
|
|
42364
|
+
Object.values(translationsMap).forEach(
|
|
42365
|
+
(translation) => {
|
|
42366
|
+
localeTranslations2[translation.source] = translation[selectedLocale] || "";
|
|
42367
|
+
}
|
|
42368
|
+
);
|
|
42369
|
+
setLocaleTranslations(localeTranslations2);
|
|
42370
|
+
});
|
|
42371
|
+
}, [selectedLocale]);
|
|
42139
42372
|
async function downloadCsv() {
|
|
42140
42373
|
const headers = ["source", "en"];
|
|
42141
42374
|
const rows = [];
|
|
@@ -42160,12 +42393,39 @@ ${content}</tr>
|
|
|
42160
42393
|
window.location.assign(file);
|
|
42161
42394
|
window.URL.revokeObjectURL(file);
|
|
42162
42395
|
}
|
|
42396
|
+
async function importCsv() {
|
|
42397
|
+
const fileInput = document.createElement("input");
|
|
42398
|
+
fileInput.type = "file";
|
|
42399
|
+
fileInput.accept = ".csv";
|
|
42400
|
+
fileInput.addEventListener("change", async () => {
|
|
42401
|
+
const file = fileInput.files?.[0];
|
|
42402
|
+
if (file) {
|
|
42403
|
+
const formData = new FormData();
|
|
42404
|
+
formData.append("file", file);
|
|
42405
|
+
const res = await fetch("/cms/api/csv.import", {
|
|
42406
|
+
method: "POST",
|
|
42407
|
+
body: formData
|
|
42408
|
+
}).then((res2) => res2.json());
|
|
42409
|
+
await cmsDocImportCsv(props.docId, res.data);
|
|
42410
|
+
showNotification({
|
|
42411
|
+
title: "Saved!",
|
|
42412
|
+
message: `Successfully imported translations for ${props.docId}.`,
|
|
42413
|
+
autoClose: 5e3
|
|
42414
|
+
});
|
|
42415
|
+
}
|
|
42416
|
+
});
|
|
42417
|
+
fileInput.click();
|
|
42418
|
+
}
|
|
42163
42419
|
function onAction(action) {
|
|
42164
42420
|
switch (action) {
|
|
42165
42421
|
case "export-download-csv": {
|
|
42166
42422
|
downloadCsv();
|
|
42167
42423
|
return;
|
|
42168
42424
|
}
|
|
42425
|
+
case "import-csv": {
|
|
42426
|
+
importCsv();
|
|
42427
|
+
return;
|
|
42428
|
+
}
|
|
42169
42429
|
}
|
|
42170
42430
|
}
|
|
42171
42431
|
if (loading) {
|
|
@@ -42241,7 +42501,7 @@ ${content}</tr>
|
|
|
42241
42501
|
borderRadius: 4,
|
|
42242
42502
|
height: "100%"
|
|
42243
42503
|
}),
|
|
42244
|
-
children: /* @__PURE__ */ o4(Text, { size: "xs", sx: { whiteSpace: "pre-wrap" }, children: "
|
|
42504
|
+
children: /* @__PURE__ */ o4(Text, { size: "xs", sx: { whiteSpace: "pre-wrap" }, children: localeTranslations[source] || " " })
|
|
42245
42505
|
}
|
|
42246
42506
|
) })
|
|
42247
42507
|
] }, i3))
|
|
@@ -42335,7 +42595,7 @@ ${content}</tr>
|
|
|
42335
42595
|
/* @__PURE__ */ o4(Menu.Item, { disabled: true, onClick: () => dispatch("import-google-sheet"), children: "Import Google Sheet" }),
|
|
42336
42596
|
/* @__PURE__ */ o4(Divider, {}),
|
|
42337
42597
|
/* @__PURE__ */ o4(Menu.Label, { children: "File" }),
|
|
42338
|
-
/* @__PURE__ */ o4(Menu.Item, { onClick: () => dispatch("import-
|
|
42598
|
+
/* @__PURE__ */ o4(Menu.Item, { onClick: () => dispatch("import-csv"), children: "Import .csv" })
|
|
42339
42599
|
]
|
|
42340
42600
|
}
|
|
42341
42601
|
);
|
|
@@ -42547,14 +42807,9 @@ ${content}</tr>
|
|
|
42547
42807
|
// ui/components/DocEditor/DocEditor.tsx
|
|
42548
42808
|
function DocEditor(props) {
|
|
42549
42809
|
const fields = props.collection.fields || [];
|
|
42550
|
-
const { loading,
|
|
42810
|
+
const { loading, controller, saveState, data } = props.draft;
|
|
42551
42811
|
const [publishDocModalOpen, setPublishDocModalOpen] = y2(false);
|
|
42552
42812
|
const [l10nModalOpen, setL10nModalOpen] = y2(false);
|
|
42553
|
-
s2(() => {
|
|
42554
|
-
if (draft && props.onDraftController) {
|
|
42555
|
-
props.onDraftController(draft);
|
|
42556
|
-
}
|
|
42557
|
-
}, [draft]);
|
|
42558
42813
|
function goBack() {
|
|
42559
42814
|
const collectionId = props.docId.split("/")[0];
|
|
42560
42815
|
$4(`/cms/content/${collectionId}`);
|
|
@@ -42571,7 +42826,7 @@ ${content}</tr>
|
|
|
42571
42826
|
/* @__PURE__ */ o4(
|
|
42572
42827
|
LocalizationModal,
|
|
42573
42828
|
{
|
|
42574
|
-
draft,
|
|
42829
|
+
draft: controller,
|
|
42575
42830
|
collection: props.collection,
|
|
42576
42831
|
docId: props.docId,
|
|
42577
42832
|
opened: l10nModalOpen,
|
|
@@ -42631,7 +42886,7 @@ ${content}</tr>
|
|
|
42631
42886
|
field,
|
|
42632
42887
|
shallowKey: field.id,
|
|
42633
42888
|
deepKey: `fields.${field.id}`,
|
|
42634
|
-
draft
|
|
42889
|
+
draft: controller
|
|
42635
42890
|
},
|
|
42636
42891
|
field.id
|
|
42637
42892
|
)) })
|
|
@@ -42687,7 +42942,9 @@ ${content}</tr>
|
|
|
42687
42942
|
minRows: 2,
|
|
42688
42943
|
maxRows: field.maxRows || 12,
|
|
42689
42944
|
value,
|
|
42690
|
-
onChange: (e3) =>
|
|
42945
|
+
onChange: (e3) => {
|
|
42946
|
+
onChange(e3.currentTarget.value);
|
|
42947
|
+
}
|
|
42691
42948
|
}
|
|
42692
42949
|
);
|
|
42693
42950
|
}
|
|
@@ -42697,7 +42954,9 @@ ${content}</tr>
|
|
|
42697
42954
|
size: "xs",
|
|
42698
42955
|
radius: 0,
|
|
42699
42956
|
value,
|
|
42700
|
-
onChange: (e3) =>
|
|
42957
|
+
onChange: (e3) => {
|
|
42958
|
+
onChange(e3.currentTarget.value);
|
|
42959
|
+
}
|
|
42701
42960
|
}
|
|
42702
42961
|
);
|
|
42703
42962
|
};
|
|
@@ -42711,7 +42970,7 @@ ${content}</tr>
|
|
|
42711
42970
|
async function uploadFileToGCS(file) {
|
|
42712
42971
|
const projectId = window.__ROOT_CTX.rootConfig.projectId;
|
|
42713
42972
|
const hashHex = await sha256(file);
|
|
42714
|
-
const ext = file.name.split(".").at(-1);
|
|
42973
|
+
const ext = normalizeExt(file.name.split(".").at(-1) || "");
|
|
42715
42974
|
const filePath = `${projectId}/uploads/${hashHex}.${ext}`;
|
|
42716
42975
|
const gcsRef = ref(window.firebase.storage, filePath);
|
|
42717
42976
|
await uploadBytes(gcsRef, file);
|
|
@@ -42741,6 +43000,13 @@ ${content}</tr>
|
|
|
42741
43000
|
src: imageSrc
|
|
42742
43001
|
};
|
|
42743
43002
|
}
|
|
43003
|
+
function normalizeExt(ext) {
|
|
43004
|
+
let output = String(ext).toLowerCase();
|
|
43005
|
+
if (output === ".jpeg") {
|
|
43006
|
+
output = ".jpg";
|
|
43007
|
+
}
|
|
43008
|
+
return output;
|
|
43009
|
+
}
|
|
42744
43010
|
async function getGciUrl(gcsPath) {
|
|
42745
43011
|
const gciDomain = window.__ROOT_CTX.rootConfig.gci;
|
|
42746
43012
|
if (!gciDomain) {
|
|
@@ -42866,7 +43132,9 @@ ${content}</tr>
|
|
|
42866
43132
|
radius: 0,
|
|
42867
43133
|
value: img.alt,
|
|
42868
43134
|
label: "Alt text",
|
|
42869
|
-
onChange: (e3) =>
|
|
43135
|
+
onChange: (e3) => {
|
|
43136
|
+
setAltText(e3.currentTarget.value);
|
|
43137
|
+
}
|
|
42870
43138
|
}
|
|
42871
43139
|
)
|
|
42872
43140
|
] }) : /* @__PURE__ */ o4("div", { className: "DocEditor__ImageField__noImage", children: "No image" }),
|
|
@@ -42986,7 +43254,6 @@ ${content}</tr>
|
|
|
42986
43254
|
)) }) });
|
|
42987
43255
|
};
|
|
42988
43256
|
function arrayReducer(state, action) {
|
|
42989
|
-
console.log(action);
|
|
42990
43257
|
switch (action.type) {
|
|
42991
43258
|
case "update": {
|
|
42992
43259
|
const newlyAdded = state._new || [];
|
|
@@ -43124,7 +43391,6 @@ ${content}</tr>
|
|
|
43124
43391
|
const unsubscribe = props.draft.subscribe(
|
|
43125
43392
|
props.deepKey,
|
|
43126
43393
|
(newValue) => {
|
|
43127
|
-
console.log("onRemoteChange()", newValue);
|
|
43128
43394
|
dispatch({ type: "update", newValue });
|
|
43129
43395
|
}
|
|
43130
43396
|
);
|
|
@@ -43468,7 +43734,6 @@ ${content}</tr>
|
|
|
43468
43734
|
placeholders._index = String(index3);
|
|
43469
43735
|
placeholders["_index:02"] = placeholders._index.padStart(2, "0");
|
|
43470
43736
|
placeholders["_index:03"] = placeholders._index.padStart(3, "0");
|
|
43471
|
-
console.log(placeholders);
|
|
43472
43737
|
while (templates.length > 0) {
|
|
43473
43738
|
const template = templates.shift();
|
|
43474
43739
|
const preview = strFormat(template, placeholders);
|
|
@@ -43543,15 +43808,12 @@ ${content}</tr>
|
|
|
43543
43808
|
const slug = props.slug;
|
|
43544
43809
|
const docId = `${collectionId}/${slug}`;
|
|
43545
43810
|
const collection = window.__ROOT_CTX.collections[collectionId];
|
|
43546
|
-
const
|
|
43811
|
+
const draft = useDraft(docId);
|
|
43547
43812
|
if (!collection) {
|
|
43548
43813
|
return /* @__PURE__ */ o4("div", { children: "Could not find collection." });
|
|
43549
43814
|
}
|
|
43550
43815
|
function saveDraft() {
|
|
43551
|
-
|
|
43552
|
-
if (draft) {
|
|
43553
|
-
draft.flush();
|
|
43554
|
-
}
|
|
43816
|
+
draft.controller.flush();
|
|
43555
43817
|
}
|
|
43556
43818
|
useHotkeys([["mod+S", () => saveDraft()]]);
|
|
43557
43819
|
return /* @__PURE__ */ o4(Layout, { children: /* @__PURE__ */ o4(SplitPanel, { className: "DocumentPage", localStorageId: "DocumentPage", children: [
|
|
@@ -43574,14 +43836,7 @@ ${content}</tr>
|
|
|
43574
43836
|
}
|
|
43575
43837
|
) })
|
|
43576
43838
|
] }),
|
|
43577
|
-
/* @__PURE__ */ o4("div", { className: "DocumentPage__side__editor", children: /* @__PURE__ */ o4(
|
|
43578
|
-
DocEditor,
|
|
43579
|
-
{
|
|
43580
|
-
collection,
|
|
43581
|
-
docId,
|
|
43582
|
-
onDraftController: (draft2) => setDraft(draft2)
|
|
43583
|
-
}
|
|
43584
|
-
) })
|
|
43839
|
+
/* @__PURE__ */ o4("div", { className: "DocumentPage__side__editor", children: /* @__PURE__ */ o4(DocEditor, { collection, docId, draft }) })
|
|
43585
43840
|
] }),
|
|
43586
43841
|
/* @__PURE__ */ o4(SplitPanel.Item, { className: "DocumentPage__main", fluid: true, children: /* @__PURE__ */ o4(DocumentPage.Preview, { docId, draft }) })
|
|
43587
43842
|
] }) });
|
|
@@ -43604,10 +43859,20 @@ ${content}</tr>
|
|
|
43604
43859
|
"--iframe-scale": "1"
|
|
43605
43860
|
});
|
|
43606
43861
|
const iframeRef = A2(null);
|
|
43862
|
+
function reloadIframe() {
|
|
43863
|
+
const iframe = iframeRef.current;
|
|
43864
|
+
iframe.src = "about:blank";
|
|
43865
|
+
window.setTimeout(() => {
|
|
43866
|
+
if (iframe.src !== previewPath) {
|
|
43867
|
+
iframe.src = previewPath;
|
|
43868
|
+
} else {
|
|
43869
|
+
iframe.contentWindow.location.reload();
|
|
43870
|
+
}
|
|
43871
|
+
}, 20);
|
|
43872
|
+
}
|
|
43607
43873
|
s2(() => {
|
|
43608
43874
|
const iframe = iframeRef.current;
|
|
43609
43875
|
function onIframeLoad() {
|
|
43610
|
-
console.log("iframe load", iframe.contentWindow?.document.title);
|
|
43611
43876
|
const iframeWindow = iframe.contentWindow;
|
|
43612
43877
|
if (!iframeWindow) {
|
|
43613
43878
|
return;
|
|
@@ -43618,7 +43883,11 @@ ${content}</tr>
|
|
|
43618
43883
|
}
|
|
43619
43884
|
}
|
|
43620
43885
|
iframe.addEventListener("load", onIframeLoad);
|
|
43886
|
+
const removeOnFlush = props.draft.controller.onFlush(() => {
|
|
43887
|
+
reloadIframe();
|
|
43888
|
+
});
|
|
43621
43889
|
return () => {
|
|
43890
|
+
removeOnFlush();
|
|
43622
43891
|
iframe.removeEventListener("load", onIframeLoad);
|
|
43623
43892
|
};
|
|
43624
43893
|
}, []);
|
|
@@ -43630,23 +43899,8 @@ ${content}</tr>
|
|
|
43630
43899
|
return device2;
|
|
43631
43900
|
});
|
|
43632
43901
|
}
|
|
43633
|
-
function
|
|
43634
|
-
|
|
43635
|
-
const iframe = iframeRef.current;
|
|
43636
|
-
iframe.src = "about:blank";
|
|
43637
|
-
window.setTimeout(() => {
|
|
43638
|
-
if (iframe.src !== previewPath) {
|
|
43639
|
-
iframe.src = previewPath;
|
|
43640
|
-
} else {
|
|
43641
|
-
iframe.contentWindow.location.reload();
|
|
43642
|
-
}
|
|
43643
|
-
}, 20);
|
|
43644
|
-
};
|
|
43645
|
-
if (props.draft) {
|
|
43646
|
-
props.draft.flush().then(() => reloadIframe());
|
|
43647
|
-
} else {
|
|
43648
|
-
reloadIframe();
|
|
43649
|
-
}
|
|
43902
|
+
function onReloadClick() {
|
|
43903
|
+
props.draft.controller.flush().then(() => reloadIframe());
|
|
43650
43904
|
}
|
|
43651
43905
|
function openNewTab() {
|
|
43652
43906
|
const tab = window.open(previewPath, "_blank");
|
|
@@ -43724,7 +43978,7 @@ ${content}</tr>
|
|
|
43724
43978
|
ActionIcon,
|
|
43725
43979
|
{
|
|
43726
43980
|
className: "DocumentPage__main__previewBar__button DocumentPage__main__previewBar__button--reload",
|
|
43727
|
-
onClick: () =>
|
|
43981
|
+
onClick: () => onReloadClick(),
|
|
43728
43982
|
children: /* @__PURE__ */ o4(IconReload, { size: 16 })
|
|
43729
43983
|
}
|
|
43730
43984
|
) }),
|
|
@@ -44025,6 +44279,94 @@ ${content}</tr>
|
|
|
44025
44279
|
] }) });
|
|
44026
44280
|
}
|
|
44027
44281
|
|
|
44282
|
+
// ui/components/CopyDocModal/CopyDocModal.tsx
|
|
44283
|
+
function CopyDocModal(modalProps) {
|
|
44284
|
+
const { innerProps: props, context, id: id2 } = modalProps;
|
|
44285
|
+
const [toCollectionId, setToCollectionId] = y2("");
|
|
44286
|
+
const [toSlug, setToSlug] = y2("");
|
|
44287
|
+
const [error, setError] = y2("");
|
|
44288
|
+
const [loading, setLoading] = y2(false);
|
|
44289
|
+
const fromDocId = props.fromDocId;
|
|
44290
|
+
const fromCollectionId = fromDocId.split("/")[0];
|
|
44291
|
+
async function onSubmit(e3) {
|
|
44292
|
+
e3.preventDefault();
|
|
44293
|
+
setLoading(true);
|
|
44294
|
+
setError("");
|
|
44295
|
+
if (!fromCollectionId) {
|
|
44296
|
+
setError("Please select a collection.");
|
|
44297
|
+
setLoading(false);
|
|
44298
|
+
return;
|
|
44299
|
+
}
|
|
44300
|
+
const cleanSlug = normalizeSlug(toSlug);
|
|
44301
|
+
if (!isSlugValid(cleanSlug)) {
|
|
44302
|
+
setError('Please enter a valid slug (e.g. "foo-bar-123").');
|
|
44303
|
+
setLoading(false);
|
|
44304
|
+
return;
|
|
44305
|
+
}
|
|
44306
|
+
const toDocId = `${toCollectionId}/${cleanSlug}`;
|
|
44307
|
+
try {
|
|
44308
|
+
await cmsCopyDoc(fromDocId, toDocId);
|
|
44309
|
+
context.closeModal(id2);
|
|
44310
|
+
showNotification({
|
|
44311
|
+
title: "Copied!",
|
|
44312
|
+
message: `Succesfully copied ${fromDocId} to ${toDocId}.`,
|
|
44313
|
+
autoClose: 5e3
|
|
44314
|
+
});
|
|
44315
|
+
} catch (err) {
|
|
44316
|
+
setError(String(err));
|
|
44317
|
+
setLoading(false);
|
|
44318
|
+
return;
|
|
44319
|
+
}
|
|
44320
|
+
setLoading(false);
|
|
44321
|
+
$4(`/cms/content/${toCollectionId}/${cleanSlug}`);
|
|
44322
|
+
}
|
|
44323
|
+
return /* @__PURE__ */ o4("div", { className: "CopyDocModal", children: /* @__PURE__ */ o4("form", { onSubmit: (e3) => onSubmit(e3), children: [
|
|
44324
|
+
/* @__PURE__ */ o4("div", { className: "CopyDocModal__from", children: [
|
|
44325
|
+
/* @__PURE__ */ o4(Text2, { className: "CopyDocModal__from__label", size: "body", weight: "bold", children: "From:" }),
|
|
44326
|
+
/* @__PURE__ */ o4(Text2, { className: "CopyDocModal__from__value", size: "body-sm", children: /* @__PURE__ */ o4("code", { children: props.fromDocId }) })
|
|
44327
|
+
] }),
|
|
44328
|
+
/* @__PURE__ */ o4("div", { className: "CopyDocModal__to", children: [
|
|
44329
|
+
/* @__PURE__ */ o4(Text2, { className: "CopyDocModal__to__label", size: "body", weight: "bold", children: "To:" }),
|
|
44330
|
+
/* @__PURE__ */ o4(
|
|
44331
|
+
SlugInput,
|
|
44332
|
+
{
|
|
44333
|
+
className: "CopyDocModal__slug",
|
|
44334
|
+
collectionId: fromCollectionId,
|
|
44335
|
+
onChange: (newValue) => {
|
|
44336
|
+
setToCollectionId(newValue.collectionId);
|
|
44337
|
+
setToSlug(newValue.slug);
|
|
44338
|
+
}
|
|
44339
|
+
}
|
|
44340
|
+
)
|
|
44341
|
+
] }),
|
|
44342
|
+
error && /* @__PURE__ */ o4("div", { className: "CopyDocModal__error", children: error }),
|
|
44343
|
+
/* @__PURE__ */ o4("div", { className: "CopyDocModal__buttons", children: [
|
|
44344
|
+
/* @__PURE__ */ o4(
|
|
44345
|
+
Button,
|
|
44346
|
+
{
|
|
44347
|
+
variant: "outline",
|
|
44348
|
+
onClick: () => context.closeModal(id2),
|
|
44349
|
+
type: "button",
|
|
44350
|
+
size: "xs",
|
|
44351
|
+
color: "dark",
|
|
44352
|
+
children: "Cancel"
|
|
44353
|
+
}
|
|
44354
|
+
),
|
|
44355
|
+
/* @__PURE__ */ o4(
|
|
44356
|
+
Button,
|
|
44357
|
+
{
|
|
44358
|
+
variant: "filled",
|
|
44359
|
+
type: "submit",
|
|
44360
|
+
size: "xs",
|
|
44361
|
+
color: "dark",
|
|
44362
|
+
loading,
|
|
44363
|
+
children: "Submit"
|
|
44364
|
+
}
|
|
44365
|
+
)
|
|
44366
|
+
] })
|
|
44367
|
+
] }) });
|
|
44368
|
+
}
|
|
44369
|
+
|
|
44028
44370
|
// ui/ui.tsx
|
|
44029
44371
|
function App() {
|
|
44030
44372
|
return /* @__PURE__ */ o4(
|
|
@@ -44034,7 +44376,7 @@ ${content}</tr>
|
|
|
44034
44376
|
fontFamily: "Inter, sans-serif",
|
|
44035
44377
|
fontSizes: { xs: 12, sm: 14, md: 16, lg: 18, xl: 20 }
|
|
44036
44378
|
},
|
|
44037
|
-
children: /* @__PURE__ */ o4(NotificationsProvider, { children: /* @__PURE__ */ o4(ModalsProvider, { children: /* @__PURE__ */ o4(FirebaseContext.Provider, { value: window.firebase, children: /* @__PURE__ */ o4(D4, { children: [
|
|
44379
|
+
children: /* @__PURE__ */ o4(NotificationsProvider, { children: /* @__PURE__ */ o4(ModalsProvider, { modals: { copyDoc: CopyDocModal }, children: /* @__PURE__ */ o4(FirebaseContext.Provider, { value: window.firebase, children: /* @__PURE__ */ o4(D4, { children: [
|
|
44038
44380
|
/* @__PURE__ */ o4(L6, { path: "/cms", component: ProjectPage }),
|
|
44039
44381
|
/* @__PURE__ */ o4(L6, { path: "/cms/assets", component: AssetsPage }),
|
|
44040
44382
|
/* @__PURE__ */ o4(
|
|
@@ -44102,7 +44444,6 @@ ${content}</tr>
|
|
|
44102
44444
|
console.log(res);
|
|
44103
44445
|
return;
|
|
44104
44446
|
}
|
|
44105
|
-
console.log("updated user session");
|
|
44106
44447
|
}
|
|
44107
44448
|
})();
|
|
44108
44449
|
/*! Bundled license information:
|