@emdash-cms/admin 0.11.1 → 0.12.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 (89) hide show
  1. package/dist/{LocaleDirectionProvider-PhIYobDG.js → LocaleDirectionProvider-cjRhNz57.js} +17 -17
  2. package/dist/{LocaleDirectionProvider-PhIYobDG.js.map → LocaleDirectionProvider-cjRhNz57.js.map} +1 -1
  3. package/dist/index.d.ts +21 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +213 -36
  6. package/dist/index.js.map +1 -1
  7. package/dist/locales/ar/messages.mjs +1 -1
  8. package/dist/locales/de/messages.mjs +1 -1
  9. package/dist/locales/en/messages.mjs +1 -1
  10. package/dist/locales/es-419/messages.mjs +1 -1
  11. package/dist/locales/es-ES/messages.mjs +1 -1
  12. package/dist/locales/eu/messages.mjs +1 -1
  13. package/dist/locales/fa/messages.mjs +1 -1
  14. package/dist/locales/fr/messages.mjs +1 -1
  15. package/dist/locales/id/messages.mjs +1 -1
  16. package/dist/locales/index.js +1 -1
  17. package/dist/locales/ja/messages.mjs +1 -1
  18. package/dist/locales/ko/messages.mjs +1 -1
  19. package/dist/locales/pl/messages.mjs +1 -1
  20. package/dist/locales/pseudo/messages.mjs +1 -1
  21. package/dist/locales/pt-BR/messages.mjs +1 -1
  22. package/dist/locales/zh-CN/messages.mjs +1 -1
  23. package/dist/locales/zh-TW/messages.mjs +1 -1
  24. package/dist/messages-9_R3aCM9.js +6 -0
  25. package/dist/messages-9_R3aCM9.js.map +1 -0
  26. package/dist/messages-A-cROb0f.js +6 -0
  27. package/dist/messages-A-cROb0f.js.map +1 -0
  28. package/dist/messages-B3-g6YaO.js +6 -0
  29. package/dist/messages-B3-g6YaO.js.map +1 -0
  30. package/dist/messages-B5UEpxLj.js +6 -0
  31. package/dist/messages-B5UEpxLj.js.map +1 -0
  32. package/dist/messages-BAEa2eLw.js +6 -0
  33. package/dist/messages-BAEa2eLw.js.map +1 -0
  34. package/dist/messages-BHndsjBE.js +6 -0
  35. package/dist/messages-BHndsjBE.js.map +1 -0
  36. package/dist/messages-BNPbaoQs.js +6 -0
  37. package/dist/messages-BNPbaoQs.js.map +1 -0
  38. package/dist/messages-BieStAB8.js +6 -0
  39. package/dist/messages-BieStAB8.js.map +1 -0
  40. package/dist/messages-COU-tgjA.js +6 -0
  41. package/dist/messages-COU-tgjA.js.map +1 -0
  42. package/dist/messages-CXVvqhvr.js +6 -0
  43. package/dist/messages-CXVvqhvr.js.map +1 -0
  44. package/dist/messages-CgTwIPDv.js +6 -0
  45. package/dist/messages-CgTwIPDv.js.map +1 -0
  46. package/dist/messages-CtPGWm7g.js +6 -0
  47. package/dist/messages-CtPGWm7g.js.map +1 -0
  48. package/dist/messages-DES9CrLv.js +6 -0
  49. package/dist/messages-DES9CrLv.js.map +1 -0
  50. package/dist/messages-DQTZQuDt.js +6 -0
  51. package/dist/messages-DQTZQuDt.js.map +1 -0
  52. package/dist/messages-Dw1e-SNm.js +6 -0
  53. package/dist/messages-Dw1e-SNm.js.map +1 -0
  54. package/dist/messages-Dzvc57yv.js +6 -0
  55. package/dist/messages-Dzvc57yv.js.map +1 -0
  56. package/dist/styles.css +1 -1
  57. package/package.json +2 -2
  58. package/dist/messages-0WS1kU2r.js +0 -6
  59. package/dist/messages-0WS1kU2r.js.map +0 -1
  60. package/dist/messages-B3nZXT9a.js +0 -6
  61. package/dist/messages-B3nZXT9a.js.map +0 -1
  62. package/dist/messages-BHe7DjK4.js +0 -6
  63. package/dist/messages-BHe7DjK4.js.map +0 -1
  64. package/dist/messages-BNm9xWl9.js +0 -6
  65. package/dist/messages-BNm9xWl9.js.map +0 -1
  66. package/dist/messages-Bf6-l0VR.js +0 -6
  67. package/dist/messages-Bf6-l0VR.js.map +0 -1
  68. package/dist/messages-C2QjBo2p.js +0 -6
  69. package/dist/messages-C2QjBo2p.js.map +0 -1
  70. package/dist/messages-CAYw_5r5.js +0 -6
  71. package/dist/messages-CAYw_5r5.js.map +0 -1
  72. package/dist/messages-CBAO8mkk.js +0 -6
  73. package/dist/messages-CBAO8mkk.js.map +0 -1
  74. package/dist/messages-CNsSgfXs.js +0 -6
  75. package/dist/messages-CNsSgfXs.js.map +0 -1
  76. package/dist/messages-CgrjHEi_.js +0 -6
  77. package/dist/messages-CgrjHEi_.js.map +0 -1
  78. package/dist/messages-DCoCdFuY.js +0 -6
  79. package/dist/messages-DCoCdFuY.js.map +0 -1
  80. package/dist/messages-DdvAysPo.js +0 -6
  81. package/dist/messages-DdvAysPo.js.map +0 -1
  82. package/dist/messages-Di1aYzxi.js +0 -6
  83. package/dist/messages-Di1aYzxi.js.map +0 -1
  84. package/dist/messages-NtPfr5Dr.js +0 -6
  85. package/dist/messages-NtPfr5Dr.js.map +0 -1
  86. package/dist/messages-Y1VN2Mk3.js +0 -6
  87. package/dist/messages-Y1VN2Mk3.js.map +0 -1
  88. package/dist/messages-cjsZTyVv.js +0 -6
  89. package/dist/messages-cjsZTyVv.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
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-qrjvPK4g.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-PhIYobDG.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-cjRhNz57.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";
@@ -3122,7 +3122,7 @@ function probeImageDimensions(url, errorMessage) {
3122
3122
  img.src = url;
3123
3123
  });
3124
3124
  }
3125
- function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "image/", mimeTypeFilters, fieldId, title: providedTitle, hideUrlInput = false, mediaKind = "image" }) {
3125
+ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "image/", mimeTypeFilters, fieldId, title: providedTitle, hideUrlInput = false, mediaKind = "image", localOnly = false }) {
3126
3126
  const { _: _t } = useLingui();
3127
3127
  const isFileKind = mediaKind === "file";
3128
3128
  const filters = React$1.useMemo(() => {
@@ -3170,11 +3170,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3170
3170
  setUploadError(null);
3171
3171
  setProviderDimensions({});
3172
3172
  }
3173
- }, [open]);
3173
+ }, [open, localOnly]);
3174
3174
  const { data: providers } = useQuery({
3175
3175
  queryKey: ["media-providers"],
3176
3176
  queryFn: fetchMediaProviders,
3177
- enabled: open,
3177
+ enabled: open && !localOnly,
3178
3178
  placeholderData: []
3179
3179
  });
3180
3180
  const activeProviderInfo = React$1.useMemo(() => {
@@ -3191,12 +3191,15 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3191
3191
  };
3192
3192
  return providers?.find((p) => p.id === activeProvider);
3193
3193
  }, [activeProvider, providers]);
3194
- const { data: localData, isLoading: localLoading } = useQuery({
3194
+ const { data: localData, isLoading: localLoading, fetchNextPage: fetchNextLocalPage, hasNextPage: hasNextLocalPage, isFetchingNextPage: isFetchingNextLocalPage } = useInfiniteQuery({
3195
3195
  queryKey: ["media", filters?.join(",") ?? ""],
3196
- queryFn: () => fetchMediaList({
3196
+ queryFn: ({ pageParam }) => fetchMediaList({
3197
3197
  mimeType: filters,
3198
- limit: 50
3198
+ cursor: pageParam,
3199
+ limit: 100
3199
3200
  }),
3201
+ initialPageParam: void 0,
3202
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
3200
3203
  enabled: open && activeProvider === "local"
3201
3204
  });
3202
3205
  const { data: providerData, isLoading: providerLoading } = useQuery({
@@ -3211,9 +3214,9 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3211
3214
  limit: 50,
3212
3215
  query: searchQuery || void 0
3213
3216
  }),
3214
- enabled: open && activeProvider !== "local"
3217
+ enabled: open && !localOnly && activeProvider !== "local"
3215
3218
  });
3216
- const isLoading = activeProvider === "local" ? localLoading : providerLoading;
3219
+ const isLoading = activeProvider === "local" ? localLoading || isFetchingNextLocalPage : providerLoading;
3217
3220
  const [uploadError, setUploadError] = React$1.useState(null);
3218
3221
  const uploadLocalMutation = useMutation({
3219
3222
  mutationFn: (file) => uploadMedia(file, { fieldId }),
@@ -3255,11 +3258,14 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3255
3258
  if (!old) return old;
3256
3259
  return {
3257
3260
  ...old,
3258
- items: old.items.map((item) => item.id === id ? {
3259
- ...item,
3260
- width,
3261
- height
3262
- } : item)
3261
+ pages: old.pages.map((page) => ({
3262
+ ...page,
3263
+ items: page.items.map((item) => item.id === id ? {
3264
+ ...item,
3265
+ width,
3266
+ height
3267
+ } : item)
3268
+ }))
3263
3269
  };
3264
3270
  });
3265
3271
  if (selectedItem?.providerId === "local" && selectedItem.item.id === id) setSelectedItem({
@@ -3285,11 +3291,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3285
3291
  });
3286
3292
  }, [dimensionsMutation]);
3287
3293
  const items = React$1.useMemo(() => {
3288
- if (activeProvider === "local") return (localData?.items || []).filter((item) => matchesAnyFilter(item.mimeType, filters));
3294
+ if (activeProvider === "local") return (localData?.pages.flatMap((page) => page.items) || []).filter((item) => matchesAnyFilter(item.mimeType, filters));
3289
3295
  return providerData?.items || [];
3290
3296
  }, [
3291
3297
  activeProvider,
3292
- localData?.items,
3298
+ localData,
3293
3299
  providerData?.items,
3294
3300
  filters
3295
3301
  ]);
@@ -3399,7 +3405,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3399
3405
  name: "Library",
3400
3406
  icon: void 0
3401
3407
  }];
3402
- if (providers) {
3408
+ if (providers && !localOnly) {
3403
3409
  for (const p of providers) if (p.id !== "local") tabs.push({
3404
3410
  id: p.id,
3405
3411
  name: p.name,
@@ -3407,7 +3413,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3407
3413
  });
3408
3414
  }
3409
3415
  return tabs;
3410
- }, [providers]);
3416
+ }, [providers, localOnly]);
3411
3417
  return /* @__PURE__ */ jsx(Dialog.Root, {
3412
3418
  open,
3413
3419
  onOpenChange: handleClose,
@@ -3444,7 +3450,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3444
3450
  })
3445
3451
  })]
3446
3452
  }),
3447
- !hideUrlInput && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
3453
+ !hideUrlInput && !localOnly && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
3448
3454
  className: "border-b pb-4",
3449
3455
  children: [
3450
3456
  /* @__PURE__ */ jsx(Label, { children: _t({
@@ -3581,9 +3587,9 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3581
3587
  }) : null,
3582
3588
  className: "mb-3"
3583
3589
  }),
3584
- /* @__PURE__ */ jsx("div", {
3590
+ /* @__PURE__ */ jsxs("div", {
3585
3591
  className: "flex-1 overflow-y-auto min-h-0",
3586
- children: isLoading ? /* @__PURE__ */ jsx("div", {
3592
+ children: [isLoading && items.length === 0 ? /* @__PURE__ */ jsx("div", {
3587
3593
  className: "flex items-center justify-center h-full",
3588
3594
  children: /* @__PURE__ */ jsx(Loader, {})
3589
3595
  }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", {
@@ -3662,7 +3668,22 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3662
3668
  }));
3663
3669
  }
3664
3670
  }, item.id))
3665
- })
3671
+ }), activeProvider === "local" && hasNextLocalPage && /* @__PURE__ */ jsx("div", {
3672
+ className: "flex justify-center py-3",
3673
+ children: /* @__PURE__ */ jsx(Button, {
3674
+ variant: "outline",
3675
+ size: "sm",
3676
+ onClick: () => void fetchNextLocalPage(),
3677
+ disabled: isFetchingNextLocalPage,
3678
+ children: isFetchingNextLocalPage ? _t({
3679
+ id: "Z3FXyt",
3680
+ message: "Loading..."
3681
+ }) : _t({
3682
+ id: "a4N/Bg",
3683
+ message: "Load More"
3684
+ })
3685
+ })
3686
+ })]
3666
3687
  }),
3667
3688
  /* @__PURE__ */ jsxs("div", {
3668
3689
  className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 border-t pt-4",
@@ -7969,7 +7990,7 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
7969
7990
  /** When editing an existing block, store the node position for updateAttributes */
7970
7991
  const editingBlockPosRef = React$1.useRef(null);
7971
7992
  const [sectionPickerOpen, setSectionPickerOpen] = React$1.useState(false);
7972
- const [slashMenuState, setSlashMenuState] = React$1.useState({
7993
+ const [slashMenuState, setSlashMenuStateRaw] = React$1.useState({
7973
7994
  isOpen: false,
7974
7995
  items: [],
7975
7996
  selectedIndex: 0,
@@ -7977,9 +7998,11 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
7977
7998
  range: null
7978
7999
  });
7979
8000
  const slashMenuStateRef = React$1.useRef(slashMenuState);
7980
- React$1.useEffect(() => {
7981
- slashMenuStateRef.current = slashMenuState;
7982
- }, [slashMenuState]);
8001
+ const setSlashMenuState = React$1.useCallback((action) => {
8002
+ const next = typeof action === "function" ? action(slashMenuStateRef.current) : action;
8003
+ slashMenuStateRef.current = next;
8004
+ setSlashMenuStateRaw(next);
8005
+ }, []);
7983
8006
  const slashCommands = React$1.useMemo(() => {
7984
8007
  const cmds = [...defaultSlashCommands];
7985
8008
  cmds.push({
@@ -19099,7 +19122,7 @@ function formatDate(isoString) {
19099
19122
  /**
19100
19123
  * Media library component with upload, provider tabs, and grid view
19101
19124
  */
19102
- function MediaLibrary({ items = [], isLoading, onUpload, onDelete, onItemUpdated }) {
19125
+ function MediaLibrary({ items = [], isLoading, onUpload, onDelete, onItemUpdated, hasMore, onLoadMore }) {
19103
19126
  const { _: _t } = useLingui();
19104
19127
  const [viewMode, setViewMode] = React$1.useState("grid");
19105
19128
  const [selectedItem, setSelectedItem] = React$1.useState(null);
@@ -19437,7 +19460,7 @@ function MediaLibrary({ items = [], isLoading, onUpload, onDelete, onItemUpdated
19437
19460
  className: "ps-9"
19438
19461
  })]
19439
19462
  }),
19440
- currentLoading ? /* @__PURE__ */ jsx("div", {
19463
+ currentLoading && currentItems.length === 0 && currentProviderItems.length === 0 ? /* @__PURE__ */ jsx("div", {
19441
19464
  className: "flex items-center justify-center py-12",
19442
19465
  children: /* @__PURE__ */ jsx(Loader, {})
19443
19466
  }) : activeProvider === "local" && currentItems.length === 0 ? /* @__PURE__ */ jsxs("div", {
@@ -19601,6 +19624,21 @@ function MediaLibrary({ items = [], isLoading, onUpload, onDelete, onItemUpdated
19601
19624
  })]
19602
19625
  })
19603
19626
  }),
19627
+ activeProvider === "local" && hasMore && onLoadMore && /* @__PURE__ */ jsx("div", {
19628
+ className: "flex justify-center",
19629
+ children: /* @__PURE__ */ jsx(Button, {
19630
+ variant: "outline",
19631
+ onClick: onLoadMore,
19632
+ disabled: isLoading,
19633
+ children: isLoading ? _t({
19634
+ id: "Z3FXyt",
19635
+ message: "Loading..."
19636
+ }) : _t({
19637
+ id: "a4N/Bg",
19638
+ message: "Load More"
19639
+ })
19640
+ })
19641
+ }),
19604
19642
  selectedItem && /* @__PURE__ */ jsx(MediaDetailPanel, {
19605
19643
  item: selectedItem,
19606
19644
  onClose: () => setSelectedItem(null),
@@ -24556,15 +24594,25 @@ function GeneralSettings() {
24556
24594
  /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Label, { children: _t({
24557
24595
  id: "iG7KNr",
24558
24596
  message: "Logo"
24559
- }) }), formData.logo?.url ? /* @__PURE__ */ jsxs("div", {
24597
+ }) }), formData.logo?.mediaId ? /* @__PURE__ */ jsxs("div", {
24560
24598
  className: "mt-2 space-y-2",
24561
- children: [/* @__PURE__ */ jsx("img", {
24599
+ children: [formData.logo.url ? /* @__PURE__ */ jsx("img", {
24562
24600
  src: formData.logo.url,
24563
24601
  alt: formData.logo.alt || _t({
24564
24602
  id: "iG7KNr",
24565
24603
  message: "Logo"
24566
24604
  }),
24567
24605
  className: "h-16 rounded border bg-kumo-tint object-contain p-2"
24606
+ }) : /* @__PURE__ */ jsxs("div", {
24607
+ className: "flex min-h-16 items-center gap-2 rounded border border-dashed bg-kumo-tint px-3 py-2 text-sm text-kumo-subtle",
24608
+ role: "status",
24609
+ children: [/* @__PURE__ */ jsx(WarningCircle, {
24610
+ className: "h-4 w-4 flex-shrink-0",
24611
+ "aria-hidden": "true"
24612
+ }), /* @__PURE__ */ jsx("span", { children: _t({
24613
+ id: "Ja5IhY",
24614
+ message: "The referenced logo is no longer available. Pick a new one or remove the reference."
24615
+ }) })]
24568
24616
  }), /* @__PURE__ */ jsxs("div", {
24569
24617
  className: "flex gap-2",
24570
24618
  children: [/* @__PURE__ */ jsx(Button, {
@@ -24603,15 +24651,25 @@ function GeneralSettings() {
24603
24651
  /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Label, { children: _t({
24604
24652
  id: "+Qaboy",
24605
24653
  message: "Favicon"
24606
- }) }), formData.favicon?.url ? /* @__PURE__ */ jsxs("div", {
24654
+ }) }), formData.favicon?.mediaId ? /* @__PURE__ */ jsxs("div", {
24607
24655
  className: "mt-2 space-y-2",
24608
- children: [/* @__PURE__ */ jsx("img", {
24656
+ children: [formData.favicon.url ? /* @__PURE__ */ jsx("img", {
24609
24657
  src: formData.favicon.url,
24610
24658
  alt: _t({
24611
24659
  id: "+Qaboy",
24612
24660
  message: "Favicon"
24613
24661
  }),
24614
24662
  className: "h-8 w-8 rounded border bg-kumo-tint object-contain p-1"
24663
+ }) : /* @__PURE__ */ jsxs("div", {
24664
+ className: "flex min-h-8 items-center gap-2 rounded border border-dashed bg-kumo-tint px-2 py-1 text-xs text-kumo-subtle",
24665
+ role: "status",
24666
+ children: [/* @__PURE__ */ jsx(WarningCircle, {
24667
+ className: "h-3 w-3 flex-shrink-0",
24668
+ "aria-hidden": "true"
24669
+ }), /* @__PURE__ */ jsx("span", { children: _t({
24670
+ id: "z58F7a",
24671
+ message: "Referenced favicon unavailable."
24672
+ }) })]
24615
24673
  }), /* @__PURE__ */ jsxs("div", {
24616
24674
  className: "flex gap-2",
24617
24675
  children: [/* @__PURE__ */ jsx(Button, {
@@ -24722,6 +24780,7 @@ function GeneralSettings() {
24722
24780
  onOpenChange: setLogoPickerOpen,
24723
24781
  onSelect: handleLogoSelect,
24724
24782
  mimeTypeFilter: "image/",
24783
+ localOnly: true,
24725
24784
  title: _t({
24726
24785
  id: "JUZ3aC",
24727
24786
  message: "Select Logo"
@@ -24732,6 +24791,7 @@ function GeneralSettings() {
24732
24791
  onOpenChange: setFaviconPickerOpen,
24733
24792
  onSelect: handleFaviconSelect,
24734
24793
  mimeTypeFilter: "image/",
24794
+ localOnly: true,
24735
24795
  title: _t({
24736
24796
  id: "LmzxcB",
24737
24797
  message: "Select Favicon"
@@ -25237,6 +25297,7 @@ function SeoSettings() {
25237
25297
  });
25238
25298
  const [formData, setFormData] = React$1.useState({});
25239
25299
  const [saveStatus, setSaveStatus] = React$1.useState(null);
25300
+ const [ogImagePickerOpen, setOgImagePickerOpen] = React$1.useState(false);
25240
25301
  React$1.useEffect(() => {
25241
25302
  if (settings) setFormData(settings);
25242
25303
  }, [settings]);
@@ -25281,6 +25342,29 @@ function SeoSettings() {
25281
25342
  }
25282
25343
  }));
25283
25344
  };
25345
+ const handleDefaultOgImageSelect = (media) => {
25346
+ setFormData((prev) => ({
25347
+ ...prev,
25348
+ seo: {
25349
+ ...prev.seo,
25350
+ defaultOgImage: {
25351
+ mediaId: media.id,
25352
+ alt: media.alt || "",
25353
+ url: media.url
25354
+ }
25355
+ }
25356
+ }));
25357
+ setOgImagePickerOpen(false);
25358
+ };
25359
+ const handleDefaultOgImageRemove = () => {
25360
+ setFormData((prev) => ({
25361
+ ...prev,
25362
+ seo: {
25363
+ ...prev.seo,
25364
+ defaultOgImage: void 0
25365
+ }
25366
+ }));
25367
+ };
25284
25368
  if (isLoading) return /* @__PURE__ */ jsxs("div", {
25285
25369
  className: "space-y-6",
25286
25370
  children: [/* @__PURE__ */ jsxs("div", {
@@ -25363,6 +25447,73 @@ function SeoSettings() {
25363
25447
  message: "Character between page title and site name (e.g., \"My Post | My Site\")"
25364
25448
  })
25365
25449
  }),
25450
+ /* @__PURE__ */ jsxs("div", { children: [
25451
+ /* @__PURE__ */ jsx(Label, { children: _t({
25452
+ id: "rqCo6p",
25453
+ message: "Default Social Image"
25454
+ }) }),
25455
+ /* @__PURE__ */ jsx("p", {
25456
+ className: "mt-1 text-sm text-kumo-subtle",
25457
+ children: _t({
25458
+ id: "YkLTCK",
25459
+ message: "Used as the fallback Open Graph image when a page has none. Recommended size: 1200×630."
25460
+ })
25461
+ }),
25462
+ formData.seo?.defaultOgImage?.mediaId ? /* @__PURE__ */ jsxs("div", {
25463
+ className: "mt-2 space-y-2",
25464
+ children: [formData.seo.defaultOgImage.url ? /* @__PURE__ */ jsx("img", {
25465
+ src: formData.seo.defaultOgImage.url,
25466
+ alt: formData.seo.defaultOgImage.alt || _t({
25467
+ id: "GOoV+w",
25468
+ message: "Default social image"
25469
+ }),
25470
+ className: "h-32 rounded border bg-kumo-tint object-contain p-2"
25471
+ }) : /* @__PURE__ */ jsxs("div", {
25472
+ className: "flex min-h-32 items-center gap-2 rounded border border-dashed bg-kumo-tint px-3 py-2 text-sm text-kumo-subtle",
25473
+ role: "status",
25474
+ children: [/* @__PURE__ */ jsx(WarningCircle, {
25475
+ className: "h-4 w-4 flex-shrink-0",
25476
+ "aria-hidden": "true"
25477
+ }), /* @__PURE__ */ jsx("span", { children: _t({
25478
+ id: "xPSZCT",
25479
+ message: "The referenced image is no longer available. Pick a new one or remove the reference."
25480
+ }) })]
25481
+ }), /* @__PURE__ */ jsxs("div", {
25482
+ className: "flex gap-2",
25483
+ children: [/* @__PURE__ */ jsx(Button, {
25484
+ type: "button",
25485
+ variant: "outline",
25486
+ size: "sm",
25487
+ icon: /* @__PURE__ */ jsx(Upload, {}),
25488
+ onClick: () => setOgImagePickerOpen(true),
25489
+ children: _t({
25490
+ id: "mwX/w0",
25491
+ message: "Change Image"
25492
+ })
25493
+ }), /* @__PURE__ */ jsx(Button, {
25494
+ type: "button",
25495
+ variant: "outline",
25496
+ size: "sm",
25497
+ icon: /* @__PURE__ */ jsx(X, {}),
25498
+ onClick: handleDefaultOgImageRemove,
25499
+ children: _t({
25500
+ id: "t/YqKh",
25501
+ message: "Remove"
25502
+ })
25503
+ })]
25504
+ })]
25505
+ }) : /* @__PURE__ */ jsx(Button, {
25506
+ type: "button",
25507
+ variant: "outline",
25508
+ icon: /* @__PURE__ */ jsx(Upload, {}),
25509
+ onClick: () => setOgImagePickerOpen(true),
25510
+ className: "mt-2",
25511
+ children: _t({
25512
+ id: "bAiEJP",
25513
+ message: "Select Image"
25514
+ })
25515
+ })
25516
+ ] }),
25366
25517
  /* @__PURE__ */ jsx(Input, {
25367
25518
  label: _t({
25368
25519
  id: "uP6I1q",
@@ -25414,6 +25565,22 @@ function SeoSettings() {
25414
25565
  })
25415
25566
  })
25416
25567
  })]
25568
+ }),
25569
+ /* @__PURE__ */ jsx(MediaPickerModal, {
25570
+ open: ogImagePickerOpen,
25571
+ onOpenChange: setOgImagePickerOpen,
25572
+ onSelect: handleDefaultOgImageSelect,
25573
+ mimeTypeFilters: [
25574
+ "image/jpeg",
25575
+ "image/png",
25576
+ "image/webp",
25577
+ "image/gif"
25578
+ ],
25579
+ localOnly: true,
25580
+ title: _t({
25581
+ id: "lxsmBp",
25582
+ message: "Select Default Social Image"
25583
+ })
25417
25584
  })
25418
25585
  ]
25419
25586
  });
@@ -35460,9 +35627,14 @@ const mediaRoute = createRoute({
35460
35627
  });
35461
35628
  function MediaPage() {
35462
35629
  const queryClient = useQueryClient();
35463
- const { data, isLoading, error } = useQuery({
35630
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, error } = useInfiniteQuery({
35464
35631
  queryKey: ["media"],
35465
- queryFn: () => fetchMediaList()
35632
+ queryFn: ({ pageParam }) => fetchMediaList({
35633
+ cursor: pageParam,
35634
+ limit: 100
35635
+ }),
35636
+ initialPageParam: void 0,
35637
+ getNextPageParam: (lastPage) => lastPage.nextCursor
35466
35638
  });
35467
35639
  const uploadMutation = useMutation({
35468
35640
  mutationFn: (file) => uploadMedia(file),
@@ -35476,10 +35648,15 @@ function MediaPage() {
35476
35648
  queryClient.invalidateQueries({ queryKey: ["media"] });
35477
35649
  }
35478
35650
  });
35651
+ const items = React$1.useMemo(() => {
35652
+ return data?.pages.flatMap((page) => page.items) || [];
35653
+ }, [data]);
35479
35654
  if (error) return /* @__PURE__ */ jsx(ErrorScreen, { error: error.message });
35480
35655
  return /* @__PURE__ */ jsx(MediaLibrary, {
35481
- items: data?.items || [],
35482
- isLoading,
35656
+ items,
35657
+ isLoading: isLoading || isFetchingNextPage,
35658
+ hasMore: !!hasNextPage,
35659
+ onLoadMore: () => void fetchNextPage(),
35483
35660
  onUpload: (file) => uploadMutation.mutate(file),
35484
35661
  onDelete: (id) => deleteMutation.mutate(id)
35485
35662
  });