@emdash-cms/admin 0.7.0 → 1.0.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.
Files changed (83) hide show
  1. package/dist/{LocaleDirectionProvider-CI7U6BBr.js → LocaleDirectionProvider-B43-InGI.js} +20 -14
  2. package/dist/LocaleDirectionProvider-B43-InGI.js.map +1 -0
  3. package/dist/{config-D8i8U4bV.d.ts → config-h7tWQRka.d.ts} +1 -1
  4. package/dist/{config-D8i8U4bV.d.ts.map → config-h7tWQRka.d.ts.map} +1 -1
  5. package/dist/index.d.ts +82 -8
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +843 -380
  8. package/dist/index.js.map +1 -1
  9. package/dist/locales/ar/messages.mjs +1 -1
  10. package/dist/locales/de/messages.mjs +1 -1
  11. package/dist/locales/en/messages.mjs +1 -1
  12. package/dist/locales/es-419/messages.mjs +1 -1
  13. package/dist/locales/eu/messages.mjs +1 -1
  14. package/dist/locales/fa/messages.mjs +1 -1
  15. package/dist/locales/fr/messages.mjs +1 -1
  16. package/dist/locales/index.d.ts +1 -1
  17. package/dist/locales/index.js +1 -1
  18. package/dist/locales/ja/messages.mjs +1 -1
  19. package/dist/locales/ko/messages.mjs +1 -1
  20. package/dist/locales/pl/messages.mjs +1 -0
  21. package/dist/locales/pseudo/messages.mjs +1 -1
  22. package/dist/locales/pt-BR/messages.mjs +1 -1
  23. package/dist/locales/zh-CN/messages.mjs +1 -1
  24. package/dist/locales/zh-TW/messages.mjs +1 -1
  25. package/dist/messages-B6ZguVfS.js +6 -0
  26. package/dist/messages-B6ZguVfS.js.map +1 -0
  27. package/dist/messages-BOnMi1Vb.js +6 -0
  28. package/dist/messages-BOnMi1Vb.js.map +1 -0
  29. package/dist/messages-BZuRVH-D.js +6 -0
  30. package/dist/messages-BZuRVH-D.js.map +1 -0
  31. package/dist/messages-Bc_PDiKw.js +6 -0
  32. package/dist/messages-Bc_PDiKw.js.map +1 -0
  33. package/dist/messages-Bddg68eH.js +6 -0
  34. package/dist/messages-Bddg68eH.js.map +1 -0
  35. package/dist/messages-BoP-RHEG.js +6 -0
  36. package/dist/messages-BoP-RHEG.js.map +1 -0
  37. package/dist/messages-C4hNtyU5.js +6 -0
  38. package/dist/messages-C4hNtyU5.js.map +1 -0
  39. package/dist/messages-CMwt5Gv-.js +6 -0
  40. package/dist/messages-CMwt5Gv-.js.map +1 -0
  41. package/dist/messages-CnliZpid.js +6 -0
  42. package/dist/messages-CnliZpid.js.map +1 -0
  43. package/dist/messages-CseAZVO2.js +6 -0
  44. package/dist/messages-CseAZVO2.js.map +1 -0
  45. package/dist/messages-DRyNt1qC.js +6 -0
  46. package/dist/messages-DRyNt1qC.js.map +1 -0
  47. package/dist/messages-DTehFUkD.js +6 -0
  48. package/dist/messages-DTehFUkD.js.map +1 -0
  49. package/dist/messages-DeQMOYvT.js +6 -0
  50. package/dist/messages-DeQMOYvT.js.map +1 -0
  51. package/dist/messages-Do3BokvI.js +6 -0
  52. package/dist/messages-Do3BokvI.js.map +1 -0
  53. package/dist/{plugins-XhZqfegd.js → plugins-DUJY_8HN.js} +9 -2
  54. package/dist/{plugins-XhZqfegd.js.map → plugins-DUJY_8HN.js.map} +1 -1
  55. package/dist/styles.css +1 -1
  56. package/package.json +2 -2
  57. package/dist/LocaleDirectionProvider-CI7U6BBr.js.map +0 -1
  58. package/dist/messages-57qx1FXa.js +0 -6
  59. package/dist/messages-57qx1FXa.js.map +0 -1
  60. package/dist/messages-8uPA5VDB.js +0 -6
  61. package/dist/messages-8uPA5VDB.js.map +0 -1
  62. package/dist/messages-Bc3iE3Xx.js +0 -6
  63. package/dist/messages-Bc3iE3Xx.js.map +0 -1
  64. package/dist/messages-BudiTpRZ.js +0 -6
  65. package/dist/messages-BudiTpRZ.js.map +0 -1
  66. package/dist/messages-CLJeZfc0.js +0 -6
  67. package/dist/messages-CLJeZfc0.js.map +0 -1
  68. package/dist/messages-CXyBDum7.js +0 -6
  69. package/dist/messages-CXyBDum7.js.map +0 -1
  70. package/dist/messages-DFXk1gAB.js +0 -6
  71. package/dist/messages-DFXk1gAB.js.map +0 -1
  72. package/dist/messages-DHg9t0ML.js +0 -6
  73. package/dist/messages-DHg9t0ML.js.map +0 -1
  74. package/dist/messages-DT-_3Gqh.js +0 -6
  75. package/dist/messages-DT-_3Gqh.js.map +0 -1
  76. package/dist/messages-DYWnQ-qc.js +0 -6
  77. package/dist/messages-DYWnQ-qc.js.map +0 -1
  78. package/dist/messages-DrHBJ5Tm.js +0 -6
  79. package/dist/messages-DrHBJ5Tm.js.map +0 -1
  80. package/dist/messages-TukFV9EF.js +0 -6
  81. package/dist/messages-TukFV9EF.js.map +0 -1
  82. package/dist/messages-cadUq4Pc.js +0 -6
  83. package/dist/messages-cadUq4Pc.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { c as fetchManifest, i as fetchPlugins, l as parseApiResponse, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as throwResponseError } from "./plugins-XhZqfegd.js";
2
- import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-CI7U6BBr.js";
1
+ import { c as fetchAuthMode, d as throwResponseError, i as fetchPlugins, l as fetchManifest, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as parseApiResponse } from "./plugins-DUJY_8HN.js";
2
+ import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-B43-InGI.js";
3
3
  import "./locales/index.js";
4
4
  import { Badge, Button, Checkbox, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
5
5
  import { i18n } from "@lingui/core";
@@ -10,7 +10,7 @@ import * as React from "react";
10
10
  import { createContext, useCallback, useContext, useEffect, useState } from "react";
11
11
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
12
  import { Dialog as Dialog$1 } from "@cloudflare/kumo/primitives";
13
- import { ArrowCounterClockwise, ArrowLeft, ArrowRight, ArrowSquareOut, ArrowUUpLeft, ArrowUUpRight, ArrowsClockwise, ArrowsInSimple, ArrowsLeftRight, ArrowsOutSimple, BracketsCurly, Calendar, CalendarBlank, CaretDown, CaretLeft, CaretRight, CaretUp, ChatCircle, Check, CheckCircle, CircleDashed, CircleNotch, ClockCounterClockwise, Cloud, Code, CodeBlock, Copy, Cube, Database, DeviceMobile, DotsSixVertical, DownloadSimple, Envelope, EnvelopeSimple, Eye, EyeSlash, File, FileArrowDown, FileText, FloppyDisk, FolderOpen, Gear, GithubLogo, Globe, GlobeSimple, GridFour, HardDrive, Hash, Image as Image$1, ImageSquare, Info, Key, Link as Link$2, LinkBreak, LinkSimple, List, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Minus, Monitor, Moon, Palette, PaperPlaneTilt, Paragraph, Pencil, PencilSimple, PlugsConnected, Plus, Prohibit, PuzzlePiece, Quotes, Rows, Ruler, ShareNetwork, Shield, ShieldCheck, ShieldWarning, SignOut, SlidersHorizontal, Sparkle, SquaresFour, Stack, Storefront, Sun, TextAlignCenter, TextAlignLeft, TextAlignRight, TextB, TextHOne, TextHThree, TextHTwo, TextItalic, TextStrikethrough, TextT, TextUnderline, ToggleLeft, Trash, Upload, User, UserCircle, UserPlus, Users, Warning, WarningCircle, WebhooksLogo, X, YoutubeLogo } from "@phosphor-icons/react";
13
+ import { ArrowCounterClockwise, ArrowLeft, ArrowRight, ArrowSquareOut, ArrowUUpLeft, ArrowUUpRight, ArrowsClockwise, ArrowsInSimple, ArrowsLeftRight, ArrowsOutSimple, BracketsCurly, Calendar, CalendarBlank, CaretDown, CaretLeft, CaretRight, CaretUp, CaretUpDown, ChatCircle, Check, CheckCircle, CircleDashed, CircleNotch, ClockCounterClockwise, Cloud, Code, CodeBlock, Copy, Cube, Database, DeviceMobile, DotsSixVertical, DownloadSimple, Envelope, EnvelopeSimple, Eye, EyeSlash, File, FileArrowDown, FileText, FloppyDisk, FolderOpen, Gear, GithubLogo, Globe, GlobeSimple, GridFour, HardDrive, Hash, Image as Image$1, ImageSquare, Info, Key, Link as Link$2, LinkBreak, LinkSimple, List, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Minus, Monitor, Moon, Palette, PaperPlaneTilt, Paragraph, Pencil, PencilSimple, PlugsConnected, Plus, Prohibit, PuzzlePiece, Quotes, Rows, Ruler, ShareNetwork, Shield, ShieldCheck, ShieldWarning, SignOut, SlidersHorizontal, Sparkle, SquaresFour, Stack, Storefront, Sun, TextAlignCenter, TextAlignLeft, TextAlignRight, TextB, TextHOne, TextHThree, TextHTwo, TextItalic, TextStrikethrough, TextT, TextUnderline, ToggleLeft, Trash, Upload, User, UserCircle, UserPlus, Users, Warning, WarningCircle, WebhooksLogo, X, YoutubeLogo } from "@phosphor-icons/react";
14
14
  import { clsx } from "clsx";
15
15
  import { twMerge } from "tailwind-merge";
16
16
  import { DndContext, DragOverlay, KeyboardSensor, PointerSensor, closestCenter, rectIntersection, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
@@ -100,6 +100,34 @@ function useTheme() {
100
100
  return context;
101
101
  }
102
102
 
103
+ //#endregion
104
+ //#region src/lib/auth-provider-context.tsx
105
+ const AuthProviderContext = createContext({});
106
+ /**
107
+ * Provider that makes auth provider components available to all descendants
108
+ */
109
+ function AuthProviderProvider({ children, authProviders }) {
110
+ return /* @__PURE__ */ jsx(AuthProviderContext.Provider, {
111
+ value: authProviders,
112
+ children
113
+ });
114
+ }
115
+ /**
116
+ * Get all auth provider modules
117
+ */
118
+ function useAuthProviders() {
119
+ return useContext(AuthProviderContext);
120
+ }
121
+ /**
122
+ * Get auth providers as an ordered array (buttons first, then forms)
123
+ */
124
+ function useAuthProviderList() {
125
+ const providers = useContext(AuthProviderContext);
126
+ return Object.values(providers).toSorted((a, b) => {
127
+ return (a.LoginForm ? 1 : 0) - (b.LoginForm ? 1 : 0);
128
+ });
129
+ }
130
+
103
131
  //#endregion
104
132
  //#region src/lib/plugin-context.tsx
105
133
  const PluginAdminContext = createContext({});
@@ -1105,6 +1133,8 @@ async function fetchContentList(collection, options) {
1105
1133
  if (options?.limit) params.set("limit", String(options.limit));
1106
1134
  if (options?.status) params.set("status", options.status);
1107
1135
  if (options?.locale) params.set("locale", options.locale);
1136
+ if (options?.orderBy) params.set("orderBy", options.orderBy);
1137
+ if (options?.order) params.set("order", options.order);
1108
1138
  return parseApiResponse(await apiFetch(`${API_BASE}/content/${collection}${params.toString() ? `?${params}` : ""}`), "Failed to fetch content");
1109
1139
  }
1110
1140
  /**
@@ -2261,6 +2291,10 @@ const API_TOKEN_SCOPES = {
2261
2291
  MediaWrite: "media:write",
2262
2292
  SchemaRead: "schema:read",
2263
2293
  SchemaWrite: "schema:write",
2294
+ TaxonomiesManage: "taxonomies:manage",
2295
+ MenusManage: "menus:manage",
2296
+ SettingsRead: "settings:read",
2297
+ SettingsManage: "settings:manage",
2264
2298
  Admin: "admin"
2265
2299
  };
2266
2300
  /**
@@ -2921,7 +2955,7 @@ var PluginFieldErrorBoundary = class extends React.Component {
2921
2955
  * Each item is a collapsible card containing the defined sub-fields.
2922
2956
  * Items can be added, removed, and reordered via drag-and-drop.
2923
2957
  */
2924
- function ensureKeys(items) {
2958
+ function ensureKeys$1(items) {
2925
2959
  return items.map((item, i) => {
2926
2960
  const obj = typeof item === "object" && item !== null ? item : {};
2927
2961
  return {
@@ -2930,13 +2964,13 @@ function ensureKeys(items) {
2930
2964
  };
2931
2965
  });
2932
2966
  }
2933
- function stripKeys(items) {
2967
+ function stripKeys$1(items) {
2934
2968
  return items.map(({ _key, ...rest }) => rest);
2935
2969
  }
2936
2970
  function RepeaterField({ label, id, value, onChange, subFields, minItems = 0, maxItems }) {
2937
2971
  const { _: _t } = useLingui();
2938
2972
  const rawItems = Array.isArray(value) ? value : [];
2939
- const [items, setItems] = React.useState(() => ensureKeys(rawItems));
2973
+ const [items, setItems] = React.useState(() => ensureKeys$1(rawItems));
2940
2974
  const [collapsedItems, setCollapsedItems] = React.useState(/* @__PURE__ */ new Set());
2941
2975
  React.useEffect(() => {
2942
2976
  const incoming = Array.isArray(value) ? value : [];
@@ -2951,7 +2985,7 @@ function RepeaterField({ label, id, value, onChange, subFields, minItems = 0, ma
2951
2985
  }, [value]);
2952
2986
  const emitChange = (updated) => {
2953
2987
  setItems(updated);
2954
- onChange(stripKeys(updated));
2988
+ onChange(stripKeys$1(updated));
2955
2989
  };
2956
2990
  const handleAdd = () => {
2957
2991
  if (maxItems && items.length >= maxItems) return;
@@ -3117,14 +3151,16 @@ function SubFieldInput({ subField, value, onChange }) {
3117
3151
  label: subField.label,
3118
3152
  value: typeof value === "string" ? value : "",
3119
3153
  onChange: (e) => onChange(e.target.value),
3120
- required: subField.required
3154
+ required: subField.required,
3155
+ dir: "auto"
3121
3156
  });
3122
3157
  case "text": return /* @__PURE__ */ jsx(InputArea, {
3123
3158
  label: subField.label,
3124
3159
  value: typeof value === "string" ? value : "",
3125
3160
  onChange: (e) => onChange(e.target.value),
3126
3161
  required: subField.required,
3127
- rows: 3
3162
+ rows: 3,
3163
+ dir: "auto"
3128
3164
  });
3129
3165
  case "number":
3130
3166
  case "integer": return /* @__PURE__ */ jsx(Input, {
@@ -6638,6 +6674,24 @@ function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedInde
6638
6674
  }, item.id))
6639
6675
  }), document.body);
6640
6676
  }
6677
+ function getPluginBlockDefaultValues(fields) {
6678
+ const defaults = {};
6679
+ for (const field of fields ?? []) {
6680
+ const initialValue = "initial_value" in field ? field.initial_value : void 0;
6681
+ if (initialValue !== void 0) defaults[field.action_id] = initialValue;
6682
+ }
6683
+ return defaults;
6684
+ }
6685
+ function buildPluginBlockFormValues(block, initialValues) {
6686
+ const defaults = getPluginBlockDefaultValues(block?.fields);
6687
+ return initialValues ? {
6688
+ ...defaults,
6689
+ ...initialValues
6690
+ } : defaults;
6691
+ }
6692
+ function hasPluginBlockFormData(values) {
6693
+ return Object.values(values).some((value) => value !== void 0 && value !== null && value !== "");
6694
+ }
6641
6695
  /**
6642
6696
  * Plugin block insertion/editing modal.
6643
6697
  * When the block has `fields`, renders Block Kit elements.
@@ -6648,8 +6702,7 @@ function PluginBlockModal({ block, initialValues, onClose, onInsert }) {
6648
6702
  const inputRef = React.useRef(null);
6649
6703
  React.useEffect(() => {
6650
6704
  if (block) {
6651
- if (initialValues) setFormValues({ ...initialValues });
6652
- else setFormValues({});
6705
+ setFormValues(buildPluginBlockFormValues(block, initialValues));
6653
6706
  if (!block.fields || block.fields.length === 0) setTimeout(() => inputRef.current?.focus(), 0);
6654
6707
  }
6655
6708
  }, [block, initialValues]);
@@ -6669,7 +6722,7 @@ function PluginBlockModal({ block, initialValues, onClose, onInsert }) {
6669
6722
  };
6670
6723
  const isEditing = !!initialValues;
6671
6724
  const hasFields = block?.fields && block.fields.length > 0;
6672
- const canSubmit = hasFields ? Object.values(formValues).some((v) => v !== void 0 && v !== null && v !== "") : typeof formValues.id === "string" && formValues.id.trim().length > 0;
6725
+ const canSubmit = hasFields ? hasPluginBlockFormData(formValues) : typeof formValues.id === "string" && formValues.id.trim().length > 0;
6673
6726
  return /* @__PURE__ */ jsx(Dialog.Root, {
6674
6727
  open: !!block,
6675
6728
  onOpenChange: (open) => !open && onClose(),
@@ -6702,7 +6755,7 @@ function PluginBlockModal({ block, initialValues, onClose, onInsert }) {
6702
6755
  }), /* @__PURE__ */ jsxs("form", {
6703
6756
  onSubmit: handleSubmit,
6704
6757
  children: [/* @__PURE__ */ jsx("div", {
6705
- className: "py-4 space-y-4",
6758
+ className: "py-4 space-y-4 max-h-[70vh] overflow-y-auto -mx-1 px-1",
6706
6759
  children: hasFields ? block.fields.map((field) => /* @__PURE__ */ jsx(BlockKitField, {
6707
6760
  field,
6708
6761
  pluginId: block.pluginId,
@@ -6789,12 +6842,244 @@ function BlockKitField({ field, pluginId, value, onChange }) {
6789
6842
  children: field.label
6790
6843
  })]
6791
6844
  });
6845
+ case "repeater": return /* @__PURE__ */ jsx(BlockKitRepeater, {
6846
+ field,
6847
+ pluginId,
6848
+ value,
6849
+ onChange
6850
+ });
6792
6851
  default: return /* @__PURE__ */ jsxs("div", {
6793
6852
  className: "text-sm text-kumo-subtle",
6794
6853
  children: ["Unknown field type: ", field.type]
6795
6854
  });
6796
6855
  }
6797
6856
  }
6857
+ function ensureKeys(items) {
6858
+ return items.map((item, i) => {
6859
+ const obj = typeof item === "object" && item !== null ? item : {};
6860
+ return {
6861
+ ...obj,
6862
+ _key: obj._key || `item-${i}-${Date.now()}`
6863
+ };
6864
+ });
6865
+ }
6866
+ function stripKeys(items) {
6867
+ return items.map(({ _key, ...rest }) => rest);
6868
+ }
6869
+ function BlockKitRepeater({ field, pluginId, value, onChange }) {
6870
+ const { _: _t2 } = useLingui();
6871
+ const rawItems = React.useMemo(() => Array.isArray(value) ? value : [], [value]);
6872
+ const [items, setItems] = React.useState(() => ensureKeys(rawItems));
6873
+ const [expanded, setExpanded] = React.useState(/* @__PURE__ */ new Set());
6874
+ const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
6875
+ const lastEmittedRef = React.useRef(null);
6876
+ React.useEffect(() => {
6877
+ if (lastEmittedRef.current === rawItems) return;
6878
+ setItems((prev) => rawItems.map((item, i) => {
6879
+ const obj = typeof item === "object" && item !== null ? item : {};
6880
+ const existingKey = obj._key || prev[i]?._key;
6881
+ return {
6882
+ ...obj,
6883
+ _key: existingKey || `item-${i}-${Date.now()}`
6884
+ };
6885
+ }));
6886
+ }, [rawItems]);
6887
+ const minItems = field.min_items ?? 0;
6888
+ const maxItems = field.max_items;
6889
+ const canAdd = maxItems === void 0 || items.length < maxItems;
6890
+ const canRemove = items.length > minItems;
6891
+ const addButtonLabel = field.item_label ? _t2({
6892
+ id: "3nLdaX",
6893
+ message: "Add {0}",
6894
+ values: { 0: field.item_label }
6895
+ }) : _t2({
6896
+ id: "NQ8llq",
6897
+ message: "Add item"
6898
+ });
6899
+ const emit = (next) => {
6900
+ setItems(next);
6901
+ const stripped = stripKeys(next);
6902
+ lastEmittedRef.current = stripped;
6903
+ onChange(field.action_id, stripped);
6904
+ };
6905
+ const handleAdd = () => {
6906
+ if (!canAdd) return;
6907
+ const newItem = { _key: `item-${Date.now()}-${Math.random().toString(36).slice(2, 7)}` };
6908
+ for (const sf of field.fields) switch (sf.type) {
6909
+ case "toggle":
6910
+ newItem[sf.action_id] = false;
6911
+ break;
6912
+ case "number_input":
6913
+ newItem[sf.action_id] = void 0;
6914
+ break;
6915
+ default: newItem[sf.action_id] = "";
6916
+ }
6917
+ setExpanded((prev) => {
6918
+ const next = new Set(prev);
6919
+ next.add(newItem._key);
6920
+ return next;
6921
+ });
6922
+ emit([...items, newItem]);
6923
+ };
6924
+ const handleRemove = (key) => {
6925
+ if (!canRemove) return;
6926
+ setExpanded((prev) => {
6927
+ if (!prev.has(key)) return prev;
6928
+ const next = new Set(prev);
6929
+ next.delete(key);
6930
+ return next;
6931
+ });
6932
+ emit(items.filter((it) => it._key !== key));
6933
+ };
6934
+ const handleItemChange = (key, subActionId, subValue) => {
6935
+ emit(items.map((it) => it._key === key ? {
6936
+ ...it,
6937
+ [subActionId]: subValue
6938
+ } : it));
6939
+ };
6940
+ const handleDragEnd = (event) => {
6941
+ const { active, over } = event;
6942
+ if (!over || active.id === over.id) return;
6943
+ const oldIndex = items.findIndex((it) => it._key === active.id);
6944
+ const newIndex = items.findIndex((it) => it._key === over.id);
6945
+ if (oldIndex === -1 || newIndex === -1) return;
6946
+ emit(arrayMove(items, oldIndex, newIndex));
6947
+ };
6948
+ const toggleExpanded = (key) => {
6949
+ setExpanded((prev) => {
6950
+ const next = new Set(prev);
6951
+ if (next.has(key)) next.delete(key);
6952
+ else next.add(key);
6953
+ return next;
6954
+ });
6955
+ };
6956
+ return /* @__PURE__ */ jsxs("div", {
6957
+ className: "space-y-2",
6958
+ children: [/* @__PURE__ */ jsxs("div", {
6959
+ className: "flex items-center justify-between",
6960
+ children: [/* @__PURE__ */ jsxs("label", {
6961
+ className: "text-sm font-medium",
6962
+ children: [field.label, items.length > 0 && /* @__PURE__ */ jsxs("span", {
6963
+ className: "ms-2 text-kumo-subtle font-normal",
6964
+ children: [
6965
+ "(",
6966
+ items.length,
6967
+ ")"
6968
+ ]
6969
+ })]
6970
+ }), canAdd && /* @__PURE__ */ jsx(Button, {
6971
+ variant: "outline",
6972
+ size: "sm",
6973
+ icon: /* @__PURE__ */ jsx(Plus, {}),
6974
+ onClick: handleAdd,
6975
+ type: "button",
6976
+ children: addButtonLabel
6977
+ })]
6978
+ }), items.length === 0 ? /* @__PURE__ */ jsxs("div", {
6979
+ className: "border-2 border-dashed rounded-lg p-6 text-center text-kumo-subtle",
6980
+ children: [/* @__PURE__ */ jsx("p", {
6981
+ className: "text-sm",
6982
+ children: _t2({
6983
+ id: "bWmJ0A",
6984
+ message: "No items yet"
6985
+ })
6986
+ }), canAdd && /* @__PURE__ */ jsx(Button, {
6987
+ variant: "outline",
6988
+ size: "sm",
6989
+ className: "mt-2",
6990
+ icon: /* @__PURE__ */ jsx(Plus, {}),
6991
+ onClick: handleAdd,
6992
+ type: "button",
6993
+ children: addButtonLabel
6994
+ })]
6995
+ }) : /* @__PURE__ */ jsx(DndContext, {
6996
+ sensors,
6997
+ collisionDetection: closestCenter,
6998
+ onDragEnd: handleDragEnd,
6999
+ children: /* @__PURE__ */ jsx(SortableContext, {
7000
+ items: items.map((it) => it._key),
7001
+ strategy: verticalListSortingStrategy,
7002
+ children: /* @__PURE__ */ jsx("div", {
7003
+ className: "space-y-2",
7004
+ children: items.map((item, index) => /* @__PURE__ */ jsx(BlockKitRepeaterItem, {
7005
+ item,
7006
+ index,
7007
+ fields: field.fields,
7008
+ pluginId,
7009
+ isCollapsed: !expanded.has(item._key),
7010
+ onToggleCollapse: () => toggleExpanded(item._key),
7011
+ onRemove: canRemove ? () => handleRemove(item._key) : void 0,
7012
+ onChange: (subActionId, v) => handleItemChange(item._key, subActionId, v)
7013
+ }, item._key))
7014
+ })
7015
+ })
7016
+ })]
7017
+ });
7018
+ }
7019
+ function BlockKitRepeaterItem({ item, index, fields, pluginId, isCollapsed, onToggleCollapse, onRemove, onChange }) {
7020
+ const { _: _t3 } = useLingui();
7021
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: item._key });
7022
+ const style = {
7023
+ transform: CSS.Transform.toString(transform),
7024
+ transition
7025
+ };
7026
+ const summaryField = fields.find((f) => f.type === "text_input");
7027
+ const summaryLabel = (summaryField && typeof item[summaryField.action_id] === "string" ? item[summaryField.action_id] : "").trim() || _t3({
7028
+ id: "y/5CE8",
7029
+ message: "Item {0}",
7030
+ values: { 0: index + 1 }
7031
+ });
7032
+ return /* @__PURE__ */ jsxs("div", {
7033
+ ref: setNodeRef,
7034
+ style,
7035
+ className: cn("border border-kumo-line rounded-lg bg-kumo-base", isDragging && "opacity-50 ring-2 ring-kumo-brand"),
7036
+ children: [/* @__PURE__ */ jsxs("div", {
7037
+ className: "flex items-center gap-2 px-3 py-2 border-b border-kumo-line",
7038
+ children: [
7039
+ /* @__PURE__ */ jsx("span", {
7040
+ className: "inline-flex h-4 w-4 text-kumo-subtle cursor-grab shrink-0",
7041
+ "aria-label": _t3({
7042
+ id: "KGi3u9",
7043
+ message: "Drag to reorder"
7044
+ }),
7045
+ ...attributes,
7046
+ ...listeners,
7047
+ children: /* @__PURE__ */ jsx(DotsSixVertical, { className: "h-4 w-4" })
7048
+ }),
7049
+ /* @__PURE__ */ jsxs("button", {
7050
+ type: "button",
7051
+ className: "flex items-center gap-2 flex-1 min-w-0 text-left cursor-pointer",
7052
+ onClick: onToggleCollapse,
7053
+ "aria-expanded": !isCollapsed,
7054
+ children: [isCollapsed ? /* @__PURE__ */ jsx(CaretRight, { className: "h-4 w-4 text-kumo-subtle shrink-0" }) : /* @__PURE__ */ jsx(CaretDown, { className: "h-4 w-4 text-kumo-subtle shrink-0" }), /* @__PURE__ */ jsx("span", {
7055
+ className: "text-sm font-medium flex-1 truncate",
7056
+ children: summaryLabel
7057
+ })]
7058
+ }),
7059
+ onRemove && /* @__PURE__ */ jsx(Button, {
7060
+ variant: "ghost",
7061
+ shape: "square",
7062
+ type: "button",
7063
+ onClick: onRemove,
7064
+ "aria-label": _t3({
7065
+ id: "mU3j1b",
7066
+ message: "Remove item {0}",
7067
+ values: { 0: index + 1 }
7068
+ }),
7069
+ children: /* @__PURE__ */ jsx(Trash, { className: "h-3.5 w-3.5 text-kumo-danger" })
7070
+ })
7071
+ ]
7072
+ }), !isCollapsed && /* @__PURE__ */ jsx("div", {
7073
+ className: "p-3 space-y-3",
7074
+ children: fields.map((sf) => /* @__PURE__ */ jsx(BlockKitField, {
7075
+ field: sf,
7076
+ pluginId,
7077
+ value: item[sf.action_id],
7078
+ onChange: (actionId, v) => onChange(actionId, v)
7079
+ }, sf.action_id))
7080
+ })]
7081
+ });
7082
+ }
6798
7083
  /**
6799
7084
  * Select field that supports loading options dynamically via `optionsRoute`.
6800
7085
  * When `optionsRoute` is set, fetches `{ items: [{ id, name }] }` from the plugin route.
@@ -6893,7 +7178,7 @@ function EditorFooter({ editor }) {
6893
7178
  * Portable Text Editor Component
6894
7179
  */
6895
7180
  function PortableTextEditor({ value, onChange, placeholder = "Start writing...", className, editable = true, "aria-labelledby": ariaLabelledby, pluginBlocks = [], focusMode: controlledFocusMode, onFocusModeChange, onEditorReady, minimal = false, onBlockSidebarOpen, onBlockSidebarClose }) {
6896
- const { _: _t2 } = useLingui();
7181
+ const { _: _t4 } = useLingui();
6897
7182
  const onChangeRef = React.useRef(onChange);
6898
7183
  React.useEffect(() => {
6899
7184
  onChangeRef.current = onChange;
@@ -6977,7 +7262,7 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
6977
7262
  for (const block of pluginBlocks) cmds.push({
6978
7263
  id: `plugin-${block.pluginId}-${block.type}`,
6979
7264
  title: block.label,
6980
- description: block.description ?? _t2({
7265
+ description: block.description ?? _t4({
6981
7266
  id: "g0zqOw",
6982
7267
  message: "Embed a {0}",
6983
7268
  values: { 0: block.label }
@@ -6994,7 +7279,7 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
6994
7279
  }
6995
7280
  });
6996
7281
  return cmds;
6997
- }, [pluginBlocks, _t2]);
7282
+ }, [pluginBlocks, _t4]);
6998
7283
  const filterCommandsRef = React.useRef((_q) => []);
6999
7284
  filterCommandsRef.current = (query) => {
7000
7285
  if (!query) return slashCommands;
@@ -7002,8 +7287,8 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
7002
7287
  const titleMatches = [];
7003
7288
  const otherMatches = [];
7004
7289
  for (const item of slashCommands) {
7005
- const titleStr = typeof item.title === "string" ? item.title : _t2(item.title);
7006
- const descStr = typeof item.description === "string" ? item.description : _t2(item.description);
7290
+ const titleStr = typeof item.title === "string" ? item.title : _t4(item.title);
7291
+ const descStr = typeof item.description === "string" ? item.description : _t4(item.description);
7007
7292
  if (titleStr.toLowerCase().includes(searchText)) titleMatches.push(item);
7008
7293
  else if (descStr.toLowerCase().includes(searchText) || item.aliases?.some((alias) => alias.toLowerCase().includes(searchText))) otherMatches.push(item);
7009
7294
  }
@@ -7055,7 +7340,10 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
7055
7340
  content: initialContent,
7056
7341
  editable,
7057
7342
  immediatelyRender: true,
7058
- editorProps: React.useMemo(() => ({ attributes: { class: "prose prose-sm sm:prose-base dark:prose-invert max-w-none focus:outline-none min-h-[200px] p-4" } }), []),
7343
+ editorProps: React.useMemo(() => ({ attributes: {
7344
+ class: "prose prose-sm sm:prose-base dark:prose-invert max-w-none focus:outline-none min-h-[200px] p-4",
7345
+ dir: "auto"
7346
+ } }), []),
7059
7347
  onUpdate: ({ editor: updatedEditor }) => {
7060
7348
  const cb = onChangeRef.current;
7061
7349
  if (cb) cb(prosemirrorToPortableText(updatedEditor.getJSON()));
@@ -8406,7 +8694,8 @@ function SeoPanel({ contentKey, seo, onChange }) {
8406
8694
  value: draft.title,
8407
8695
  onChange: (e) => {
8408
8696
  updateDraft({ title: e.target.value });
8409
- }
8697
+ },
8698
+ dir: "auto"
8410
8699
  }),
8411
8700
  /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(InputArea, {
8412
8701
  label: _t({
@@ -8425,7 +8714,8 @@ function SeoPanel({ contentKey, seo, onChange }) {
8425
8714
  onChange: (e) => {
8426
8715
  updateDraft({ description: e.target.value });
8427
8716
  },
8428
- rows: 3
8717
+ rows: 3,
8718
+ dir: "auto"
8429
8719
  }) }),
8430
8720
  /* @__PURE__ */ jsx(Input, {
8431
8721
  label: _t({
@@ -8567,7 +8857,7 @@ function CategoryCheckboxTree({ term, level = 0, selectedIds, onToggle }) {
8567
8857
  const isChecked = selectedIds.has(term.id);
8568
8858
  return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("label", {
8569
8859
  className: "flex items-center py-1 cursor-pointer hover:bg-kumo-tint/50 rounded px-2",
8570
- style: { marginLeft: `${level}rem` },
8860
+ style: { marginInlineStart: `${level}rem` },
8571
8861
  children: [/* @__PURE__ */ jsx("input", {
8572
8862
  type: "checkbox",
8573
8863
  checked: isChecked,
@@ -8917,13 +9207,6 @@ function ContentEditor({ collection, collectionLabel, item, fields, isNew, isSav
8917
9207
  roleLabel: entry.roleLabel
8918
9208
  })) ?? []);
8919
9209
  const [portableTextEditor, setPortableTextEditor] = React.useState(null);
8920
- const ptEditorClaimedRef = React.useRef(false);
8921
- React.useCallback((editor) => {
8922
- if (!ptEditorClaimedRef.current) {
8923
- ptEditorClaimedRef.current = true;
8924
- setPortableTextEditor(editor);
8925
- }
8926
- }, []);
8927
9210
  const [blockSidebarPanel, setBlockSidebarPanel] = React.useState(null);
8928
9211
  const handleBlockSidebarOpen = React.useCallback((panel) => {
8929
9212
  setBlockSidebarPanel(panel);
@@ -9751,6 +10034,7 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
9751
10034
  value: typeof value === "string" ? value : "",
9752
10035
  onChange: (e) => handleChange(e.target.value),
9753
10036
  required: field.required,
10037
+ dir: "auto",
9754
10038
  className: minimal ? "border-0 bg-transparent px-0 text-lg font-medium focus-visible:ring-0 focus-visible:ring-offset-0" : void 0
9755
10039
  });
9756
10040
  case "number": return /* @__PURE__ */ jsx(Input, {
@@ -9801,6 +10085,7 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
9801
10085
  value: typeof value === "string" ? value : "",
9802
10086
  onChange: (e) => handleChange(e.target.value),
9803
10087
  rows: 10,
10088
+ dir: "auto",
9804
10089
  placeholder: _t2({
9805
10090
  id: "dPFFy+",
9806
10091
  message: "Enter markdown content..."
@@ -9897,7 +10182,8 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
9897
10182
  id,
9898
10183
  value: typeof value === "string" ? value : "",
9899
10184
  onChange: (e) => handleChange(e.target.value),
9900
- required: field.required
10185
+ required: field.required,
10186
+ dir: "auto"
9901
10187
  });
9902
10188
  }
9903
10189
  }
@@ -10537,7 +10823,7 @@ function getItemTitle$1(item) {
10537
10823
  /**
10538
10824
  * Content list view with table display and trash tab
10539
10825
  */
10540
- function ContentList({ collection, collectionLabel, items, trashedItems = [], isLoading, isTrashedLoading, onDelete, onDuplicate, onRestore, onPermanentDelete, onLoadMore, onLoadMoreTrashed, hasMore, hasMoreTrashed, trashedCount = 0, i18n: i18n$1, activeLocale, onLocaleChange, urlPattern }) {
10826
+ function ContentList({ collection, collectionLabel, items, trashedItems = [], isLoading, isTrashedLoading, onDelete, onDuplicate, onRestore, onPermanentDelete, onLoadMore, onLoadMoreTrashed, hasMore, hasMoreTrashed, trashedCount = 0, i18n: i18n$1, activeLocale, onLocaleChange, urlPattern, sort, onSortChange }) {
10541
10827
  const { _: _t } = useLingui();
10542
10828
  const [activeTab, setActiveTab] = React.useState("all");
10543
10829
  const [searchQuery, setSearchQuery] = React.useState("");
@@ -10653,34 +10939,38 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
10653
10939
  children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", {
10654
10940
  className: "border-b bg-kumo-tint/50",
10655
10941
  children: [
10656
- /* @__PURE__ */ jsx("th", {
10657
- scope: "col",
10658
- className: "px-4 py-3 text-start text-sm font-medium",
10659
- children: _t({
10942
+ /* @__PURE__ */ jsx(SortableTh, {
10943
+ field: "title",
10944
+ sort,
10945
+ onSortChange,
10946
+ label: _t({
10660
10947
  id: "MHrjPM",
10661
10948
  message: "Title"
10662
10949
  })
10663
10950
  }),
10664
- /* @__PURE__ */ jsx("th", {
10665
- scope: "col",
10666
- className: "px-4 py-3 text-start text-sm font-medium",
10667
- children: _t({
10951
+ /* @__PURE__ */ jsx(SortableTh, {
10952
+ field: "status",
10953
+ sort,
10954
+ onSortChange,
10955
+ label: _t({
10668
10956
  id: "uAQUqI",
10669
10957
  message: "Status"
10670
10958
  })
10671
10959
  }),
10672
- i18n$1 && /* @__PURE__ */ jsx("th", {
10673
- scope: "col",
10674
- className: "px-4 py-3 text-start text-sm font-medium",
10675
- children: _t({
10960
+ i18n$1 && /* @__PURE__ */ jsx(SortableTh, {
10961
+ field: "locale",
10962
+ sort,
10963
+ onSortChange,
10964
+ label: _t({
10676
10965
  id: "8NbHF7",
10677
10966
  message: "Locale"
10678
10967
  })
10679
10968
  }),
10680
- /* @__PURE__ */ jsx("th", {
10681
- scope: "col",
10682
- className: "px-4 py-3 text-start text-sm font-medium",
10683
- children: _t({
10969
+ /* @__PURE__ */ jsx(SortableTh, {
10970
+ field: "updatedAt",
10971
+ sort,
10972
+ onSortChange,
10973
+ label: _t({
10684
10974
  id: "mYGY3B",
10685
10975
  message: "Date"
10686
10976
  })
@@ -10873,6 +11163,52 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
10873
11163
  ]
10874
11164
  });
10875
11165
  }
11166
+ /**
11167
+ * Table header that doubles as a sort control when the parent opted in by
11168
+ * passing `onSortChange`. When no callback is provided we fall back to a
11169
+ * plain `<th>` so legacy callers (and screen readers) see exactly the same
11170
+ * markup as before this change.
11171
+ *
11172
+ * The button's accessible name is just the column label — the sort state
11173
+ * is conveyed via `aria-sort` on the <th>, which screen readers announce
11174
+ * automatically. Adding a verbose aria-label would make each header re-read
11175
+ * the sort instruction on every focus, which is noisy.
11176
+ */
11177
+ function SortableTh({ field, sort, onSortChange, label }) {
11178
+ const isActive = sort?.field === field;
11179
+ const direction = isActive ? sort?.direction : void 0;
11180
+ if (!onSortChange) return /* @__PURE__ */ jsx("th", {
11181
+ scope: "col",
11182
+ className: "px-4 py-3 text-start text-sm font-medium",
11183
+ children: label
11184
+ });
11185
+ const ariaSort = isActive ? direction === "asc" ? "ascending" : "descending" : "none";
11186
+ const handleClick = () => {
11187
+ if (isActive) onSortChange({
11188
+ field,
11189
+ direction: direction === "asc" ? "desc" : "asc"
11190
+ });
11191
+ else onSortChange({
11192
+ field,
11193
+ direction: "desc"
11194
+ });
11195
+ };
11196
+ const Icon = isActive ? direction === "asc" ? CaretUp : CaretDown : CaretUpDown;
11197
+ return /* @__PURE__ */ jsx("th", {
11198
+ scope: "col",
11199
+ "aria-sort": ariaSort,
11200
+ className: "px-4 py-3 text-start text-sm font-medium",
11201
+ children: /* @__PURE__ */ jsxs("button", {
11202
+ type: "button",
11203
+ onClick: handleClick,
11204
+ className: cn("inline-flex items-center gap-1 rounded hover:text-kumo-brand", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-kumo-brand", isActive ? "text-kumo-fg" : "text-kumo-subtle"),
11205
+ children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx(Icon, {
11206
+ className: "h-3 w-3",
11207
+ "aria-hidden": "true"
11208
+ })]
11209
+ })
11210
+ });
11211
+ }
10876
11212
  function ContentListItem({ item, collection, onDelete, onDuplicate, showLocale, urlPattern }) {
10877
11213
  const { _: _t2 } = useLingui();
10878
11214
  const title = getItemTitle$1(item);
@@ -12094,7 +12430,7 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
12094
12430
  const [labelSingular, setLabelSingular] = React.useState(collection?.labelSingular ?? "");
12095
12431
  const [description, setDescription] = React.useState(collection?.description ?? "");
12096
12432
  const [urlPattern, setUrlPattern] = React.useState(collection?.urlPattern ?? "");
12097
- const [supports, setSupports] = React.useState((collection?.supports ?? ["drafts"]).filter((s) => s !== "seo"));
12433
+ const [supports, setSupports] = React.useState((collection?.supports ?? ["drafts", "revisions"]).filter((s) => s !== "seo"));
12098
12434
  const [hasSeo, setHasSeo] = React.useState(collection?.hasSeo ?? false);
12099
12435
  const [commentsEnabled, setCommentsEnabled] = React.useState(collection?.commentsEnabled ?? false);
12100
12436
  const [commentsModeration, setCommentsModeration] = React.useState(collection?.commentsModeration ?? "first_time");
@@ -14742,54 +15078,13 @@ function PasskeyLogin({ optionsEndpoint, verifyEndpoint, onSuccess, onError, sho
14742
15078
  * It's a standalone page for authentication.
14743
15079
  *
14744
15080
  * Supports:
14745
- * - Passkey authentication (primary)
14746
- * - OAuth (GitHub, Google) when configured
15081
+ * - Passkey authentication (always available)
15082
+ * - Pluggable auth providers (AT Protocol, GitHub, Google, etc.) when configured
14747
15083
  * - Magic link (email) when configured
14748
15084
  *
14749
15085
  * When external auth (e.g., Cloudflare Access) is configured, this page
14750
15086
  * redirects to the admin dashboard since authentication is handled externally.
14751
15087
  */
14752
- function GitHubIcon({ className }) {
14753
- return /* @__PURE__ */ jsx("svg", {
14754
- className,
14755
- viewBox: "0 0 24 24",
14756
- fill: "currentColor",
14757
- children: /* @__PURE__ */ jsx("path", { d: "M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" })
14758
- });
14759
- }
14760
- function GoogleIcon({ className }) {
14761
- return /* @__PURE__ */ jsxs("svg", {
14762
- className,
14763
- viewBox: "0 0 24 24",
14764
- children: [
14765
- /* @__PURE__ */ jsx("path", {
14766
- fill: "#4285F4",
14767
- d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
14768
- }),
14769
- /* @__PURE__ */ jsx("path", {
14770
- fill: "#34A853",
14771
- d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
14772
- }),
14773
- /* @__PURE__ */ jsx("path", {
14774
- fill: "#FBBC05",
14775
- d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
14776
- }),
14777
- /* @__PURE__ */ jsx("path", {
14778
- fill: "#EA4335",
14779
- d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
14780
- })
14781
- ]
14782
- });
14783
- }
14784
- const OAUTH_PROVIDERS = [{
14785
- id: "github",
14786
- name: "GitHub",
14787
- icon: /* @__PURE__ */ jsx(GitHubIcon, { className: "h-5 w-5" })
14788
- }, {
14789
- id: "google",
14790
- name: "Google",
14791
- icon: /* @__PURE__ */ jsx(GoogleIcon, { className: "h-5 w-5" })
14792
- }];
14793
15088
  function MagicLinkForm({ onBack }) {
14794
15089
  const { _: _t } = useLingui();
14795
15090
  const [email, setEmail] = React.useState("");
@@ -14930,22 +15225,21 @@ function MagicLinkForm({ onBack }) {
14930
15225
  ]
14931
15226
  });
14932
15227
  }
14933
- function handleOAuthClick(providerId) {
14934
- window.location.href = `/_emdash/api/auth/oauth/${providerId}`;
14935
- }
14936
15228
  function LoginPage({ redirectUrl = "/_emdash/admin" }) {
14937
15229
  const safeRedirectUrl = sanitizeRedirectUrl(redirectUrl);
14938
15230
  const { _: _t2 } = useLingui();
14939
15231
  const { locale, setLocale } = useLocale();
14940
15232
  const [method, setMethod] = React.useState("passkey");
14941
15233
  const [urlError, setUrlError] = React.useState(null);
14942
- const { data: manifest, isLoading: manifestLoading } = useQuery({
14943
- queryKey: ["manifest"],
14944
- queryFn: fetchManifest
15234
+ const [activeProvider, setActiveProvider] = React.useState(null);
15235
+ const authProviderList = useAuthProviderList();
15236
+ const { data: authInfo, isLoading: authModeLoading } = useQuery({
15237
+ queryKey: ["authMode"],
15238
+ queryFn: fetchAuthMode
14945
15239
  });
14946
15240
  React.useEffect(() => {
14947
- if (manifest?.authMode && manifest.authMode !== "passkey") window.location.href = safeRedirectUrl;
14948
- }, [manifest, safeRedirectUrl]);
15241
+ if (authInfo?.authMode && authInfo.authMode !== "passkey") window.location.href = safeRedirectUrl;
15242
+ }, [authInfo, safeRedirectUrl]);
14949
15243
  React.useEffect(() => {
14950
15244
  const params = new URLSearchParams(window.location.search);
14951
15245
  const error = params.get("error");
@@ -14962,15 +15256,12 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
14962
15256
  const handleSuccess = () => {
14963
15257
  window.location.href = safeRedirectUrl;
14964
15258
  };
14965
- if (manifestLoading || manifest?.authMode && manifest.authMode !== "passkey") return /* @__PURE__ */ jsx("div", {
15259
+ const buttonProviders = authProviderList.filter((p) => p.LoginButton);
15260
+ if (authModeLoading || authInfo?.authMode && authInfo.authMode !== "passkey") return /* @__PURE__ */ jsx("div", {
14966
15261
  className: "min-h-screen flex items-center justify-center bg-kumo-base p-4",
14967
15262
  children: /* @__PURE__ */ jsxs("div", {
14968
15263
  className: "flex flex-col items-center",
14969
- children: [/* @__PURE__ */ jsx(BrandLogo, {
14970
- logoUrl: manifest?.admin?.logo,
14971
- siteName: manifest?.admin?.siteName,
14972
- className: "h-10 mb-4"
14973
- }), /* @__PURE__ */ jsx(Loader, {})]
15264
+ children: [/* @__PURE__ */ jsx(BrandLogo, { className: "h-10 mb-4" }), /* @__PURE__ */ jsx(Loader, {})]
14974
15265
  })
14975
15266
  });
14976
15267
  return /* @__PURE__ */ jsx("div", {
@@ -14980,19 +15271,19 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
14980
15271
  children: [
14981
15272
  /* @__PURE__ */ jsxs("div", {
14982
15273
  className: "text-center mb-8",
14983
- children: [/* @__PURE__ */ jsx(BrandLogo, {
14984
- logoUrl: manifest?.admin?.logo,
14985
- siteName: manifest?.admin?.siteName,
14986
- className: "h-10 mx-auto mb-2"
14987
- }), /* @__PURE__ */ jsxs("h1", {
15274
+ children: [/* @__PURE__ */ jsx(BrandLogo, { className: "h-10 mx-auto mb-2" }), /* @__PURE__ */ jsx("h1", {
14988
15275
  className: "text-2xl font-semibold text-kumo-default",
14989
- children: [method === "passkey" && _t2({
14990
- id: "lE0wHD",
14991
- message: "Sign in to your site"
14992
- }), method === "magic-link" && _t2({
15276
+ children: method === "magic-link" ? _t2({
14993
15277
  id: "me9L29",
14994
15278
  message: "Sign in with email"
14995
- })]
15279
+ }) : activeProvider ? _t2({
15280
+ id: "e/ToF5",
15281
+ message: "Sign in with {0}",
15282
+ values: { 0: authProviderList.find((p) => p.id === activeProvider)?.label ?? activeProvider }
15283
+ }) : _t2({
15284
+ id: "lE0wHD",
15285
+ message: "Sign in to your site"
15286
+ })
14996
15287
  })]
14997
15288
  }),
14998
15289
  urlError && /* @__PURE__ */ jsx("div", {
@@ -15001,71 +15292,94 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
15001
15292
  }),
15002
15293
  /* @__PURE__ */ jsxs("div", {
15003
15294
  className: "bg-kumo-base border rounded-lg shadow-sm p-6",
15004
- children: [method === "passkey" && /* @__PURE__ */ jsxs("div", {
15005
- className: "space-y-6",
15006
- children: [
15007
- /* @__PURE__ */ jsx(PasskeyLogin, {
15008
- optionsEndpoint: "/_emdash/api/auth/passkey/options",
15009
- verifyEndpoint: "/_emdash/api/auth/passkey/verify",
15010
- onSuccess: handleSuccess,
15011
- buttonText: _t2({
15012
- id: "QjsOMP",
15013
- message: "Sign in with Passkey"
15014
- })
15015
- }),
15016
- /* @__PURE__ */ jsxs("div", {
15017
- className: "relative",
15018
- children: [/* @__PURE__ */ jsx("div", {
15019
- className: "absolute inset-0 flex items-center",
15020
- children: /* @__PURE__ */ jsx("span", { className: "w-full border-t" })
15021
- }), /* @__PURE__ */ jsx("div", {
15022
- className: "relative flex justify-center text-xs uppercase",
15023
- children: /* @__PURE__ */ jsx("span", {
15024
- className: "bg-kumo-base px-2 text-kumo-subtle",
15025
- children: _t2({
15026
- id: "zW+FpA",
15027
- message: "Or continue with"
15295
+ children: [
15296
+ method === "passkey" && !activeProvider && /* @__PURE__ */ jsxs("div", {
15297
+ className: "space-y-6",
15298
+ children: [
15299
+ /* @__PURE__ */ jsx(PasskeyLogin, {
15300
+ optionsEndpoint: "/_emdash/api/auth/passkey/options",
15301
+ verifyEndpoint: "/_emdash/api/auth/passkey/verify",
15302
+ onSuccess: handleSuccess,
15303
+ buttonText: _t2({
15304
+ id: "QjsOMP",
15305
+ message: "Sign in with Passkey"
15306
+ })
15307
+ }),
15308
+ /* @__PURE__ */ jsxs("div", {
15309
+ className: "relative",
15310
+ children: [/* @__PURE__ */ jsx("div", {
15311
+ className: "absolute inset-0 flex items-center",
15312
+ children: /* @__PURE__ */ jsx("span", { className: "w-full border-t" })
15313
+ }), /* @__PURE__ */ jsx("div", {
15314
+ className: "relative flex justify-center text-xs uppercase",
15315
+ children: /* @__PURE__ */ jsx("span", {
15316
+ className: "bg-kumo-base px-2 text-kumo-subtle",
15317
+ children: _t2({
15318
+ id: "zW+FpA",
15319
+ message: "Or continue with"
15320
+ })
15028
15321
  })
15322
+ })]
15323
+ }),
15324
+ buttonProviders.length > 0 && /* @__PURE__ */ jsx("div", {
15325
+ className: `grid gap-3 ${buttonProviders.length === 1 ? "grid-cols-1" : "grid-cols-2"}`,
15326
+ children: buttonProviders.map((provider) => {
15327
+ const Btn = provider.LoginButton;
15328
+ const hasForm = !!provider.LoginForm;
15329
+ const selectProvider = () => setActiveProvider(provider.id);
15330
+ return /* @__PURE__ */ jsx("div", {
15331
+ onClick: hasForm ? selectProvider : void 0,
15332
+ children: /* @__PURE__ */ jsx(Btn, {})
15333
+ }, provider.id);
15029
15334
  })
15030
- })]
15031
- }),
15032
- /* @__PURE__ */ jsx("div", {
15033
- className: "grid grid-cols-2 gap-3",
15034
- children: OAUTH_PROVIDERS.map((provider) => /* @__PURE__ */ jsxs(Button, {
15035
- variant: "outline",
15036
- type: "button",
15037
- onClick: () => handleOAuthClick(provider.id),
15335
+ }),
15336
+ /* @__PURE__ */ jsx(Button, {
15337
+ variant: "ghost",
15038
15338
  className: "w-full justify-center",
15039
- children: [provider.icon, /* @__PURE__ */ jsx("span", {
15040
- className: "ms-2",
15041
- children: provider.name
15042
- })]
15043
- }, provider.id))
15044
- }),
15045
- /* @__PURE__ */ jsx(Button, {
15046
- variant: "ghost",
15047
- className: "w-full justify-center",
15048
- type: "button",
15049
- onClick: () => setMethod("magic-link"),
15050
- children: _t2({
15051
- id: "RxerEl",
15052
- message: "Sign in with email link"
15339
+ type: "button",
15340
+ onClick: () => setMethod("magic-link"),
15341
+ children: _t2({
15342
+ id: "RxerEl",
15343
+ message: "Sign in with email link"
15344
+ })
15053
15345
  })
15054
- })
15055
- ]
15056
- }), method === "magic-link" && /* @__PURE__ */ jsx(MagicLinkForm, { onBack: () => setMethod("passkey") })]
15346
+ ]
15347
+ }),
15348
+ method === "passkey" && activeProvider && (() => {
15349
+ const provider = authProviderList.find((p) => p.id === activeProvider);
15350
+ if (!provider?.LoginForm) return null;
15351
+ const Form = provider.LoginForm;
15352
+ return /* @__PURE__ */ jsxs("div", {
15353
+ className: "space-y-4",
15354
+ children: [/* @__PURE__ */ jsx(Form, {}), /* @__PURE__ */ jsx(Button, {
15355
+ type: "button",
15356
+ variant: "ghost",
15357
+ className: "w-full justify-center",
15358
+ onClick: () => setActiveProvider(null),
15359
+ children: _t2({
15360
+ id: "VCoEm+",
15361
+ message: "Back to login"
15362
+ })
15363
+ })]
15364
+ });
15365
+ })(),
15366
+ method === "magic-link" && /* @__PURE__ */ jsx(MagicLinkForm, { onBack: () => setMethod("passkey") })
15367
+ ]
15057
15368
  }),
15058
15369
  /* @__PURE__ */ jsx("p", {
15059
15370
  className: "text-center mt-6 text-sm text-kumo-subtle",
15060
- children: method === "passkey" ? _t2({
15061
- id: "+ET/av",
15062
- message: "Use your registered passkey to sign in securely."
15063
- }) : _t2({
15371
+ children: method === "magic-link" ? _t2({
15064
15372
  id: "pv+wH3",
15065
15373
  message: "We'll send you a link to sign in without a password."
15374
+ }) : activeProvider ? _t2({
15375
+ id: "TZGT4o",
15376
+ message: "Enter your handle to sign in."
15377
+ }) : _t2({
15378
+ id: "+ET/av",
15379
+ message: "Use your registered passkey to sign in securely."
15066
15380
  })
15067
15381
  }),
15068
- manifest?.signupEnabled && /* @__PURE__ */ jsx("p", {
15382
+ authInfo?.signupEnabled && /* @__PURE__ */ jsx("p", {
15069
15383
  className: "text-center mt-4 text-sm text-kumo-subtle",
15070
15384
  children: /* @__PURE__ */ jsx(Trans, {
15071
15385
  id: "352VU2",
@@ -21459,6 +21773,50 @@ const API_TOKEN_SCOPE_VALUES = [
21459
21773
  message: "Modify collection schemas"
21460
21774
  }
21461
21775
  },
21776
+ {
21777
+ scope: API_TOKEN_SCOPES.TaxonomiesManage,
21778
+ label: {
21779
+ id: "cfmuSI",
21780
+ message: "Taxonomies Manage"
21781
+ },
21782
+ description: {
21783
+ id: "mmBufY",
21784
+ message: "Create, update, and delete taxonomy terms"
21785
+ }
21786
+ },
21787
+ {
21788
+ scope: API_TOKEN_SCOPES.MenusManage,
21789
+ label: {
21790
+ id: "Wosws9",
21791
+ message: "Menus Manage"
21792
+ },
21793
+ description: {
21794
+ id: "DGhfmD",
21795
+ message: "Create, update, and delete navigation menus"
21796
+ }
21797
+ },
21798
+ {
21799
+ scope: API_TOKEN_SCOPES.SettingsRead,
21800
+ label: {
21801
+ id: "tYQSLw",
21802
+ message: "Settings Read"
21803
+ },
21804
+ description: {
21805
+ id: "fHKrk0",
21806
+ message: "Read site settings"
21807
+ }
21808
+ },
21809
+ {
21810
+ scope: API_TOKEN_SCOPES.SettingsManage,
21811
+ label: {
21812
+ id: "+K5A49",
21813
+ message: "Settings Manage"
21814
+ },
21815
+ description: {
21816
+ id: "RAXQwS",
21817
+ message: "Update site settings"
21818
+ }
21819
+ },
21462
21820
  {
21463
21821
  scope: API_TOKEN_SCOPES.Admin,
21464
21822
  label: {
@@ -23516,8 +23874,9 @@ function SocialSettings() {
23516
23874
  *
23517
23875
  * Steps:
23518
23876
  * 1. Site Configuration (title, tagline, sample content)
23519
- * 2. Admin Account (email, name)
23520
- * 3. Passkey Registration
23877
+ * 2. Create admin account — user picks any available auth method:
23878
+ * - Passkey (always available)
23879
+ * - Any configured auth provider (AT Protocol, GitHub, Google, etc.)
23521
23880
  */
23522
23881
  async function fetchSetupStatus() {
23523
23882
  return parseApiResponse(await apiFetch("/_emdash/api/setup/status"), "Failed to fetch setup status");
@@ -23538,8 +23897,8 @@ async function executeAdminSetup(data) {
23538
23897
  }
23539
23898
  function SiteStep({ seedInfo, onNext, isLoading, error }) {
23540
23899
  const { _: _t } = useLingui();
23541
- const [title, setTitle] = React.useState("");
23542
- const [tagline, setTagline] = React.useState("");
23900
+ const [title, setTitle] = React.useState(seedInfo?.title ?? "");
23901
+ const [tagline, setTagline] = React.useState(seedInfo?.tagline ?? "");
23543
23902
  const [includeContent, setIncludeContent] = React.useState(true);
23544
23903
  const [errors, setErrors] = React.useState({});
23545
23904
  const validate = () => {
@@ -23751,58 +24110,97 @@ function AdminStep({ onNext, onBack, isLoading, error }) {
23751
24110
  ]
23752
24111
  });
23753
24112
  }
23754
- function handlePasskeySuccess() {
24113
+ function handleSetupSuccess() {
23755
24114
  window.location.href = "/_emdash/admin";
23756
24115
  }
23757
- function PasskeyStep({ adminData, onBack }) {
24116
+ function AuthMethodStep({ adminData, providers, onBack }) {
23758
24117
  const { _: _t3 } = useLingui();
24118
+ const [activeProvider, setActiveProvider] = React.useState(null);
24119
+ const buttonProviders = providers.filter((p) => p.LoginButton);
24120
+ const hasProviders = buttonProviders.length > 0;
24121
+ if (activeProvider) {
24122
+ const provider = providers.find((p) => p.id === activeProvider);
24123
+ if (provider && (provider.SetupStep || provider.LoginForm)) return /* @__PURE__ */ jsxs("div", {
24124
+ className: "space-y-4",
24125
+ children: [
24126
+ /* @__PURE__ */ jsx("div", {
24127
+ className: "text-center mb-2",
24128
+ children: /* @__PURE__ */ jsx("h3", {
24129
+ className: "text-lg font-medium",
24130
+ children: _t3({
24131
+ id: "e/ToF5",
24132
+ message: "Sign in with {0}",
24133
+ values: { 0: provider.label }
24134
+ })
24135
+ })
24136
+ }),
24137
+ provider.SetupStep ? /* @__PURE__ */ jsx(provider.SetupStep, { onComplete: handleSetupSuccess }) : provider.LoginForm ? /* @__PURE__ */ jsx(provider.LoginForm, {}) : null,
24138
+ /* @__PURE__ */ jsx(Button, {
24139
+ type: "button",
24140
+ variant: "ghost",
24141
+ className: "w-full justify-center",
24142
+ onClick: () => setActiveProvider(null),
24143
+ children: _t3({
24144
+ id: "2ygf/L",
24145
+ message: "← Back"
24146
+ })
24147
+ })
24148
+ ]
24149
+ });
24150
+ }
23759
24151
  return /* @__PURE__ */ jsxs("div", {
23760
24152
  className: "space-y-6",
23761
24153
  children: [
23762
24154
  /* @__PURE__ */ jsxs("div", {
23763
24155
  className: "text-center",
23764
- children: [
23765
- /* @__PURE__ */ jsx("div", {
23766
- className: "inline-flex items-center justify-center w-16 h-16 rounded-full bg-kumo-brand/10 mb-4",
23767
- children: /* @__PURE__ */ jsx("svg", {
23768
- className: "w-8 h-8 text-kumo-brand",
23769
- fill: "none",
23770
- stroke: "currentColor",
23771
- viewBox: "0 0 24 24",
23772
- children: /* @__PURE__ */ jsx("path", {
23773
- strokeLinecap: "round",
23774
- strokeLinejoin: "round",
23775
- strokeWidth: 2,
23776
- d: "M12 11c0 3.517-1.009 6.799-2.753 9.571m-3.44-2.04l.054-.09A13.916 13.916 0 008 11a4 4 0 118 0c0 1.017-.07 2.019-.203 3m-2.118 6.844A21.88 21.88 0 0015.171 17m3.839 1.132c.645-2.266.99-4.659.99-7.132A8 8 0 008 4.07M3 15.364c.64-1.319 1-2.8 1-4.364 0-1.457.39-2.823 1.07-4"
23777
- })
23778
- })
23779
- }),
23780
- /* @__PURE__ */ jsx("h3", {
23781
- className: "text-lg font-medium",
23782
- children: _t3({
23783
- id: "fifQ8k",
23784
- message: "Set up your passkey"
23785
- })
23786
- }),
23787
- /* @__PURE__ */ jsx("p", {
23788
- className: "text-sm text-kumo-subtle mt-1",
23789
- children: _t3({
23790
- id: "YdZ7D8",
23791
- message: "Passkeys are more secure than passwords. You'll use your device's biometrics, PIN, or security key to sign in."
23792
- })
24156
+ children: [/* @__PURE__ */ jsx("h3", {
24157
+ className: "text-lg font-medium",
24158
+ children: _t3({
24159
+ id: "HAV363",
24160
+ message: "Choose how to sign in"
23793
24161
  })
23794
- ]
24162
+ }), /* @__PURE__ */ jsx("p", {
24163
+ className: "text-sm text-kumo-subtle mt-1",
24164
+ children: _t3({
24165
+ id: "NH33Oi",
24166
+ message: "Pick any method to create your admin account."
24167
+ })
24168
+ })]
23795
24169
  }),
23796
24170
  /* @__PURE__ */ jsx(PasskeyRegistration, {
23797
24171
  optionsEndpoint: "/_emdash/api/setup/admin",
23798
24172
  verifyEndpoint: "/_emdash/api/setup/admin/verify",
23799
- onSuccess: handlePasskeySuccess,
24173
+ onSuccess: handleSetupSuccess,
23800
24174
  buttonText: _t3({
23801
24175
  id: "AKqzR1",
23802
24176
  message: "Create Passkey"
23803
24177
  }),
23804
24178
  additionalData: { ...adminData }
23805
24179
  }),
24180
+ hasProviders && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
24181
+ className: "relative",
24182
+ children: [/* @__PURE__ */ jsx("div", {
24183
+ className: "absolute inset-0 flex items-center",
24184
+ children: /* @__PURE__ */ jsx("span", { className: "w-full border-t" })
24185
+ }), /* @__PURE__ */ jsx("div", {
24186
+ className: "relative flex justify-center text-xs uppercase",
24187
+ children: /* @__PURE__ */ jsx("span", {
24188
+ className: "bg-kumo-base px-2 text-kumo-subtle",
24189
+ children: "Or continue with"
24190
+ })
24191
+ })]
24192
+ }), /* @__PURE__ */ jsx("div", {
24193
+ className: `grid gap-3 ${buttonProviders.length === 1 ? "grid-cols-1" : "grid-cols-2"}`,
24194
+ children: buttonProviders.map((provider) => {
24195
+ const Btn = provider.LoginButton;
24196
+ const hasForm = !!provider.LoginForm || !!provider.SetupStep;
24197
+ const selectProvider = () => setActiveProvider(provider.id);
24198
+ return /* @__PURE__ */ jsx("div", {
24199
+ onClick: hasForm ? selectProvider : void 0,
24200
+ children: /* @__PURE__ */ jsx(Btn, {})
24201
+ }, provider.id);
24202
+ })
24203
+ })] }),
23806
24204
  /* @__PURE__ */ jsx(Button, {
23807
24205
  type: "button",
23808
24206
  variant: "ghost",
@@ -23842,8 +24240,8 @@ function StepIndicator$1({ currentStep, useAccessAuth }) {
23842
24240
  {
23843
24241
  key: "passkey",
23844
24242
  label: _t4({
23845
- id: "FGSN4s",
23846
- message: "Passkey"
24243
+ id: "n1ekoW",
24244
+ message: "Sign In"
23847
24245
  })
23848
24246
  }
23849
24247
  ];
@@ -23881,6 +24279,17 @@ function SetupWizard() {
23881
24279
  const [_siteData, setSiteData] = React.useState(null);
23882
24280
  const [adminData, setAdminData] = React.useState(null);
23883
24281
  const [error, setError] = React.useState();
24282
+ const [urlError, setUrlError] = React.useState(null);
24283
+ const authProviderList = useAuthProviderList();
24284
+ React.useEffect(() => {
24285
+ const params = new URLSearchParams(window.location.search);
24286
+ const errorParam = params.get("error");
24287
+ const message = params.get("message");
24288
+ if (errorParam) {
24289
+ setUrlError(message || `Authentication error: ${errorParam}`);
24290
+ window.history.replaceState({}, "", window.location.pathname);
24291
+ }
24292
+ }, []);
23884
24293
  const { data: status, isLoading: statusLoading, error: statusError } = useQuery({
23885
24294
  queryKey: ["setup", "status"],
23886
24295
  queryFn: fetchSetupStatus,
@@ -23999,6 +24408,10 @@ function SetupWizard() {
23999
24408
  })
24000
24409
  ]
24001
24410
  }),
24411
+ urlError && /* @__PURE__ */ jsx("div", {
24412
+ className: "mb-6 rounded-lg bg-kumo-danger/10 border border-kumo-danger/20 p-4 text-sm text-kumo-danger",
24413
+ children: urlError
24414
+ }),
24002
24415
  /* @__PURE__ */ jsx(StepIndicator$1, {
24003
24416
  currentStep,
24004
24417
  useAccessAuth
@@ -24021,8 +24434,9 @@ function SetupWizard() {
24021
24434
  isLoading: adminMutation.isPending,
24022
24435
  error
24023
24436
  }),
24024
- currentStep === "passkey" && adminData && /* @__PURE__ */ jsx(PasskeyStep, {
24437
+ currentStep === "passkey" && adminData && /* @__PURE__ */ jsx(AuthMethodStep, {
24025
24438
  adminData,
24439
+ providers: authProviderList,
24026
24440
  onBack: () => {
24027
24441
  setError(void 0);
24028
24442
  setCurrentStep("admin");
@@ -25788,7 +26202,7 @@ function TermRow({ term, level = 0, onEdit, onDelete }) {
25788
26202
  className: "flex items-center gap-4 py-2 px-4 border-b hover:bg-kumo-tint/50",
25789
26203
  children: [
25790
26204
  /* @__PURE__ */ jsxs("div", {
25791
- style: { marginLeft: `${level * 1.5}rem` },
26205
+ style: { marginInlineStart: `${level * 1.5}rem` },
25792
26206
  className: "flex-1",
25793
26207
  children: [/* @__PURE__ */ jsx("span", {
25794
26208
  className: "font-medium",
@@ -27132,7 +27546,20 @@ function Widgets() {
27132
27546
  const [activeId, setActiveId] = React.useState(null);
27133
27547
  const [activeDragData, setActiveDragData] = React.useState(null);
27134
27548
  const [expandedWidgets, setExpandedWidgets] = React.useState(/* @__PURE__ */ new Set());
27549
+ const [blockSidebarPanel, setBlockSidebarPanel] = React.useState(null);
27135
27550
  const draggingFromPaletteRef = React.useRef(false);
27551
+ const handleBlockSidebarOpen = React.useCallback((panel) => {
27552
+ setBlockSidebarPanel((prev) => {
27553
+ prev?.onClose();
27554
+ return panel;
27555
+ });
27556
+ }, []);
27557
+ const handleBlockSidebarClose = React.useCallback(() => {
27558
+ setBlockSidebarPanel((prev) => {
27559
+ prev?.onClose();
27560
+ return null;
27561
+ });
27562
+ }, []);
27136
27563
  const { data: areas = [], isLoading } = useQuery({
27137
27564
  queryKey: ["widget-areas"],
27138
27565
  queryFn: fetchWidgetAreas
@@ -27270,174 +27697,189 @@ function Widgets() {
27270
27697
  collisionDetection,
27271
27698
  onDragStart: handleDragStart,
27272
27699
  onDragEnd: handleDragEnd,
27273
- children: [/* @__PURE__ */ jsxs("div", {
27274
- className: "space-y-6",
27275
- children: [/* @__PURE__ */ jsxs("div", {
27276
- className: "flex items-center justify-between",
27277
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
27278
- className: "text-3xl font-bold",
27279
- children: "Widgets"
27280
- }), /* @__PURE__ */ jsx("p", {
27281
- className: "text-kumo-subtle",
27282
- children: "Manage content widgets in your widget areas"
27283
- })] }), /* @__PURE__ */ jsxs(Dialog.Root, {
27284
- open: isCreateAreaOpen,
27285
- onOpenChange: (open) => {
27286
- setIsCreateAreaOpen(open);
27287
- if (!open) setCreateAreaError(null);
27288
- },
27289
- children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (props) => /* @__PURE__ */ jsx(Button, {
27290
- ...props,
27291
- icon: /* @__PURE__ */ jsx(Plus, {}),
27292
- children: "Add Widget Area"
27293
- }) }), /* @__PURE__ */ jsxs(Dialog, {
27294
- className: "p-6",
27295
- size: "lg",
27296
- children: [/* @__PURE__ */ jsxs("div", {
27297
- className: "flex items-start justify-between gap-4 mb-4",
27298
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
27299
- className: "text-lg font-semibold leading-none tracking-tight",
27300
- children: "Create Widget Area"
27301
- }), /* @__PURE__ */ jsx(Dialog.Close, {
27302
- "aria-label": "Close",
27303
- render: (props) => /* @__PURE__ */ jsxs(Button, {
27304
- ...props,
27305
- variant: "ghost",
27306
- shape: "square",
27700
+ children: [
27701
+ /* @__PURE__ */ jsxs("div", {
27702
+ className: "space-y-6",
27703
+ children: [/* @__PURE__ */ jsxs("div", {
27704
+ className: "flex items-center justify-between",
27705
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
27706
+ className: "text-3xl font-bold",
27707
+ children: "Widgets"
27708
+ }), /* @__PURE__ */ jsx("p", {
27709
+ className: "text-kumo-subtle",
27710
+ children: "Manage content widgets in your widget areas"
27711
+ })] }), /* @__PURE__ */ jsxs(Dialog.Root, {
27712
+ open: isCreateAreaOpen,
27713
+ onOpenChange: (open) => {
27714
+ setIsCreateAreaOpen(open);
27715
+ if (!open) setCreateAreaError(null);
27716
+ },
27717
+ children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (props) => /* @__PURE__ */ jsx(Button, {
27718
+ ...props,
27719
+ icon: /* @__PURE__ */ jsx(Plus, {}),
27720
+ children: "Add Widget Area"
27721
+ }) }), /* @__PURE__ */ jsxs(Dialog, {
27722
+ className: "p-6",
27723
+ size: "lg",
27724
+ children: [/* @__PURE__ */ jsxs("div", {
27725
+ className: "flex items-start justify-between gap-4 mb-4",
27726
+ children: [/* @__PURE__ */ jsx(Dialog.Title, {
27727
+ className: "text-lg font-semibold leading-none tracking-tight",
27728
+ children: "Create Widget Area"
27729
+ }), /* @__PURE__ */ jsx(Dialog.Close, {
27307
27730
  "aria-label": "Close",
27308
- className: "absolute end-4 top-4",
27309
- children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
27310
- className: "sr-only",
27311
- children: "Close"
27312
- })]
27313
- })
27731
+ render: (props) => /* @__PURE__ */ jsxs(Button, {
27732
+ ...props,
27733
+ variant: "ghost",
27734
+ shape: "square",
27735
+ "aria-label": "Close",
27736
+ className: "absolute end-4 top-4",
27737
+ children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
27738
+ className: "sr-only",
27739
+ children: "Close"
27740
+ })]
27741
+ })
27742
+ })]
27743
+ }), /* @__PURE__ */ jsxs("form", {
27744
+ onSubmit: handleCreateArea,
27745
+ className: "space-y-4",
27746
+ children: [
27747
+ /* @__PURE__ */ jsx(Input, {
27748
+ label: "Name",
27749
+ name: "name",
27750
+ required: true,
27751
+ placeholder: "sidebar",
27752
+ pattern: "[a-z0-9-]+"
27753
+ }),
27754
+ /* @__PURE__ */ jsx(Input, {
27755
+ label: "Label",
27756
+ name: "label",
27757
+ required: true,
27758
+ placeholder: "Main Sidebar"
27759
+ }),
27760
+ /* @__PURE__ */ jsx(Input, {
27761
+ label: "Description",
27762
+ name: "description",
27763
+ placeholder: "Appears on posts and pages"
27764
+ }),
27765
+ /* @__PURE__ */ jsx(DialogError, { message: createAreaError || getMutationError(createAreaMutation.error) }),
27766
+ /* @__PURE__ */ jsxs("div", {
27767
+ className: "flex justify-end gap-2",
27768
+ children: [/* @__PURE__ */ jsx(Button, {
27769
+ type: "button",
27770
+ variant: "outline",
27771
+ onClick: () => setIsCreateAreaOpen(false),
27772
+ children: "Cancel"
27773
+ }), /* @__PURE__ */ jsx(Button, {
27774
+ type: "submit",
27775
+ disabled: createAreaMutation.isPending,
27776
+ children: "Create"
27777
+ })]
27778
+ })
27779
+ ]
27314
27780
  })]
27315
- }), /* @__PURE__ */ jsxs("form", {
27316
- onSubmit: handleCreateArea,
27317
- className: "space-y-4",
27781
+ })]
27782
+ })]
27783
+ }), /* @__PURE__ */ jsxs("div", {
27784
+ className: "grid grid-cols-12 gap-6",
27785
+ children: [/* @__PURE__ */ jsx("div", {
27786
+ className: "col-span-4",
27787
+ children: /* @__PURE__ */ jsxs("div", {
27788
+ className: "rounded-lg border bg-kumo-base p-6 space-y-4",
27318
27789
  children: [
27319
- /* @__PURE__ */ jsx(Input, {
27320
- label: "Name",
27321
- name: "name",
27322
- required: true,
27323
- placeholder: "sidebar",
27324
- pattern: "[a-z0-9-]+"
27325
- }),
27326
- /* @__PURE__ */ jsx(Input, {
27327
- label: "Label",
27328
- name: "label",
27329
- required: true,
27330
- placeholder: "Main Sidebar"
27790
+ /* @__PURE__ */ jsx("h2", {
27791
+ className: "text-xl font-semibold",
27792
+ children: "Available Widgets"
27331
27793
  }),
27332
- /* @__PURE__ */ jsx(Input, {
27333
- label: "Description",
27334
- name: "description",
27335
- placeholder: "Appears on posts and pages"
27794
+ /* @__PURE__ */ jsx("p", {
27795
+ className: "text-sm text-kumo-subtle",
27796
+ children: "Drag widgets into an area to add them"
27336
27797
  }),
27337
- /* @__PURE__ */ jsx(DialogError, { message: createAreaError || getMutationError(createAreaMutation.error) }),
27338
27798
  /* @__PURE__ */ jsxs("div", {
27339
- className: "flex justify-end gap-2",
27340
- children: [/* @__PURE__ */ jsx(Button, {
27341
- type: "button",
27342
- variant: "outline",
27343
- onClick: () => setIsCreateAreaOpen(false),
27344
- children: "Cancel"
27345
- }), /* @__PURE__ */ jsx(Button, {
27346
- type: "submit",
27347
- disabled: createAreaMutation.isPending,
27348
- children: "Create"
27349
- })]
27799
+ className: "space-y-2",
27800
+ children: [BUILTIN_WIDGETS.map((item) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
27801
+ id: item.id,
27802
+ label: _t(item.label),
27803
+ description: _t(item.description),
27804
+ widgetInput: {
27805
+ ...item.input,
27806
+ title: _t(item.label)
27807
+ }
27808
+ }, item.id)), components.map((comp) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
27809
+ id: `palette-comp-${comp.id}`,
27810
+ label: comp.label,
27811
+ description: comp.description,
27812
+ widgetInput: {
27813
+ type: "component",
27814
+ title: comp.label,
27815
+ componentId: comp.id
27816
+ }
27817
+ }, `palette-comp-${comp.id}`))]
27350
27818
  })
27351
27819
  ]
27352
- })]
27820
+ })
27821
+ }), /* @__PURE__ */ jsx("div", {
27822
+ className: "col-span-8 space-y-4",
27823
+ children: areas.length === 0 ? /* @__PURE__ */ jsx("div", {
27824
+ className: "rounded-lg border bg-kumo-base p-12 text-center",
27825
+ children: /* @__PURE__ */ jsx("p", {
27826
+ className: "text-kumo-subtle",
27827
+ children: "No widget areas yet. Create one to get started."
27828
+ })
27829
+ }) : areas.map((area) => /* @__PURE__ */ jsx(WidgetAreaPanel, {
27830
+ area,
27831
+ expandedWidgets,
27832
+ onToggleWidget: toggleWidget,
27833
+ isDraggingPalette: activeDragData !== null && isPaletteItem(activeDragData),
27834
+ components,
27835
+ pluginBlocks,
27836
+ onBlockSidebarOpen: handleBlockSidebarOpen,
27837
+ onBlockSidebarClose: handleBlockSidebarClose
27838
+ }, area.id))
27353
27839
  })]
27354
27840
  })]
27355
- }), /* @__PURE__ */ jsxs("div", {
27356
- className: "grid grid-cols-12 gap-6",
27357
- children: [/* @__PURE__ */ jsx("div", {
27358
- className: "col-span-4",
27841
+ }),
27842
+ /* @__PURE__ */ jsx(DragOverlay, {
27843
+ dropAnimation: draggingFromPaletteRef.current ? null : void 0,
27844
+ children: activePaletteLabel ? /* @__PURE__ */ jsx("div", {
27845
+ className: "rounded border bg-kumo-base p-3 shadow-lg opacity-90",
27846
+ children: /* @__PURE__ */ jsx("div", {
27847
+ className: "font-medium",
27848
+ children: activePaletteLabel
27849
+ })
27850
+ }) : activeWidget ? /* @__PURE__ */ jsx("div", {
27851
+ className: "rounded border bg-kumo-base p-3 shadow-lg opacity-90",
27359
27852
  children: /* @__PURE__ */ jsxs("div", {
27360
- className: "rounded-lg border bg-kumo-base p-6 space-y-4",
27853
+ className: "flex items-center gap-2",
27361
27854
  children: [
27362
- /* @__PURE__ */ jsx("h2", {
27363
- className: "text-xl font-semibold",
27364
- children: "Available Widgets"
27365
- }),
27366
- /* @__PURE__ */ jsx("p", {
27367
- className: "text-sm text-kumo-subtle",
27368
- children: "Drag widgets into an area to add them"
27855
+ /* @__PURE__ */ jsx(DotsSixVertical, { className: "h-4 w-4 text-kumo-subtle" }),
27856
+ /* @__PURE__ */ jsx("span", {
27857
+ className: "font-medium",
27858
+ children: activeWidget.title || "Untitled Widget"
27369
27859
  }),
27370
- /* @__PURE__ */ jsxs("div", {
27371
- className: "space-y-2",
27372
- children: [BUILTIN_WIDGETS.map((item) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
27373
- id: item.id,
27374
- label: _t(item.label),
27375
- description: _t(item.description),
27376
- widgetInput: {
27377
- ...item.input,
27378
- title: _t(item.label)
27379
- }
27380
- }, item.id)), components.map((comp) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
27381
- id: `palette-comp-${comp.id}`,
27382
- label: comp.label,
27383
- description: comp.description,
27384
- widgetInput: {
27385
- type: "component",
27386
- title: comp.label,
27387
- componentId: comp.id
27388
- }
27389
- }, `palette-comp-${comp.id}`))]
27860
+ /* @__PURE__ */ jsxs("span", {
27861
+ className: "text-xs text-kumo-subtle",
27862
+ children: [
27863
+ "(",
27864
+ activeWidget.type,
27865
+ ")"
27866
+ ]
27390
27867
  })
27391
27868
  ]
27392
27869
  })
27393
- }), /* @__PURE__ */ jsx("div", {
27394
- className: "col-span-8 space-y-4",
27395
- children: areas.length === 0 ? /* @__PURE__ */ jsx("div", {
27396
- className: "rounded-lg border bg-kumo-base p-12 text-center",
27397
- children: /* @__PURE__ */ jsx("p", {
27398
- className: "text-kumo-subtle",
27399
- children: "No widget areas yet. Create one to get started."
27400
- })
27401
- }) : areas.map((area) => /* @__PURE__ */ jsx(WidgetAreaPanel, {
27402
- area,
27403
- expandedWidgets,
27404
- onToggleWidget: toggleWidget,
27405
- isDraggingPalette: activeDragData !== null && isPaletteItem(activeDragData),
27406
- components,
27407
- pluginBlocks
27408
- }, area.id))
27409
- })]
27410
- })]
27411
- }), /* @__PURE__ */ jsx(DragOverlay, {
27412
- dropAnimation: draggingFromPaletteRef.current ? null : void 0,
27413
- children: activePaletteLabel ? /* @__PURE__ */ jsx("div", {
27414
- className: "rounded border bg-kumo-base p-3 shadow-lg opacity-90",
27415
- children: /* @__PURE__ */ jsx("div", {
27416
- className: "font-medium",
27417
- children: activePaletteLabel
27418
- })
27419
- }) : activeWidget ? /* @__PURE__ */ jsx("div", {
27420
- className: "rounded border bg-kumo-base p-3 shadow-lg opacity-90",
27421
- children: /* @__PURE__ */ jsxs("div", {
27422
- className: "flex items-center gap-2",
27423
- children: [
27424
- /* @__PURE__ */ jsx(DotsSixVertical, { className: "h-4 w-4 text-kumo-subtle" }),
27425
- /* @__PURE__ */ jsx("span", {
27426
- className: "font-medium",
27427
- children: activeWidget.title || "Untitled Widget"
27428
- }),
27429
- /* @__PURE__ */ jsxs("span", {
27430
- className: "text-xs text-kumo-subtle",
27431
- children: [
27432
- "(",
27433
- activeWidget.type,
27434
- ")"
27435
- ]
27436
- })
27437
- ]
27438
- })
27439
- }) : null
27440
- })]
27870
+ }) : null
27871
+ }),
27872
+ blockSidebarPanel?.type === "image" && /* @__PURE__ */ jsx(ImageDetailPanel, {
27873
+ attributes: blockSidebarPanel.attrs,
27874
+ onUpdate: (attrs) => blockSidebarPanel.onUpdate(attrs),
27875
+ onReplace: (attrs) => blockSidebarPanel.onReplace(attrs),
27876
+ onDelete: () => {
27877
+ blockSidebarPanel.onDelete();
27878
+ setBlockSidebarPanel(null);
27879
+ },
27880
+ onClose: handleBlockSidebarClose
27881
+ })
27882
+ ]
27441
27883
  });
27442
27884
  }
27443
27885
  /** A draggable item in the available widgets palette */
@@ -27464,7 +27906,7 @@ function DraggablePaletteItem({ id, label, description, widgetInput }) {
27464
27906
  })]
27465
27907
  });
27466
27908
  }
27467
- function WidgetAreaPanel({ area, expandedWidgets, onToggleWidget, isDraggingPalette, components, pluginBlocks }) {
27909
+ function WidgetAreaPanel({ area, expandedWidgets, onToggleWidget, isDraggingPalette, components, pluginBlocks, onBlockSidebarOpen, onBlockSidebarClose }) {
27468
27910
  const queryClient = useQueryClient();
27469
27911
  const toastManager = Toast.useToastManager();
27470
27912
  const [deleteAreaName, setDeleteAreaName] = React.useState(null);
@@ -27510,7 +27952,9 @@ function WidgetAreaPanel({ area, expandedWidgets, onToggleWidget, isDraggingPale
27510
27952
  isExpanded: expandedWidgets.has(widget.id),
27511
27953
  onToggle: () => onToggleWidget(widget.id),
27512
27954
  components,
27513
- pluginBlocks
27955
+ pluginBlocks,
27956
+ onBlockSidebarOpen,
27957
+ onBlockSidebarClose
27514
27958
  }, widget.id))
27515
27959
  }) : null,
27516
27960
  isDraggingPalette && /* @__PURE__ */ jsx("div", {
@@ -27540,7 +27984,7 @@ function WidgetAreaPanel({ area, expandedWidgets, onToggleWidget, isDraggingPale
27540
27984
  ]
27541
27985
  });
27542
27986
  }
27543
- function WidgetItem({ widget, areaName, isExpanded, onToggle, components, pluginBlocks }) {
27987
+ function WidgetItem({ widget, areaName, isExpanded, onToggle, components, pluginBlocks, onBlockSidebarOpen, onBlockSidebarClose }) {
27544
27988
  const queryClient = useQueryClient();
27545
27989
  const toastManager = Toast.useToastManager();
27546
27990
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
@@ -27632,12 +28076,14 @@ function WidgetItem({ widget, areaName, isExpanded, onToggle, components, plugin
27632
28076
  components,
27633
28077
  pluginBlocks,
27634
28078
  onSave: (input) => updateMutation.mutate(input),
27635
- isSaving: updateMutation.isPending
28079
+ isSaving: updateMutation.isPending,
28080
+ onBlockSidebarOpen,
28081
+ onBlockSidebarClose
27636
28082
  })]
27637
28083
  });
27638
28084
  }
27639
28085
  /** Inline editor form for a widget, rendered when the widget is expanded */
27640
- function WidgetEditor({ widget, components, pluginBlocks, onSave, isSaving }) {
28086
+ function WidgetEditor({ widget, components, pluginBlocks, onSave, isSaving, onBlockSidebarOpen, onBlockSidebarClose }) {
27641
28087
  const [title, setTitle] = React.useState(widget.title ?? "");
27642
28088
  const [content, setContent] = React.useState(Array.isArray(widget.content) ? widget.content : []);
27643
28089
  const [menuName, setMenuName] = React.useState(widget.menuName ?? "");
@@ -27676,7 +28122,9 @@ function WidgetEditor({ widget, components, pluginBlocks, onSave, isSaving }) {
27676
28122
  onChange: (value) => setContent(value),
27677
28123
  minimal: true,
27678
28124
  placeholder: "Write widget content...",
27679
- pluginBlocks
28125
+ pluginBlocks,
28126
+ onBlockSidebarOpen,
28127
+ onBlockSidebarClose
27680
28128
  })] }),
27681
28129
  widget.type === "menu" && /* @__PURE__ */ jsxs(Select, {
27682
28130
  label: "Menu",
@@ -31894,16 +32342,25 @@ function ContentListPage() {
31894
32342
  });
31895
32343
  const i18n = manifest?.i18n;
31896
32344
  const activeLocale = i18n ? localeParam ?? i18n.defaultLocale : void 0;
32345
+ const [sort, setSort] = React.useState({
32346
+ field: "updatedAt",
32347
+ direction: "desc"
32348
+ });
31897
32349
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, error } = useInfiniteQuery({
31898
32350
  queryKey: [
31899
32351
  "content",
31900
32352
  collection,
31901
- { locale: activeLocale }
32353
+ {
32354
+ locale: activeLocale,
32355
+ sort
32356
+ }
31902
32357
  ],
31903
32358
  queryFn: ({ pageParam }) => fetchContentList(collection, {
31904
32359
  locale: activeLocale,
31905
32360
  cursor: pageParam,
31906
- limit: 100
32361
+ limit: 100,
32362
+ orderBy: sort.field,
32363
+ order: sort.direction
31907
32364
  }),
31908
32365
  initialPageParam: void 0,
31909
32366
  getNextPageParam: (lastPage) => lastPage.nextCursor,
@@ -32014,7 +32471,9 @@ function ContentListPage() {
32014
32471
  i18n,
32015
32472
  activeLocale,
32016
32473
  onLocaleChange: handleLocaleChange,
32017
- urlPattern: collectionConfig.urlPattern
32474
+ urlPattern: collectionConfig.urlPattern,
32475
+ sort,
32476
+ onSortChange: setSort
32018
32477
  });
32019
32478
  }
32020
32479
  const contentNewRoute = createRoute({
@@ -32734,7 +33193,7 @@ function MarketplaceBrowsePage() {
32734
33193
  const { data: plugins } = useQuery({
32735
33194
  queryKey: ["plugins"],
32736
33195
  queryFn: async () => {
32737
- const { fetchPlugins } = await import("./plugins-XhZqfegd.js").then((n) => n.a);
33196
+ const { fetchPlugins } = await import("./plugins-DUJY_8HN.js").then((n) => n.a);
32738
33197
  return fetchPlugins();
32739
33198
  }
32740
33199
  });
@@ -32753,7 +33212,7 @@ function MarketplaceDetailPage() {
32753
33212
  const { data: plugins } = useQuery({
32754
33213
  queryKey: ["plugins"],
32755
33214
  queryFn: async () => {
32756
- const { fetchPlugins } = await import("./plugins-XhZqfegd.js").then((n) => n.a);
33215
+ const { fetchPlugins } = await import("./plugins-DUJY_8HN.js").then((n) => n.a);
32757
33216
  return fetchPlugins();
32758
33217
  }
32759
33218
  });
@@ -33166,7 +33625,8 @@ const router = createAdminRouter(queryClient);
33166
33625
  * Main Admin Application
33167
33626
  */
33168
33627
  const EMPTY_PLUGINS = {};
33169
- function AdminApp({ pluginAdmins = EMPTY_PLUGINS, locale = "en", messages = {} }) {
33628
+ const EMPTY_AUTH_PROVIDERS = {};
33629
+ function AdminApp({ pluginAdmins = EMPTY_PLUGINS, authProviders = EMPTY_AUTH_PROVIDERS, locale = "en", messages = {} }) {
33170
33630
  React.useEffect(() => {
33171
33631
  document.getElementById("emdash-boot-loader")?.remove();
33172
33632
  }, []);
@@ -33180,16 +33640,19 @@ function AdminApp({ pluginAdmins = EMPTY_PLUGINS, locale = "en", messages = {} }
33180
33640
  }
33181
33641
  return /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(I18nProvider, {
33182
33642
  i18n,
33183
- children: /* @__PURE__ */ jsx(LocaleDirectionProvider, { children: /* @__PURE__ */ jsx(Toasty, { children: /* @__PURE__ */ jsx(PluginAdminProvider, {
33184
- pluginAdmins,
33185
- children: /* @__PURE__ */ jsx(QueryClientProvider, {
33186
- client: queryClient,
33187
- children: /* @__PURE__ */ jsx(RouterProvider, { router })
33643
+ children: /* @__PURE__ */ jsx(LocaleDirectionProvider, { children: /* @__PURE__ */ jsx(Toasty, { children: /* @__PURE__ */ jsx(AuthProviderProvider, {
33644
+ authProviders,
33645
+ children: /* @__PURE__ */ jsx(PluginAdminProvider, {
33646
+ pluginAdmins,
33647
+ children: /* @__PURE__ */ jsx(QueryClientProvider, {
33648
+ client: queryClient,
33649
+ children: /* @__PURE__ */ jsx(RouterProvider, { router })
33650
+ })
33188
33651
  })
33189
33652
  }) }) })
33190
33653
  }) });
33191
33654
  }
33192
33655
 
33193
33656
  //#endregion
33194
- export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, CAPABILITY_LABELS, ContentEditor, ContentList, DEFAULT_LOCALE, Dashboard, Header, Link, LoginPage, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SUPPORTED_LOCALES, SUPPORTED_LOCALE_CODES, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createCollection, createContent, createField, createMenu, createMenuItem, createRedirect, createSection, createTaxonomy, createTerm, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchByline, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, resolveLocale, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useCurrentUser, useLocale, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, validateInviteToken, verifySignupToken };
33657
+ export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, AuthProviderProvider, CAPABILITY_LABELS, ContentEditor, ContentList, DEFAULT_LOCALE, Dashboard, Header, Link, LoginPage, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SUPPORTED_LOCALES, SUPPORTED_LOCALE_CODES, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createCollection, createContent, createField, createMenu, createMenuItem, createRedirect, createSection, createTaxonomy, createTerm, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchAuthMode, fetchByline, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, resolveLocale, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useAuthProviderList, useAuthProviders, useCurrentUser, useLocale, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, validateInviteToken, verifySignupToken };
33195
33658
  //# sourceMappingURL=index.js.map