@goodfellow-cms/admin 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editor.js +540 -7
- package/dist/{entry-values-BrY3L0Ai.js → entry-values-DO01xZ9L.js} +376 -44
- package/dist/index.d.ts +104 -3
- package/dist/index.js +490 -90
- package/package.json +5 -5
- package/plugin.css +43 -39
- package/styles.css +243 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as CONNECT_MESSAGE, r as createChannel } from "./plugin-protocol-DkvBDqsF.js";
|
|
2
|
-
import { APP_API_HEADER, COLOR_SCHEME_ATTRIBUTE, ConflictError, DraftError, FOOTER_FILE, GOODFELLOW_REGISTRY, HEADER_FILE, MAX_UPLOAD_BYTES, MEDIA_DIR, MENUS_FILE, PluginTaskError, REDIRECTS_FILE, SHADCN_NAMESPACE, SHADCN_REGISTRY, SITE_FILE, ScheduledBuildsError, SignInError, TASK_INPUT_LIMIT, addressPatternFor, adminOrigin, allPages, checkEntrySlug, checkPageAddress, checkSite, codeFileChanges, collectionFileChange, collectionFileChange as collectionFileChange$1, customCssFileChange, deleteCollectionChanges, describedConfig, duplicatePageData, entryFileChange, entryFileChange as entryFileChange$1, entryLanguage, entryPathIn, entryTitle, escapeStyleText, extensionOf, fileName, goodfellowRegistryUrl, googleFontsUrl, isDemoStore, isStorableAddress, keptDrafts, layoutFileChange, loadSiteContent, markdownToHtml, mediaFileChange, mediaKind, mediaKind as mediaKind$1, mediaStorageFileChange, memoryKeeper, menusFileChange, moveEntryChanges, movePageChanges, newCollectionSettings, newDraftName, newPageData, newTaskRequestId, openTaskAnswer, outsideHost, pageFileChange, pageTitle as pageTitle$1, pluginFrameUrl, pluginMayList, pluginMayUse, publishProblems, redirectsFileChange, relinkSite, relinkedChanges, scheduleOf, scheduleProblem, scheduleState, siteLanguages, siteSettingsFileChange, slugify, storedCss, storedData, storedEntryFields, storedMediaUrl, taskKeys, themeToCss, todayIn, trimChars, uniqueName, upcomingChanges, updateSettingsFileChange, uploadName, wallClock, withStoredFiles, withoutCredits, writeChanges } from "@goodfellow-cms/core";
|
|
2
|
+
import { APP_API_HEADER, COLOR_SCHEME_ATTRIBUTE, ConflictError, DraftError, FOOTER_FILE, GOODFELLOW_REGISTRY, HEADER_FILE, MAX_UPLOAD_BYTES, MEDIA_DIR, MENUS_FILE, PluginTaskError, REDIRECTS_FILE, SHADCN_NAMESPACE, SHADCN_REGISTRY, SITE_FILE, ScheduledBuildsError, SignInError, TASK_INPUT_LIMIT, addressPatternFor, adminOrigin, allPages, checkEntrySlug, checkPageAddress, checkSite, codeFileChanges, collectionFileChange, collectionFileChange as collectionFileChange$1, customCssFileChange, deleteCollectionChanges, describedConfig, duplicatePageData, entryFileChange, entryFileChange as entryFileChange$1, entryLanguage, entryPathIn, entryTitle, escapeStyleText, extensionOf, fileName, goodfellowRegistryUrl, googleFontsUrl, isDemoStore, isStorableAddress, keptDrafts, layoutFileChange, limitsFor, loadSiteContent, markdownToHtml, mayChangeEntry, mayChangeLayout, mayChangeMedia, mayChangeMenus, mayChangePage, mediaFileChange, mediaKind, mediaKind as mediaKind$1, mediaStorageFileChange, memoryKeeper, menusFileChange, moveEntryChanges, movePageChanges, newCollectionSettings, newDraftName, newPageData, newTaskRequestId, openTaskAnswer, outsideHost, outsideLimits, pageFileChange, pageTitle as pageTitle$1, pluginFrameUrl, pluginMayList, pluginMayUse, publishProblems, redirectsFileChange, relinkSite, relinkedChanges, reviewersFor, scheduleOf, scheduleProblem, scheduleState, siteLanguages, siteSettingsFileChange, slugify, storedCss, storedData, storedEntryFields, storedMediaUrl, taskKeys, themeToCss, todayIn, trimChars, uniqueName, upcomingChanges, updateSettingsFileChange, uploadName, wallClock, withStoredFiles, withoutCredits, writeChanges } from "@goodfellow-cms/core";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
4
|
import TurndownService from "turndown";
|
|
5
5
|
import { gfm } from "turndown-plugin-gfm";
|
|
@@ -493,7 +493,15 @@ const defaultStrings = {
|
|
|
493
493
|
"editor.failed": "The editor stopped working. Reload the page to start it again.",
|
|
494
494
|
"editor.frame": "Editing {title}",
|
|
495
495
|
"editor.choose": "Editor",
|
|
496
|
+
"editor.blockSearch": "Search blocks",
|
|
497
|
+
"editor.blockSearchNone": "No blocks match. Try another word, such as \"picture\" or \"columns\".",
|
|
498
|
+
"editor.blockSearchFound": "Blocks found",
|
|
496
499
|
"editor.standard": "Standard editor",
|
|
500
|
+
"editor.plugin.switchLoses": "Some of what you changed in {editor} can't be kept in the other editor, so switching now leaves behind everything you changed since you opened {editor}. Switch anyway?\n\n{problems}",
|
|
501
|
+
"editor.plugin.pageSettings": "The page's settings",
|
|
502
|
+
"editor.plugin.problem": "{block}: {message}",
|
|
503
|
+
"editor.plugin.problemField": "{block}, {field}: {message}",
|
|
504
|
+
"editor.plugin.loading": "Opening {editor}…",
|
|
497
505
|
"editor.plugin.failed": "{editor} didn't start. Choose the standard editor to keep editing.",
|
|
498
506
|
"editor.plugin.invalid": "{editor} gave back something this site can't publish, so nothing was published. Try again, or choose the standard editor.",
|
|
499
507
|
"publish.publishing": "Publishing…",
|
|
@@ -522,6 +530,9 @@ const defaultStrings = {
|
|
|
522
530
|
"draft.leave": "Back to the live site",
|
|
523
531
|
"draft.waiting": "A draft started {date} is waiting to be published.",
|
|
524
532
|
"draft.waitingMany": "{count} drafts are waiting to be published.",
|
|
533
|
+
"draft.reviewWaiting": "A draft is waiting for review: {title}.",
|
|
534
|
+
"draft.reviewWaitingMany": "{count} drafts are waiting for review.",
|
|
535
|
+
"draft.inReview": "Submitted for review.",
|
|
525
536
|
"draft.choose": "Draft to open",
|
|
526
537
|
"draft.started": "Started {date}",
|
|
527
538
|
"draft.open": "Open",
|
|
@@ -541,6 +552,22 @@ const defaultStrings = {
|
|
|
541
552
|
"checks.alsoWarnings": "These could be better too:",
|
|
542
553
|
"checks.publishAnyway": "Publish anyway",
|
|
543
554
|
"checks.goBack": "Go back",
|
|
555
|
+
"limits.title": "Some of this is outside what you can change",
|
|
556
|
+
"limits.intro": "An owner has limited what you can change on this site, and these changes are outside it:",
|
|
557
|
+
"limits.review": "Submit them for review instead: the site's reviewers are asked to look, and can publish them for you.",
|
|
558
|
+
"limits.noReview": "Ask an owner to make these changes for you, or to let you make them on Site Settings' Editors screen.",
|
|
559
|
+
"limits.goBack": "Go back",
|
|
560
|
+
"limits.submitting": "Submitting for review…",
|
|
561
|
+
"limits.submitted": "Submitted for review. The live site stays as it is until a reviewer publishes it.",
|
|
562
|
+
"limits.submitError": "The changes couldn't be submitted for review. Check your connection and try again.",
|
|
563
|
+
"limits.page": "The page {name}",
|
|
564
|
+
"limits.entry": "{name}, in {collection}",
|
|
565
|
+
"limits.media": "The media library",
|
|
566
|
+
"limits.layout": "The header and footer",
|
|
567
|
+
"limits.menus": "The menus",
|
|
568
|
+
"limits.other": "The site's settings, or other things only owners change",
|
|
569
|
+
"limits.readOnly": "You can look at this, but an owner has limited what you can change, and it's outside it.",
|
|
570
|
+
"limits.mediaReadOnly": "An owner has limited what you can change, and the media library is outside it. You can still use its files on pages you can change.",
|
|
544
571
|
"checks.missing-page": "{place} links to {target}, which isn't a page on the site.",
|
|
545
572
|
"checks.missing-media": "{place} uses {target}, which isn't in the media library.",
|
|
546
573
|
"checks.no-title": "{place} has no title, so browser tabs and search results show only the site's name.",
|
|
@@ -572,6 +599,7 @@ const defaultStrings = {
|
|
|
572
599
|
"pages.empty": "This site has no pages yet.",
|
|
573
600
|
"pages.column.title": "Title",
|
|
574
601
|
"pages.column.address": "Address",
|
|
602
|
+
"pages.look": "Look",
|
|
575
603
|
"pages.edit": "Edit",
|
|
576
604
|
"pages.move": "Change address",
|
|
577
605
|
"pages.duplicate": "Duplicate",
|
|
@@ -633,7 +661,7 @@ const defaultStrings = {
|
|
|
633
661
|
"deletePage.submit": "Delete page",
|
|
634
662
|
"deletePage.message": "Delete page \"{title}\"",
|
|
635
663
|
"address.invalid": "Use lowercase letters, numbers and hyphens, with / between parts, such as /about-us.",
|
|
636
|
-
"address.reserved": "This address
|
|
664
|
+
"address.reserved": "This address can't be used: the admin panel uses it, or it ends in /index, which is the page above it. Choose another.",
|
|
637
665
|
"address.taken": "Another page already uses this address.",
|
|
638
666
|
"field.required": "This can't be empty.",
|
|
639
667
|
"editPage.message": "Update page \"{title}\"",
|
|
@@ -711,7 +739,7 @@ const defaultStrings = {
|
|
|
711
739
|
"newEntry.addressHint": "The last part of the page's address, as in {example}.",
|
|
712
740
|
"newEntry.message": "Add {entry} \"{title}\"",
|
|
713
741
|
"entryName.invalid": "Use lowercase letters, numbers and hyphens only, such as easter-vigil.",
|
|
714
|
-
"entryName.reserved": "This address
|
|
742
|
+
"entryName.reserved": "This address can't be used: the admin panel uses it, or it ends in /index, which is the page above it. Choose another.",
|
|
715
743
|
"entryName.taken": "Something else on the site already uses this address.",
|
|
716
744
|
"moveEntry.message": "Move {entry} \"{title}\" from {from} to {to}",
|
|
717
745
|
"deleteEntry.body": "{title} will be removed from {name}.",
|
|
@@ -904,6 +932,51 @@ const defaultStrings = {
|
|
|
904
932
|
"table.removeColumn": "Remove this column",
|
|
905
933
|
"table.removeColumnNumber": "Remove column {column}",
|
|
906
934
|
"table.cell": "Row {row}, column {column}",
|
|
935
|
+
"style.align": "Text alignment",
|
|
936
|
+
"style.align.default": "As the block has it",
|
|
937
|
+
"style.align.left": "Left",
|
|
938
|
+
"style.align.center": "Centered",
|
|
939
|
+
"style.align.right": "Right",
|
|
940
|
+
"style.align.justify": "Justified",
|
|
941
|
+
"style.fontSize": "Text size",
|
|
942
|
+
"style.fontSize.xs": "Extra small",
|
|
943
|
+
"style.fontSize.sm": "Small",
|
|
944
|
+
"style.fontSize.base": "Normal",
|
|
945
|
+
"style.fontSize.lg": "Large",
|
|
946
|
+
"style.fontSize.xl": "Extra large",
|
|
947
|
+
"style.fontSize.2xl": "Very large",
|
|
948
|
+
"style.fontSize.3xl": "Huge",
|
|
949
|
+
"style.fontSize.4xl": "Very huge",
|
|
950
|
+
"style.fontSize.5xl": "Giant",
|
|
951
|
+
"style.fontSize.6xl": "Enormous",
|
|
952
|
+
"style.color": "Text color",
|
|
953
|
+
"style.background": "Background color",
|
|
954
|
+
"style.colorDefault": "As the block has it",
|
|
955
|
+
"style.colorCustom": "Choose a color",
|
|
956
|
+
"style.contrast": "This text may be hard to read on this background. Try colors further apart.",
|
|
957
|
+
"style.padding": "Space inside",
|
|
958
|
+
"style.margin": "Space around",
|
|
959
|
+
"style.eachSide": "Set each side",
|
|
960
|
+
"style.side.top": "Top",
|
|
961
|
+
"style.side.right": "Right",
|
|
962
|
+
"style.side.bottom": "Bottom",
|
|
963
|
+
"style.side.left": "Left",
|
|
964
|
+
"style.allSides": "All sides",
|
|
965
|
+
"style.none": "None",
|
|
966
|
+
"style.radius": "Rounded corners",
|
|
967
|
+
"style.radius.none": "Square",
|
|
968
|
+
"style.radius.sm": "Slightly rounded",
|
|
969
|
+
"style.radius.md": "Rounded",
|
|
970
|
+
"style.radius.lg": "The theme's rounding",
|
|
971
|
+
"style.radius.xl": "Very rounded",
|
|
972
|
+
"style.radius.full": "Round",
|
|
973
|
+
"style.default": "As the block has it",
|
|
974
|
+
"style.custom": "Your own…",
|
|
975
|
+
"style.customLength": "Your own size, such as 12px or 1.5rem",
|
|
976
|
+
"style.customLengthInvalid": "Write a number with px, rem, em or %, such as 12px.",
|
|
977
|
+
"style.other": "Other CSS classes",
|
|
978
|
+
"style.otherHint": "Tailwind classes, or your own from Custom CSS, separated by spaces.",
|
|
979
|
+
"style.reset": "Back to the block's own look",
|
|
907
980
|
"media.credit": "Credit: {credit}",
|
|
908
981
|
"media.stored": "Kept by {plugin}",
|
|
909
982
|
"media.error.storageSize": "{name} is too large: {plugin} takes files up to {size}.",
|
|
@@ -1014,6 +1087,7 @@ const defaultStrings = {
|
|
|
1014
1087
|
"settings.previewEmpty": "Add a home page to see a preview here.",
|
|
1015
1088
|
"domain.intro": "Connect a domain you own, such as example.org, so the site is at that address.",
|
|
1016
1089
|
"domain.current": "The site is at {address} now.",
|
|
1090
|
+
"domain.copy": "This admin panel is a copy of the site's, such as a staging site, at {address}. That address is set where the copy is built, so the domain this screen connects is the main site's.",
|
|
1017
1091
|
"domain.connected": "Connected to {domain}.",
|
|
1018
1092
|
"domain.signIn": "Editors sign in by going to {host} and coming back here. Add {address} to the redirect URIs of the application they sign in with on {host}, or signing in will stop working once the site moves.",
|
|
1019
1093
|
"domain.local": "Domains are connected in the published site's admin panel, where you sign in with GitHub, GitLab or Bitbucket.",
|
|
@@ -1540,7 +1614,7 @@ const defaultStrings = {
|
|
|
1540
1614
|
"updates.error.save": "The change couldn't be saved. Try again in a moment.",
|
|
1541
1615
|
"updates.error.other": "Something went wrong. Try again in a moment.",
|
|
1542
1616
|
"editors.intro": "The people who can edit this site.",
|
|
1543
|
-
"editors.roles": "Editors can change and publish everything in the admin panel. Owners can also invite and remove editors, and connect a domain.",
|
|
1617
|
+
"editors.roles": "Editors can change and publish everything in the admin panel, unless their limits below say otherwise. Owners can also invite and remove editors, limit what they can change, and connect a domain.",
|
|
1544
1618
|
"editors.local": "Editors are invited in the published site's admin panel, where you sign in with GitHub, GitLab or Bitbucket.",
|
|
1545
1619
|
"editors.demo": "Editors can't be invited in a demo.",
|
|
1546
1620
|
"editors.loading": "Loading editors…",
|
|
@@ -1576,6 +1650,33 @@ const defaultStrings = {
|
|
|
1576
1650
|
"editors.error.invalid": "That isn't a username or email address that {host} accepts.",
|
|
1577
1651
|
"editors.error.already": "They already edit the site, or have been invited.",
|
|
1578
1652
|
"editors.error.other": "Something went wrong. Try again in a moment.",
|
|
1653
|
+
"permissions.title": "Limits",
|
|
1654
|
+
"permissions.intro": "Limit what someone can change: some pages, some collections, the media library, the header and footer, or the menus. Anyone not listed here can change everything their role allows. Changes outside someone's limits go to a reviewer, who publishes them or not.",
|
|
1655
|
+
"permissions.where": "The admin panel keeps people to their limits, so nobody changes the wrong page by mistake. People who can publish to the site on {host} could still change other files there, so only a site with its own server holds everyone to them.",
|
|
1656
|
+
"permissions.whereServer": "The site's server holds everyone to their limits, whatever they try.",
|
|
1657
|
+
"permissions.host": "the site's host",
|
|
1658
|
+
"permissions.person": "Their username",
|
|
1659
|
+
"permissions.personHint": "The name they sign in with, as the list above shows it.",
|
|
1660
|
+
"permissions.add": "Limit what they can change",
|
|
1661
|
+
"permissions.change": "Change",
|
|
1662
|
+
"permissions.remove": "Remove limits",
|
|
1663
|
+
"permissions.nothing": "Nothing yet",
|
|
1664
|
+
"permissions.allPages": "Every page",
|
|
1665
|
+
"permissions.editTitle": "What {name} can change",
|
|
1666
|
+
"permissions.editIntro": "Tick what they can change. They can look at everything else, and submit changes to it for review.",
|
|
1667
|
+
"permissions.pages": "Pages",
|
|
1668
|
+
"permissions.pagesHint": "Each with the pages under it, and their translations.",
|
|
1669
|
+
"permissions.collections": "Collections' items",
|
|
1670
|
+
"permissions.more": "Also",
|
|
1671
|
+
"permissions.languages": "Languages",
|
|
1672
|
+
"permissions.everyLanguage": "Every language",
|
|
1673
|
+
"permissions.save": "Publish limits",
|
|
1674
|
+
"permissions.message": "Change what {name} can change",
|
|
1675
|
+
"permissions.removeMessage": "Let {name} change everything",
|
|
1676
|
+
"permissions.reviewers": "Who reviews changes outside someone's limits",
|
|
1677
|
+
"permissions.reviewersHint": "Usernames, separated by commas. Leave it empty for every owner.",
|
|
1678
|
+
"permissions.saveReviewers": "Publish reviewers",
|
|
1679
|
+
"permissions.reviewersMessage": "Change who reviews changes outside editors' limits",
|
|
1579
1680
|
"general.siteTitle": "Site name",
|
|
1580
1681
|
"general.description": "Description",
|
|
1581
1682
|
"general.descriptionHint": "Shown by search engines when a page doesn't have its own description.",
|
|
@@ -2235,6 +2336,119 @@ function SiteCodeFrame({ onClient }) {
|
|
|
2235
2336
|
});
|
|
2236
2337
|
}
|
|
2237
2338
|
//#endregion
|
|
2339
|
+
//#region src/limits-dialog.tsx
|
|
2340
|
+
/** What a change outside someone's limits touches, in words. Files that are none of those are named once, together. */
|
|
2341
|
+
function describeLimitProblems(t, content, problems) {
|
|
2342
|
+
const described = /* @__PURE__ */ new Set();
|
|
2343
|
+
const pages = allPages(content);
|
|
2344
|
+
for (const problem of problems) if (problem.kind === "page") {
|
|
2345
|
+
const title = (pages.find((found) => found.path === problem.address)?.content.data.root.props)?.title;
|
|
2346
|
+
described.add(t("limits.page", { name: typeof title === "string" && title ? title : problem.address }));
|
|
2347
|
+
} else if (problem.kind === "entry") {
|
|
2348
|
+
const collection = content.collections.find((found) => found.id === problem.collection);
|
|
2349
|
+
const title = (collection?.entries.find((found) => found.slug === problem.slug))?.content.fields.title;
|
|
2350
|
+
described.add(t("limits.entry", {
|
|
2351
|
+
name: typeof title === "string" && title ? title : problem.slug,
|
|
2352
|
+
collection: collection?.settings.name ?? problem.collection
|
|
2353
|
+
}));
|
|
2354
|
+
} else described.add(t(`limits.${problem.kind}`));
|
|
2355
|
+
return [...described];
|
|
2356
|
+
}
|
|
2357
|
+
/**
|
|
2358
|
+
* Changes outside what someone may change: listed, with what they can do
|
|
2359
|
+
* instead, submitting them for review where the site can take one.
|
|
2360
|
+
*/
|
|
2361
|
+
function LimitsDialog({ problems, content, onSubmit, onClose }) {
|
|
2362
|
+
const t = useStrings();
|
|
2363
|
+
const [state, setState] = useState({ type: "asking" });
|
|
2364
|
+
const submit = async () => {
|
|
2365
|
+
if (!onSubmit) return;
|
|
2366
|
+
setState({ type: "submitting" });
|
|
2367
|
+
try {
|
|
2368
|
+
setState({
|
|
2369
|
+
type: "submitted",
|
|
2370
|
+
...await onSubmit()
|
|
2371
|
+
});
|
|
2372
|
+
} catch (error) {
|
|
2373
|
+
setState({
|
|
2374
|
+
type: "error",
|
|
2375
|
+
error
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
return /* @__PURE__ */ jsxs(Dialog, {
|
|
2380
|
+
title: t("limits.title"),
|
|
2381
|
+
onClose,
|
|
2382
|
+
children: [
|
|
2383
|
+
/* @__PURE__ */ jsx("p", { children: t("limits.intro") }),
|
|
2384
|
+
/* @__PURE__ */ jsx("ul", {
|
|
2385
|
+
className: "gfa-check-list",
|
|
2386
|
+
children: describeLimitProblems(t, content, problems).map((line) => /* @__PURE__ */ jsx("li", { children: line }, line))
|
|
2387
|
+
}),
|
|
2388
|
+
state.type === "submitted" ? /* @__PURE__ */ jsxs("p", {
|
|
2389
|
+
role: "status",
|
|
2390
|
+
children: [
|
|
2391
|
+
t("limits.submitted"),
|
|
2392
|
+
" ",
|
|
2393
|
+
state.url && /* @__PURE__ */ jsx("a", {
|
|
2394
|
+
href: state.url,
|
|
2395
|
+
target: "_blank",
|
|
2396
|
+
rel: "noreferrer",
|
|
2397
|
+
children: t("draft.seeReview")
|
|
2398
|
+
})
|
|
2399
|
+
]
|
|
2400
|
+
}) : /* @__PURE__ */ jsx("p", { children: t(onSubmit ? "limits.review" : "limits.noReview") }),
|
|
2401
|
+
state.type === "error" && /* @__PURE__ */ jsx(ErrorMessage, {
|
|
2402
|
+
message: t("limits.submitError"),
|
|
2403
|
+
error: state.error
|
|
2404
|
+
}),
|
|
2405
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2406
|
+
className: "gfa-dialog-actions",
|
|
2407
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
2408
|
+
onClick: onClose,
|
|
2409
|
+
children: t(state.type === "submitted" ? "action.close" : "limits.goBack")
|
|
2410
|
+
}), onSubmit && state.type !== "submitted" && /* @__PURE__ */ jsx(Button, {
|
|
2411
|
+
variant: "primary",
|
|
2412
|
+
disabled: state.type === "submitting",
|
|
2413
|
+
onClick: () => void submit(),
|
|
2414
|
+
children: t(state.type === "submitting" ? "limits.submitting" : "draft.submit")
|
|
2415
|
+
})]
|
|
2416
|
+
})
|
|
2417
|
+
]
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2420
|
+
//#endregion
|
|
2421
|
+
//#region src/limits.ts
|
|
2422
|
+
/**
|
|
2423
|
+
* What the signed-in person may change, for screens that show the rest
|
|
2424
|
+
* read-only. Publishing checks every change again (`outsideLimits()`), so
|
|
2425
|
+
* these only spare people changes they couldn't publish.
|
|
2426
|
+
*/
|
|
2427
|
+
/** Whether someone with `limits` may change what's open. Collections' templates are their settings, which limits never cover. */
|
|
2428
|
+
function mayChange(content, limits, what) {
|
|
2429
|
+
if (!limits) return true;
|
|
2430
|
+
switch (what.kind) {
|
|
2431
|
+
case "page": {
|
|
2432
|
+
const page = content.pages.find((found) => found.path === what.path);
|
|
2433
|
+
return mayChangePage(content, limits, page ?? { path: what.path });
|
|
2434
|
+
}
|
|
2435
|
+
case "header":
|
|
2436
|
+
case "footer": return mayChangeLayout(content, limits, what.language);
|
|
2437
|
+
case "template": return false;
|
|
2438
|
+
case "entry": {
|
|
2439
|
+
const entry = content.collections.find((found) => found.id === what.collection)?.entries.find((found) => found.slug === what.entry);
|
|
2440
|
+
return entry ? mayChangeEntry(content, limits, entry) : (limits.collections ?? []).includes(what.collection);
|
|
2441
|
+
}
|
|
2442
|
+
case "media": return mayChangeMedia(limits);
|
|
2443
|
+
case "menus": return mayChangeMenus(content, limits, what.language);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
/** Whether the signed-in person may change what's open, once the site has loaded. */
|
|
2447
|
+
function useMayChange(what) {
|
|
2448
|
+
const { state, limits } = useAdmin();
|
|
2449
|
+
return state.status !== "ready" || mayChange(state.content, limits, what);
|
|
2450
|
+
}
|
|
2451
|
+
//#endregion
|
|
2238
2452
|
//#region src/media-previews.ts
|
|
2239
2453
|
const TYPES = {
|
|
2240
2454
|
jpg: "image/jpeg",
|
|
@@ -3632,6 +3846,7 @@ function MediaScreen() {
|
|
|
3632
3846
|
const [copied, setCopied] = useState(null);
|
|
3633
3847
|
const [moved, setMoved] = useState();
|
|
3634
3848
|
const searchId = useId();
|
|
3849
|
+
const mayChange = useMayChange({ kind: "media" });
|
|
3635
3850
|
useEffect(() => {
|
|
3636
3851
|
const stop = (event) => {
|
|
3637
3852
|
if (event.dataTransfer?.types.includes("Files")) event.preventDefault();
|
|
@@ -3650,7 +3865,7 @@ function MediaScreen() {
|
|
|
3650
3865
|
children: [
|
|
3651
3866
|
/* @__PURE__ */ jsxs("div", {
|
|
3652
3867
|
className: "gfa-screen-header",
|
|
3653
|
-
children: [/* @__PURE__ */ jsx("h1", { children: t("media.title") }), /* @__PURE__ */ jsx(UploadButton, {
|
|
3868
|
+
children: [/* @__PURE__ */ jsx("h1", { children: t("media.title") }), mayChange && /* @__PURE__ */ jsx(UploadButton, {
|
|
3654
3869
|
label: t("media.upload"),
|
|
3655
3870
|
disabled: status.type === "uploading",
|
|
3656
3871
|
onFiles: (files) => void run(files)
|
|
@@ -3660,6 +3875,11 @@ function MediaScreen() {
|
|
|
3660
3875
|
className: "gfa-hint",
|
|
3661
3876
|
children: t("media.intro")
|
|
3662
3877
|
}),
|
|
3878
|
+
!mayChange && /* @__PURE__ */ jsx("p", {
|
|
3879
|
+
className: "gfa-notice",
|
|
3880
|
+
role: "note",
|
|
3881
|
+
children: t("limits.mediaReadOnly")
|
|
3882
|
+
}),
|
|
3663
3883
|
cloudflareVideos && /* @__PURE__ */ jsxs("p", {
|
|
3664
3884
|
className: "gfa-notice",
|
|
3665
3885
|
role: "note",
|
|
@@ -3674,7 +3894,7 @@ function MediaScreen() {
|
|
|
3674
3894
|
})
|
|
3675
3895
|
]
|
|
3676
3896
|
}),
|
|
3677
|
-
/* @__PURE__ */ jsx(StorageSection, { onDone: setMoved }),
|
|
3897
|
+
mayChange && /* @__PURE__ */ jsx(StorageSection, { onDone: setMoved }),
|
|
3678
3898
|
moved && /* @__PURE__ */ jsx("p", {
|
|
3679
3899
|
className: "gfa-notice gfa-notice-success",
|
|
3680
3900
|
role: "status",
|
|
@@ -3696,7 +3916,7 @@ function MediaScreen() {
|
|
|
3696
3916
|
})]
|
|
3697
3917
|
}),
|
|
3698
3918
|
/* @__PURE__ */ jsx(DropZone, {
|
|
3699
|
-
onFiles: (files) => void run(files),
|
|
3919
|
+
onFiles: (files) => void (mayChange && run(files)),
|
|
3700
3920
|
children: media.length === 0 ? /* @__PURE__ */ jsx("p", { children: t("media.empty") }) : urls.length === 0 ? /* @__PURE__ */ jsx("p", { children: t("media.noMatches") }) : /* @__PURE__ */ jsx("ul", {
|
|
3701
3921
|
className: "gfa-media-grid",
|
|
3702
3922
|
children: urls.map((url) => /* @__PURE__ */ jsxs("li", {
|
|
@@ -3715,25 +3935,21 @@ function MediaScreen() {
|
|
|
3715
3935
|
}),
|
|
3716
3936
|
/* @__PURE__ */ jsxs("div", {
|
|
3717
3937
|
className: "gfa-media-actions",
|
|
3718
|
-
children: [
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
onClick: () => setDeleting(url),
|
|
3734
|
-
children: t("media.delete")
|
|
3735
|
-
})
|
|
3736
|
-
]
|
|
3938
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
3939
|
+
variant: "ghost",
|
|
3940
|
+
onClick: () => void navigator.clipboard?.writeText(url).then(() => setCopied(url), () => setCopied(null)),
|
|
3941
|
+
children: copied === url ? t("media.copied") : t("media.copy")
|
|
3942
|
+
}), mayChange && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(UploadButton, {
|
|
3943
|
+
label: t("media.replace"),
|
|
3944
|
+
variant: "secondary",
|
|
3945
|
+
multiple: false,
|
|
3946
|
+
disabled: status.type === "uploading",
|
|
3947
|
+
onFiles: (files) => void run(files.slice(0, 1), mediaPath(url))
|
|
3948
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
3949
|
+
variant: "ghost",
|
|
3950
|
+
onClick: () => setDeleting(url),
|
|
3951
|
+
children: t("media.delete")
|
|
3952
|
+
})] })]
|
|
3737
3953
|
})
|
|
3738
3954
|
]
|
|
3739
3955
|
}, url))
|
|
@@ -3967,7 +4183,7 @@ function pluginSecretsHelp(place, plugin, t) {
|
|
|
3967
4183
|
//#endregion
|
|
3968
4184
|
//#region src/registry-version.ts
|
|
3969
4185
|
/** The release of Goodfellow's block registry this admin panel was built with, so a site gets blocks that match it. */
|
|
3970
|
-
const REGISTRY_VERSION = "0.
|
|
4186
|
+
const REGISTRY_VERSION = "0.7.0";
|
|
3971
4187
|
//#endregion
|
|
3972
4188
|
//#region src/schedule.tsx
|
|
3973
4189
|
/** The computer's own time zone, which a site without one takes when something is first scheduled. */
|
|
@@ -4318,13 +4534,15 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4318
4534
|
const [draftPaths, setDraftPaths] = useState([]);
|
|
4319
4535
|
const content = draft?.store ?? store;
|
|
4320
4536
|
const [checking, setChecking] = useState();
|
|
4537
|
+
const [limiting, setLimiting] = useState();
|
|
4538
|
+
const [draftReviews, setDraftReviews] = useState([]);
|
|
4321
4539
|
const blocks = useMemo(() => describedConfig(site.description, "template").components, [site.description]);
|
|
4322
4540
|
const storage = useRef(void 0);
|
|
4323
4541
|
storage.current = state.status === "ready" ? state.content.mediaStorage : void 0;
|
|
4324
4542
|
const mediaPreviews = useMemo(() => createMediaPreviews(content, siteUrl, () => storage.current), [content, siteUrl]);
|
|
4325
4543
|
const outOfReach = registry !== void 0 || atAdminAddress(site.admin) || site.broker !== void 0;
|
|
4326
4544
|
const registries = useMemo(() => ({
|
|
4327
|
-
[GOODFELLOW_REGISTRY]: registry ?? goodfellowRegistryUrl("0.
|
|
4545
|
+
[GOODFELLOW_REGISTRY]: registry ?? goodfellowRegistryUrl("0.7.0"),
|
|
4328
4546
|
...outOfReach && {
|
|
4329
4547
|
[SHADCN_NAMESPACE]: SHADCN_REGISTRY,
|
|
4330
4548
|
...site.registries
|
|
@@ -4422,9 +4640,14 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4422
4640
|
reload
|
|
4423
4641
|
]);
|
|
4424
4642
|
const refreshDrafts = useCallback(async (current) => {
|
|
4425
|
-
const [names, paths] = await Promise.all([
|
|
4643
|
+
const [names, paths, reviews] = await Promise.all([
|
|
4644
|
+
siteDrafts.list().catch(() => []),
|
|
4645
|
+
current ? current.paths().catch(() => []) : [],
|
|
4646
|
+
siteDrafts.reviews().catch(() => [])
|
|
4647
|
+
]);
|
|
4426
4648
|
setDraftNames(names);
|
|
4427
4649
|
setDraftPaths(paths);
|
|
4650
|
+
setDraftReviews(reviews);
|
|
4428
4651
|
}, [siteDrafts]);
|
|
4429
4652
|
useEffect(() => {
|
|
4430
4653
|
if (draftFound) refreshDrafts(draft);
|
|
@@ -4444,12 +4667,64 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4444
4667
|
setChecking(void 0);
|
|
4445
4668
|
return go;
|
|
4446
4669
|
}, []);
|
|
4670
|
+
const limits = useMemo(() => state.status === "ready" ? limitsFor(state.content.permissions, account?.user.login) : void 0, [state, account]);
|
|
4671
|
+
/** Who's asked to review: those the permissions name, else every owner, never the one asking. */
|
|
4672
|
+
const reviewers = useCallback(async () => {
|
|
4673
|
+
const owners = await editors?.list().then((list) => list.editors.flatMap((editor) => editor.role === "owner" && editor.login ? [editor.login] : [])).catch(() => []);
|
|
4674
|
+
const self = account?.user.login.toLowerCase();
|
|
4675
|
+
const permissions = state.status === "ready" ? state.content.permissions : void 0;
|
|
4676
|
+
return reviewersFor(permissions, owners ?? []).filter((login) => login.toLowerCase() !== self);
|
|
4677
|
+
}, [
|
|
4678
|
+
editors,
|
|
4679
|
+
account,
|
|
4680
|
+
state
|
|
4681
|
+
]);
|
|
4682
|
+
/** Shows what's outside someone's limits, and lets them submit it for review where the site can take one. */
|
|
4683
|
+
const askLimits = useCallback((problems, shown, submit) => new Promise((done) => setLimiting({
|
|
4684
|
+
problems,
|
|
4685
|
+
content: shown,
|
|
4686
|
+
...submit && { submit },
|
|
4687
|
+
done
|
|
4688
|
+
})), []);
|
|
4447
4689
|
const publish = useCallback(async (changes, message, options) => {
|
|
4448
4690
|
if (state.status !== "ready") return {
|
|
4449
4691
|
ok: false,
|
|
4450
4692
|
reason: "error",
|
|
4451
4693
|
error: /* @__PURE__ */ new Error("The site isn't loaded.")
|
|
4452
4694
|
};
|
|
4695
|
+
const outside = draft || options?.draft ? [] : outsideLimits(state.content, limits, changes);
|
|
4696
|
+
if (outside.length > 0) {
|
|
4697
|
+
const from = state.revision;
|
|
4698
|
+
const description = [
|
|
4699
|
+
t("draft.reviewDescription"),
|
|
4700
|
+
"",
|
|
4701
|
+
...changes.map((change) => `- \`${change.path}\``)
|
|
4702
|
+
].join("\n");
|
|
4703
|
+
const submit = backendDrafts ? async () => {
|
|
4704
|
+
const review = await siteDrafts.create(newDraftName(), { from });
|
|
4705
|
+
await writeChanges(review.store, changes, {
|
|
4706
|
+
message,
|
|
4707
|
+
expectedRevision: await review.store.revision()
|
|
4708
|
+
});
|
|
4709
|
+
const { url } = await review.submitForReview({
|
|
4710
|
+
title: message,
|
|
4711
|
+
description,
|
|
4712
|
+
reviewers: await reviewers()
|
|
4713
|
+
});
|
|
4714
|
+
refreshDrafts(void 0);
|
|
4715
|
+
return { url };
|
|
4716
|
+
} : account?.review ? () => account.review?.(changes, {
|
|
4717
|
+
title: message,
|
|
4718
|
+
description,
|
|
4719
|
+
from
|
|
4720
|
+
}) ?? Promise.resolve({}) : void 0;
|
|
4721
|
+
await askLimits(outside, state.content, submit);
|
|
4722
|
+
return {
|
|
4723
|
+
ok: false,
|
|
4724
|
+
reason: "checks",
|
|
4725
|
+
error: void 0
|
|
4726
|
+
};
|
|
4727
|
+
}
|
|
4453
4728
|
const checks = options?.checks === false ? void 0 : await checkPublish(content, state, changes, {
|
|
4454
4729
|
blocks,
|
|
4455
4730
|
code
|
|
@@ -4504,7 +4779,13 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4504
4779
|
confirmChecks,
|
|
4505
4780
|
refreshDrafts,
|
|
4506
4781
|
loadFrom,
|
|
4507
|
-
onSignInError
|
|
4782
|
+
onSignInError,
|
|
4783
|
+
limits,
|
|
4784
|
+
backendDrafts,
|
|
4785
|
+
account,
|
|
4786
|
+
askLimits,
|
|
4787
|
+
reviewers,
|
|
4788
|
+
t
|
|
4508
4789
|
]);
|
|
4509
4790
|
const openDraft = useCallback(async (name) => {
|
|
4510
4791
|
if (name === draft?.name) return true;
|
|
@@ -4548,6 +4829,29 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4548
4829
|
reason: "error",
|
|
4549
4830
|
error: live.status === "error" && live.error
|
|
4550
4831
|
};
|
|
4832
|
+
const outside = outsideLimits(live.content, limitsFor(live.content.permissions, account?.user.login), changes);
|
|
4833
|
+
if (outside.length > 0) {
|
|
4834
|
+
const current = draft;
|
|
4835
|
+
const submit = backendDrafts ? async () => {
|
|
4836
|
+
const paths = changes.map((change) => change.path);
|
|
4837
|
+
return current.submitForReview({
|
|
4838
|
+
title: t("draft.reviewTitle", { name: current.name }),
|
|
4839
|
+
description: [
|
|
4840
|
+
t("draft.reviewDescription"),
|
|
4841
|
+
"",
|
|
4842
|
+
...paths.map((path) => `- \`${path}\``)
|
|
4843
|
+
].join("\n"),
|
|
4844
|
+
reviewers: await reviewers()
|
|
4845
|
+
});
|
|
4846
|
+
} : void 0;
|
|
4847
|
+
await askLimits(outside, live.content, submit);
|
|
4848
|
+
refreshDrafts(current);
|
|
4849
|
+
return {
|
|
4850
|
+
ok: false,
|
|
4851
|
+
reason: "checks",
|
|
4852
|
+
error: void 0
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4551
4855
|
if (!await confirmChecks(await checkPublish(store, live, changes, {
|
|
4552
4856
|
blocks,
|
|
4553
4857
|
code
|
|
@@ -4584,7 +4888,12 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4584
4888
|
key,
|
|
4585
4889
|
t,
|
|
4586
4890
|
confirmChecks,
|
|
4587
|
-
onSignInError
|
|
4891
|
+
onSignInError,
|
|
4892
|
+
account,
|
|
4893
|
+
backendDrafts,
|
|
4894
|
+
askLimits,
|
|
4895
|
+
reviewers,
|
|
4896
|
+
refreshDrafts
|
|
4588
4897
|
]);
|
|
4589
4898
|
const submitDraft = useCallback(async () => {
|
|
4590
4899
|
if (!draft) return {
|
|
@@ -4599,8 +4908,10 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4599
4908
|
t("draft.reviewDescription"),
|
|
4600
4909
|
"",
|
|
4601
4910
|
...paths.map((path) => `- \`${path}\``)
|
|
4602
|
-
].join("\n")
|
|
4911
|
+
].join("\n"),
|
|
4912
|
+
reviewers: await reviewers()
|
|
4603
4913
|
});
|
|
4914
|
+
refreshDrafts(draft);
|
|
4604
4915
|
return {
|
|
4605
4916
|
ok: true,
|
|
4606
4917
|
url
|
|
@@ -4611,7 +4922,12 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4611
4922
|
error
|
|
4612
4923
|
};
|
|
4613
4924
|
}
|
|
4614
|
-
}, [
|
|
4925
|
+
}, [
|
|
4926
|
+
draft,
|
|
4927
|
+
t,
|
|
4928
|
+
reviewers,
|
|
4929
|
+
refreshDrafts
|
|
4930
|
+
]);
|
|
4615
4931
|
const discardDraft = useCallback(async () => {
|
|
4616
4932
|
if (!draft) return { ok: true };
|
|
4617
4933
|
try {
|
|
@@ -4630,6 +4946,7 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4630
4946
|
const drafts = useMemo(() => ({
|
|
4631
4947
|
kept: backendDrafts === void 0,
|
|
4632
4948
|
names: draftNames,
|
|
4949
|
+
reviews: draftReviews,
|
|
4633
4950
|
...draft && { current: {
|
|
4634
4951
|
name: draft.name,
|
|
4635
4952
|
paths: draftPaths
|
|
@@ -4641,6 +4958,7 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4641
4958
|
}), [
|
|
4642
4959
|
backendDrafts,
|
|
4643
4960
|
draftNames,
|
|
4961
|
+
draftReviews,
|
|
4644
4962
|
draft,
|
|
4645
4963
|
draftPaths,
|
|
4646
4964
|
openDraft,
|
|
@@ -4692,6 +5010,7 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4692
5010
|
const pluginInstalls = demo || contentOnly ? void 0 : account?.review ? "review" : atAdminAddress(site.admin) || site.broker !== void 0 ? "publish" : void 0;
|
|
4693
5011
|
const value = useMemo(() => ({
|
|
4694
5012
|
site,
|
|
5013
|
+
...limits && { limits },
|
|
4695
5014
|
blocks,
|
|
4696
5015
|
code,
|
|
4697
5016
|
preview,
|
|
@@ -4724,6 +5043,7 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4724
5043
|
tasks
|
|
4725
5044
|
}), [
|
|
4726
5045
|
site,
|
|
5046
|
+
limits,
|
|
4727
5047
|
blocks,
|
|
4728
5048
|
code,
|
|
4729
5049
|
preview,
|
|
@@ -4766,16 +5086,28 @@ function AdminProvider({ site, frames, store, account, preview, siteUrl, registr
|
|
|
4766
5086
|
value,
|
|
4767
5087
|
children: /* @__PURE__ */ jsxs(StringsProvider, {
|
|
4768
5088
|
strings,
|
|
4769
|
-
children: [
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
5089
|
+
children: [
|
|
5090
|
+
state.status === "ready" ? /* @__PURE__ */ jsx(SiteFrames, {
|
|
5091
|
+
frames,
|
|
5092
|
+
state,
|
|
5093
|
+
onCodeClient,
|
|
5094
|
+
children
|
|
5095
|
+
}) : children,
|
|
5096
|
+
checking && /* @__PURE__ */ jsx(ChecksDialog, {
|
|
5097
|
+
checks: checking.checks,
|
|
5098
|
+
content: checking.content,
|
|
5099
|
+
onDecide: checking.decide
|
|
5100
|
+
}),
|
|
5101
|
+
limiting && /* @__PURE__ */ jsx(LimitsDialog, {
|
|
5102
|
+
problems: limiting.problems,
|
|
5103
|
+
content: limiting.content,
|
|
5104
|
+
...limiting.submit && { onSubmit: limiting.submit },
|
|
5105
|
+
onClose: () => {
|
|
5106
|
+
setLimiting(void 0);
|
|
5107
|
+
limiting.done();
|
|
5108
|
+
}
|
|
5109
|
+
})
|
|
5110
|
+
]
|
|
4779
5111
|
})
|
|
4780
5112
|
});
|
|
4781
5113
|
}
|
|
@@ -5079,4 +5411,4 @@ function formValues(collection, entry) {
|
|
|
5079
5411
|
return values;
|
|
5080
5412
|
}
|
|
5081
5413
|
//#endregion
|
|
5082
|
-
export {
|
|
5414
|
+
export { PublishedNotice as $, useRoute as A, pageFileChange as At, mayChange as B, editedMarkdown as Bt, AppLink as C, layoutFileChange as Ct, hasUnsavedChanges as D, movePageChanges as Dt, entryEditorHref as E, moveEntryChanges as Et, PluginScreenFrame as F, storedCss as Ft, useFrameServices as G, FrameServicesProvider as H, usePluginFrame as I, storedData as It, draftStarted as J, useFrameUpdates as K, usePluginHost as L, storedEntryFields as Lt, prepareUpload as M, redirectsFileChange as Mt, useOutsideHost as N, siteSettingsFileChange as Nt, navigate as O, newCollectionSettings as Ot, PublishFailure as P, slugify as Pt, Field as Q, createMediaPreviews as R, uniqueName as Rt, MediaScreen as S, entryFileChange$1 as St, collectionHref as T, menusFileChange as Tt, reloadFrames as U, useMayChange as V, formattedHtml as Vt, useFrame as W, Dialog as X, Button as Y, ErrorMessage as Z, scheduleSettingsChanges as _, collectionFileChange$1 as _t, AdminContext as a, useStrings as at, MediaChooser as b, deleteCollectionChanges as bt, useCanChangeSettings as c, allMedia as ct, useApplyThemeChoice as d, siteImages as dt, TextField as et, useDarkMode as f, uploadName as ft, ScheduleStatus as g, codeFileChanges as gt, ScheduleFields as h, checkPageAddress as ht, usePreviewStyles as i, useStringTable as it, useUnsavedChanges as j, pageTitle$1 as jt, pageEditorHref as k, newPageData as kt, useSiteContent as l, fileName as lt, ComingUp as m, checkEntrySlug as mt, formValues as n, StringsProvider as nt, AdminProvider as o, describeContrast as ot, useThemeChoice as p, addressPatternFor as pt, READY_MESSAGE as q, PreviewFrame as r, defaultStrings as rt, useAdmin as s, findPage as st, SCHEDULE_PROP as t, useDebounced as tt, setThemeChoice as u, mediaUrl as ut, REGISTRY_VERSION as v, collectionSettingsChanges as vt, SETTINGS_SECTIONS as w, mediaFileChange as wt, MediaField as x, duplicatePageData as xt, MediaChoiceContext as y, customCssFileChange as yt, showMediaInPreview as z, updateSettingsFileChange as zt };
|