@emdash-cms/admin 0.28.0 → 0.29.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 (119) hide show
  1. package/dist/{LocaleDirectionProvider-C9lpIjJq.js → LocaleDirectionProvider-BChkadr-.js} +23 -23
  2. package/dist/{LocaleDirectionProvider-C9lpIjJq.js.map → LocaleDirectionProvider-BChkadr-.js.map} +1 -1
  3. package/dist/index.d.ts +16 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +738 -294
  6. package/dist/index.js.map +1 -1
  7. package/dist/locales/ar/messages.mjs +1 -1
  8. package/dist/locales/ca/messages.mjs +1 -1
  9. package/dist/locales/de/messages.mjs +1 -1
  10. package/dist/locales/en/messages.mjs +1 -1
  11. package/dist/locales/en-GB/messages.mjs +1 -1
  12. package/dist/locales/es-419/messages.mjs +1 -1
  13. package/dist/locales/es-ES/messages.mjs +1 -1
  14. package/dist/locales/eu/messages.mjs +1 -1
  15. package/dist/locales/fa/messages.mjs +1 -1
  16. package/dist/locales/fr/messages.mjs +1 -1
  17. package/dist/locales/hu/messages.mjs +1 -1
  18. package/dist/locales/id/messages.mjs +1 -1
  19. package/dist/locales/index.js +1 -1
  20. package/dist/locales/ja/messages.mjs +1 -1
  21. package/dist/locales/ko/messages.mjs +1 -1
  22. package/dist/locales/nb/messages.mjs +1 -1
  23. package/dist/locales/pl/messages.mjs +1 -1
  24. package/dist/locales/pseudo/messages.mjs +1 -1
  25. package/dist/locales/pt-BR/messages.mjs +1 -1
  26. package/dist/locales/th/messages.mjs +1 -1
  27. package/dist/locales/tr/messages.mjs +1 -1
  28. package/dist/locales/zh-CN/messages.mjs +1 -1
  29. package/dist/locales/zh-TW/messages.mjs +1 -1
  30. package/dist/messages-B4BHvrsT.js +6 -0
  31. package/dist/messages-B4BHvrsT.js.map +1 -0
  32. package/dist/messages-B4juPtn9.js +6 -0
  33. package/dist/messages-B4juPtn9.js.map +1 -0
  34. package/dist/messages-BDE2DX8G.js +6 -0
  35. package/dist/messages-BDE2DX8G.js.map +1 -0
  36. package/dist/messages-BGPUdzH4.js +6 -0
  37. package/dist/messages-BGPUdzH4.js.map +1 -0
  38. package/dist/messages-BTBS_y80.js +6 -0
  39. package/dist/messages-BTBS_y80.js.map +1 -0
  40. package/dist/messages-BZoGFJCR.js +6 -0
  41. package/dist/messages-BZoGFJCR.js.map +1 -0
  42. package/dist/messages-BZtW7iEb.js +6 -0
  43. package/dist/messages-BZtW7iEb.js.map +1 -0
  44. package/dist/messages-C1T5tVuG.js +6 -0
  45. package/dist/messages-C1T5tVuG.js.map +1 -0
  46. package/dist/messages-C2T5TtJs.js +6 -0
  47. package/dist/messages-C2T5TtJs.js.map +1 -0
  48. package/dist/messages-CT-Qd0ZJ.js +6 -0
  49. package/dist/messages-CT-Qd0ZJ.js.map +1 -0
  50. package/dist/messages-CZPLfRYr.js +6 -0
  51. package/dist/messages-CZPLfRYr.js.map +1 -0
  52. package/dist/messages-CeMAXloc.js +6 -0
  53. package/dist/messages-CeMAXloc.js.map +1 -0
  54. package/dist/messages-CyEZuSL3.js +6 -0
  55. package/dist/messages-CyEZuSL3.js.map +1 -0
  56. package/dist/messages-D2YcmfWc.js +6 -0
  57. package/dist/messages-D2YcmfWc.js.map +1 -0
  58. package/dist/messages-D31PGWI9.js +6 -0
  59. package/dist/messages-D31PGWI9.js.map +1 -0
  60. package/dist/messages-D6QU1alD.js +6 -0
  61. package/dist/messages-D6QU1alD.js.map +1 -0
  62. package/dist/messages-DHMviva4.js +6 -0
  63. package/dist/messages-DHMviva4.js.map +1 -0
  64. package/dist/messages-DXVNuRej.js +6 -0
  65. package/dist/messages-DXVNuRej.js.map +1 -0
  66. package/dist/messages-DnSF6k-0.js +6 -0
  67. package/dist/messages-DnSF6k-0.js.map +1 -0
  68. package/dist/messages-S2yvER7u.js +6 -0
  69. package/dist/messages-S2yvER7u.js.map +1 -0
  70. package/dist/messages-_Syx7u6a.js +6 -0
  71. package/dist/messages-_Syx7u6a.js.map +1 -0
  72. package/dist/messages-a7P1Z1CV.js +6 -0
  73. package/dist/messages-a7P1Z1CV.js.map +1 -0
  74. package/dist/styles.css +1 -1
  75. package/package.json +5 -5
  76. package/dist/messages-6fY68LcP.js +0 -6
  77. package/dist/messages-6fY68LcP.js.map +0 -1
  78. package/dist/messages-6lTdmQGb.js +0 -6
  79. package/dist/messages-6lTdmQGb.js.map +0 -1
  80. package/dist/messages-AMpyLsVV.js +0 -6
  81. package/dist/messages-AMpyLsVV.js.map +0 -1
  82. package/dist/messages-B3sCXNcK.js +0 -6
  83. package/dist/messages-B3sCXNcK.js.map +0 -1
  84. package/dist/messages-BAyngJJl.js +0 -6
  85. package/dist/messages-BAyngJJl.js.map +0 -1
  86. package/dist/messages-BQZTS0MM.js +0 -6
  87. package/dist/messages-BQZTS0MM.js.map +0 -1
  88. package/dist/messages-BV9Wj2_G.js +0 -6
  89. package/dist/messages-BV9Wj2_G.js.map +0 -1
  90. package/dist/messages-CRMEv0fl.js +0 -6
  91. package/dist/messages-CRMEv0fl.js.map +0 -1
  92. package/dist/messages-CT15OURU.js +0 -6
  93. package/dist/messages-CT15OURU.js.map +0 -1
  94. package/dist/messages-CUCFPFJ3.js +0 -6
  95. package/dist/messages-CUCFPFJ3.js.map +0 -1
  96. package/dist/messages-CavWWCi3.js +0 -6
  97. package/dist/messages-CavWWCi3.js.map +0 -1
  98. package/dist/messages-CoBqWHqG.js +0 -6
  99. package/dist/messages-CoBqWHqG.js.map +0 -1
  100. package/dist/messages-D2o12uTm.js +0 -6
  101. package/dist/messages-D2o12uTm.js.map +0 -1
  102. package/dist/messages-D3pkHI7F.js +0 -6
  103. package/dist/messages-D3pkHI7F.js.map +0 -1
  104. package/dist/messages-D5PMXXV7.js +0 -6
  105. package/dist/messages-D5PMXXV7.js.map +0 -1
  106. package/dist/messages-D8FYHPeJ.js +0 -6
  107. package/dist/messages-D8FYHPeJ.js.map +0 -1
  108. package/dist/messages-D8kZj9qx.js +0 -6
  109. package/dist/messages-D8kZj9qx.js.map +0 -1
  110. package/dist/messages-I4Ix7mrr.js +0 -6
  111. package/dist/messages-I4Ix7mrr.js.map +0 -1
  112. package/dist/messages-LzxSk1w_.js +0 -6
  113. package/dist/messages-LzxSk1w_.js.map +0 -1
  114. package/dist/messages-YG3baZDu.js +0 -6
  115. package/dist/messages-YG3baZDu.js.map +0 -1
  116. package/dist/messages-maew9CuC.js +0 -6
  117. package/dist/messages-maew9CuC.js.map +0 -1
  118. package/dist/messages-ygue5BY_.js +0 -6
  119. package/dist/messages-ygue5BY_.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
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-G9Z9NQ7n.js";
2
- import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, s as getLocaleDir, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-C9lpIjJq.js";
2
+ import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, s as getLocaleDir, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-BChkadr-.js";
3
3
  import "./locales/index.js";
4
- import { Autocomplete, Badge, Button, Checkbox, ClipboardText, Combobox, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, LinkProvider, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useKumoToastManager, useSidebar } from "@cloudflare/kumo";
4
+ import { Autocomplete, Badge, Banner, Button, Checkbox, ClipboardText, Combobox, CommandPalette, Dialog, Input, InputArea, Label, LayerCard, LinkButton, LinkProvider, Loader, Popover, Select, Sidebar as KumoSidebar, SkeletonLine, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useKumoToastManager, useSidebar } from "@cloudflare/kumo";
5
5
  import { i18n } from "@lingui/core";
6
6
  import { I18nProvider, Trans, useLingui } from "@lingui/react";
7
7
  import { QueryClient, QueryClientProvider, keepPreviousData, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -10,7 +10,7 @@ import * as React$1 from "react";
10
10
  import React, { 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, ArrowDown, ArrowRight, ArrowRightIcon, ArrowSquareOut, ArrowUUpLeft, ArrowUUpRight, ArrowUp, ArrowsClockwise, ArrowsInSimple, ArrowsLeftRight, ArrowsOutSimple, Bell, BookOpen, BracketsAngle, BracketsCurly, Calendar, CalendarBlank, CaretDown, CaretRightIcon, CaretUp, CaretUpDown, ChartBar, ChartLine, ChatCircle, Check, CheckCircle, CircleDashed, CircleNotch, ClockCounterClockwise, Cloud, Code, CodeBlock, Columns, Copy, Crop, Cube, Database, DeviceMobile, DotsSixVertical, DownloadSimple, Envelope, EnvelopeSimple, Eye, EyeSlash, File, FileArrowDown, FileText, FloppyDisk, Folder, FolderOpen, Gear, GithubLogo, Globe, GlobeSimple, GridFour, HardDrive, Hash, IdentificationCard, Image as Image$1, ImageBroken, ImageSquare, Images, Info, Key, Link as Link$2, LinkBreak, LinkSimple, List, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Medal, Minus, Monitor, Moon, Palette, PaperPlaneTilt, Paperclip, Paragraph, Pencil, PencilSimple, Plug, PlugsConnected, Plus, Prohibit, PuzzlePiece, Quotes, Rows, Ruler, ShareNetwork, Shield, ShieldCheck, ShieldWarning, SignOut, SlidersHorizontal, Sparkle, SquaresFour, Stack, Star, Storefront, Sun, Table, Tag, TextAlignCenter, TextAlignLeft, TextAlignRight, TextB, TextHOne, TextHThree, TextHTwo, TextItalic, TextStrikethrough, TextT, TextUnderline, ToggleLeft, Trash, Trophy, Upload, User, UserCircle, UserPlus, Users, Warning, WarningCircle, WebhooksLogo, X, YoutubeLogo } from "@phosphor-icons/react";
13
+ import { ArrowCounterClockwise, ArrowDown, ArrowRightIcon, ArrowSquareOut, ArrowUUpLeft, ArrowUUpRight, ArrowUp, ArrowsClockwise, ArrowsInSimple, ArrowsLeftRight, ArrowsOutSimple, Bell, BookOpen, BracketsAngle, BracketsCurly, Calendar, CalendarBlank, CaretDown, CaretRightIcon, CaretUp, CaretUpDown, ChartBar, ChartLine, ChatCircle, Check, CheckCircle, CircleDashed, CircleNotch, ClockCounterClockwise, Cloud, Code, CodeBlock, Columns, Copy, Crop, Cube, Database, DeviceMobile, DotsSixVertical, DownloadSimple, Envelope, EnvelopeSimple, Eye, EyeSlash, File, FileArrowDown, FileText, FloppyDisk, Folder, FolderOpen, Gear, GithubLogo, Globe, GlobeSimple, GridFour, HardDrive, Hash, IdentificationCard, Image as Image$1, ImageBroken, ImageSquare, Images, Info, Key, Link as Link$2, LinkBreak, LinkSimple, List, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Medal, Minus, Monitor, Moon, Palette, PaperPlaneTilt, Paperclip, Paragraph, Pencil, PencilSimple, Plug, PlugsConnected, Plus, Prohibit, PuzzlePiece, Quotes, Rows, Ruler, ShareNetwork, Shield, ShieldCheck, ShieldWarning, SignOut, SlidersHorizontal, Sparkle, SquaresFour, Stack, Star, Storefront, Sun, Table, Tag, TextAlignCenter, TextAlignLeft, TextAlignRight, TextB, TextHOne, TextHThree, TextHTwo, TextItalic, TextStrikethrough, TextT, TextUnderline, ToggleLeft, Trash, Trophy, 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";
@@ -608,8 +608,13 @@ function CommentStatusBadge({ status }) {
608
608
  message: "trash"
609
609
  })
610
610
  };
611
- return /* @__PURE__ */ jsx("span", {
612
- className: cn("inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium", status === "approved" && "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200", status === "pending" && "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200", status === "spam" && "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200", status === "trash" && "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200"),
611
+ return /* @__PURE__ */ jsx(Badge, {
612
+ variant: {
613
+ approved: "success",
614
+ pending: "warning",
615
+ spam: "error",
616
+ trash: "neutral"
617
+ }[status],
613
618
  children: labels[status]
614
619
  });
615
620
  }
@@ -1096,7 +1101,7 @@ function CommentRow({ comment, isSelected, onToggle, onRowClick, onStatusChange,
1096
1101
  }),
1097
1102
  onClick: () => onStatusChange(comment.id, "approved"),
1098
1103
  disabled: isStatusPending,
1099
- children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-green-600" })
1104
+ children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-kumo-success" })
1100
1105
  }),
1101
1106
  comment.status !== "spam" && /* @__PURE__ */ jsx(Button, {
1102
1107
  variant: "ghost",
@@ -1108,7 +1113,7 @@ function CommentRow({ comment, isSelected, onToggle, onRowClick, onStatusChange,
1108
1113
  }),
1109
1114
  onClick: () => onStatusChange(comment.id, "spam"),
1110
1115
  disabled: isStatusPending,
1111
- children: /* @__PURE__ */ jsx(Warning, { className: "h-4 w-4 text-orange-500" })
1116
+ children: /* @__PURE__ */ jsx(Warning, { className: "h-4 w-4 text-kumo-warning" })
1112
1117
  }),
1113
1118
  comment.status !== "trash" && /* @__PURE__ */ jsx(Button, {
1114
1119
  variant: "ghost",
@@ -3002,6 +3007,10 @@ const CAPABILITY_LABELS = {
3002
3007
  id: "cibvDN",
3003
3008
  message: "Create, update, and delete content"
3004
3009
  },
3010
+ "taxonomies:read": {
3011
+ id: "qLgcL9",
3012
+ message: "Read your taxonomies and terms"
3013
+ },
3005
3014
  "media:read": {
3006
3015
  id: "Le+rBu",
3007
3016
  message: "Access your media library"
@@ -13671,11 +13680,13 @@ function getItemTitle$1(item) {
13671
13680
  /**
13672
13681
  * Content list view with table display and trash tab
13673
13682
  */
13674
- function ContentList({ collection, collectionLabel, items, trashedItems = [], isLoading, isTrashedLoading, onDelete, onDuplicate, onRestore, onPermanentDelete, onLoadMore, onLoadMoreTrashed, hasMore, hasMoreTrashed, trashedCount = 0, i18n, activeLocale, onLocaleChange, urlPattern, sort, onSortChange, total, onSearchChange, statusFilter = "all", onStatusFilterChange, authors, authorFilter = "", onAuthorFilterChange, dateFilter = EMPTY_DATE_FILTER, onDateFilterChange }) {
13683
+ function ContentList({ collection, collectionLabel, items, trashedItems = [], isLoading, isTrashedLoading, onDelete, onDuplicate, onRestore, onPermanentDelete, onLoadMore, onLoadMoreTrashed, hasMore, hasMoreTrashed, trashedCount = 0, i18n: i18n$2, activeLocale, onLocaleChange, urlPattern, sort, onSortChange, total, onSearchChange, statusFilter = "all", onStatusFilterChange, authors, authorFilter = "", onAuthorFilterChange, dateFilter = EMPTY_DATE_FILTER, onDateFilterChange, onBulkPublish, onBulkUnpublish, onBulkDelete }) {
13675
13684
  const { _: _t } = useLingui();
13676
13685
  const [activeTab, setActiveTab] = React$1.useState("all");
13677
13686
  const [searchQuery, setSearchQuery] = React$1.useState("");
13678
13687
  const [page, setPage] = React$1.useState(0);
13688
+ const [selectedIds, setSelectedIds] = React$1.useState(() => /* @__PURE__ */ new Set());
13689
+ const bulkEnabled = !!(onBulkPublish || onBulkUnpublish || onBulkDelete);
13679
13690
  const serverSearch = !!onSearchChange;
13680
13691
  const debouncedSearch = useDebouncedValue$1(searchQuery, 300);
13681
13692
  React$1.useEffect(() => {
@@ -13710,6 +13721,48 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13710
13721
  searchQuery,
13711
13722
  serverSearch
13712
13723
  ]);
13724
+ React$1.useEffect(() => {
13725
+ setSelectedIds((prev) => {
13726
+ if (prev.size === 0) return prev;
13727
+ const present = new Set(items.map((i) => i.id));
13728
+ let changed = false;
13729
+ const next = /* @__PURE__ */ new Set();
13730
+ for (const id of prev) if (present.has(id)) next.add(id);
13731
+ else changed = true;
13732
+ return changed ? next : prev;
13733
+ });
13734
+ }, [items]);
13735
+ const clearSelection = React$1.useCallback(() => setSelectedIds(/* @__PURE__ */ new Set()), []);
13736
+ const toggleOne = (id) => setSelectedIds((prev) => {
13737
+ const next = new Set(prev);
13738
+ if (next.has(id)) next.delete(id);
13739
+ else next.add(id);
13740
+ return next;
13741
+ });
13742
+ const pageIds = paginatedItems.map((i) => i.id);
13743
+ const allPageSelected = pageIds.length > 0 && pageIds.every((id) => selectedIds.has(id));
13744
+ const togglePage = () => setSelectedIds((prev) => {
13745
+ const next = new Set(prev);
13746
+ if (allPageSelected) for (const id of pageIds) next.delete(id);
13747
+ else for (const id of pageIds) next.add(id);
13748
+ return next;
13749
+ });
13750
+ const selectedCount = selectedIds.size;
13751
+ const [bulkBusy, setBulkBusy] = React$1.useState(false);
13752
+ const runBulk = (fn) => {
13753
+ if (!fn || selectedCount === 0 || bulkBusy) return;
13754
+ const ids = [...selectedIds];
13755
+ setBulkBusy(true);
13756
+ (async () => {
13757
+ try {
13758
+ const failedIds = await fn(ids);
13759
+ setSelectedIds(new Set(failedIds));
13760
+ } catch {} finally {
13761
+ setBulkBusy(false);
13762
+ }
13763
+ })();
13764
+ };
13765
+ const colSpan = (i18n$2 ? 5 : 4) + (bulkEnabled ? 1 : 0);
13713
13766
  return /* @__PURE__ */ jsxs("div", {
13714
13767
  className: "space-y-4",
13715
13768
  children: [
@@ -13720,9 +13773,9 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13720
13773
  children: [/* @__PURE__ */ jsx("h1", {
13721
13774
  className: "text-2xl font-bold",
13722
13775
  children: collectionLabel
13723
- }), i18n && activeLocale && onLocaleChange && /* @__PURE__ */ jsx(LocaleSwitcher, {
13724
- locales: i18n.locales,
13725
- defaultLocale: i18n.defaultLocale,
13776
+ }), i18n$2 && activeLocale && onLocaleChange && /* @__PURE__ */ jsx(LocaleSwitcher, {
13777
+ locales: i18n$2.locales,
13778
+ defaultLocale: i18n$2.defaultLocale,
13726
13779
  value: activeLocale,
13727
13780
  onChange: onLocaleChange,
13728
13781
  size: "sm"
@@ -13800,6 +13853,109 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13800
13853
  dateFilter,
13801
13854
  onDateFilterChange
13802
13855
  }),
13856
+ bulkEnabled && selectedCount > 0 && /* @__PURE__ */ jsxs("div", {
13857
+ className: "flex flex-wrap items-center gap-3 rounded-md border bg-kumo-tint/40 px-4 py-2",
13858
+ children: [/* @__PURE__ */ jsx("span", {
13859
+ className: "text-sm font-medium",
13860
+ children: bulkBusy ? _t({
13861
+ id: "JKl1C3",
13862
+ message: "Working on {selectedCount} items…",
13863
+ values: { selectedCount }
13864
+ }) : i18n._({
13865
+ id: "6XtCKk",
13866
+ message: "{selectedCount, plural, one {# selected} other {# selected}}",
13867
+ values: { selectedCount }
13868
+ })
13869
+ }), /* @__PURE__ */ jsxs("div", {
13870
+ className: "flex flex-wrap items-center gap-2",
13871
+ children: [
13872
+ onBulkPublish && /* @__PURE__ */ jsx(Button, {
13873
+ size: "sm",
13874
+ variant: "secondary",
13875
+ disabled: bulkBusy,
13876
+ onClick: () => runBulk(onBulkPublish),
13877
+ children: _t({
13878
+ id: "EEYbdt",
13879
+ message: "Publish"
13880
+ })
13881
+ }),
13882
+ onBulkUnpublish && /* @__PURE__ */ jsx(Button, {
13883
+ size: "sm",
13884
+ variant: "secondary",
13885
+ disabled: bulkBusy,
13886
+ onClick: () => runBulk(onBulkUnpublish),
13887
+ children: _t({
13888
+ id: "aIk+8y",
13889
+ message: "Set to draft"
13890
+ })
13891
+ }),
13892
+ onBulkDelete && /* @__PURE__ */ jsxs(Dialog.Root, {
13893
+ disablePointerDismissal: true,
13894
+ children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (p) => /* @__PURE__ */ jsx(Button, {
13895
+ ...p,
13896
+ size: "sm",
13897
+ variant: "destructive",
13898
+ icon: /* @__PURE__ */ jsx(Trash, {}),
13899
+ disabled: bulkBusy,
13900
+ children: _t({
13901
+ id: "rRZjIm",
13902
+ message: "Move to trash"
13903
+ })
13904
+ }) }), /* @__PURE__ */ jsxs(Dialog, {
13905
+ className: "p-6",
13906
+ size: "sm",
13907
+ children: [
13908
+ /* @__PURE__ */ jsx(Dialog.Title, {
13909
+ className: "text-lg font-semibold",
13910
+ children: _t({
13911
+ id: "eAnjuA",
13912
+ message: "Move to Trash?"
13913
+ })
13914
+ }),
13915
+ /* @__PURE__ */ jsx(Dialog.Description, {
13916
+ className: "text-kumo-subtle",
13917
+ children: i18n._({
13918
+ id: "wzIy8K",
13919
+ message: "{selectedCount, plural, one {Move # item to trash? You can restore it later.} other {Move # items to trash? You can restore them later.}}",
13920
+ values: { selectedCount }
13921
+ })
13922
+ }),
13923
+ /* @__PURE__ */ jsxs("div", {
13924
+ className: "mt-6 flex justify-end gap-2",
13925
+ children: [/* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
13926
+ ...p,
13927
+ variant: "secondary",
13928
+ children: _t({
13929
+ id: "dEgA5A",
13930
+ message: "Cancel"
13931
+ })
13932
+ }) }), /* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
13933
+ ...p,
13934
+ variant: "destructive",
13935
+ onClick: () => runBulk(onBulkDelete),
13936
+ children: _t({
13937
+ id: "q3TWG7",
13938
+ message: "Move to Trash"
13939
+ })
13940
+ }) })]
13941
+ })
13942
+ ]
13943
+ })]
13944
+ }),
13945
+ /* @__PURE__ */ jsx(Button, {
13946
+ size: "sm",
13947
+ variant: "ghost",
13948
+ icon: /* @__PURE__ */ jsx(X, {}),
13949
+ disabled: bulkBusy,
13950
+ onClick: clearSelection,
13951
+ children: _t({
13952
+ id: "xCJdfg",
13953
+ message: "Clear"
13954
+ })
13955
+ })
13956
+ ]
13957
+ })]
13958
+ }),
13803
13959
  /* @__PURE__ */ jsx("div", {
13804
13960
  className: "rounded-md border bg-kumo-base overflow-x-auto",
13805
13961
  children: /* @__PURE__ */ jsxs("table", {
@@ -13807,6 +13963,18 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13807
13963
  children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", {
13808
13964
  className: "border-b bg-kumo-tint/50",
13809
13965
  children: [
13966
+ bulkEnabled && /* @__PURE__ */ jsx("th", {
13967
+ scope: "col",
13968
+ className: "w-10 px-4 py-3",
13969
+ children: /* @__PURE__ */ jsx(Checkbox, {
13970
+ checked: allPageSelected,
13971
+ onCheckedChange: togglePage,
13972
+ "aria-label": _t({
13973
+ id: "pV4KKD",
13974
+ message: "Select all on this page"
13975
+ })
13976
+ })
13977
+ }),
13810
13978
  /* @__PURE__ */ jsx(SortableTh, {
13811
13979
  field: "title",
13812
13980
  sort,
@@ -13825,7 +13993,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13825
13993
  message: "Status"
13826
13994
  })
13827
13995
  }),
13828
- i18n && /* @__PURE__ */ jsx(SortableTh, {
13996
+ i18n$2 && /* @__PURE__ */ jsx(SortableTh, {
13829
13997
  field: "locale",
13830
13998
  sort,
13831
13999
  onSortChange,
@@ -13855,7 +14023,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13855
14023
  }) }), /* @__PURE__ */ jsx("tbody", {
13856
14024
  className: "divide-y divide-kumo-line",
13857
14025
  children: isLoading && items.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
13858
- colSpan: i18n ? 5 : 4,
14026
+ colSpan,
13859
14027
  className: "px-4 py-8 text-center text-kumo-subtle",
13860
14028
  children: /* @__PURE__ */ jsxs("span", {
13861
14029
  className: "inline-flex items-center gap-2",
@@ -13865,7 +14033,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13865
14033
  })]
13866
14034
  })
13867
14035
  }) }) : items.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
13868
- colSpan: i18n ? 5 : 4,
14036
+ colSpan,
13869
14037
  className: "px-4 py-8 text-center text-kumo-subtle",
13870
14038
  children: activeSearch ? _t({
13871
14039
  id: "QpOp1w",
@@ -13890,7 +14058,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13890
14058
  })
13891
14059
  ] })
13892
14060
  }) }) : paginatedItems.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
13893
- colSpan: i18n ? 5 : 4,
14061
+ colSpan,
13894
14062
  className: "px-4 py-8 text-center text-kumo-subtle",
13895
14063
  children: _t({
13896
14064
  id: "QpOp1w",
@@ -13902,8 +14070,11 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
13902
14070
  collection,
13903
14071
  onDelete,
13904
14072
  onDuplicate,
13905
- showLocale: !!i18n,
13906
- urlPattern
14073
+ showLocale: !!i18n$2,
14074
+ urlPattern,
14075
+ selectable: bulkEnabled,
14076
+ selected: selectedIds.has(item.id),
14077
+ onToggleSelect: toggleOne
13907
14078
  }, item.id))
13908
14079
  })]
13909
14080
  })
@@ -14300,13 +14471,25 @@ function renderItemCount({ searchQuery, filteredCount, total, hasMore, serverSea
14300
14471
  }
14301
14472
  });
14302
14473
  }
14303
- function ContentListItem({ item, collection, onDelete, onDuplicate, showLocale, urlPattern }) {
14474
+ function ContentListItem({ item, collection, onDelete, onDuplicate, showLocale, urlPattern, selectable, selected, onToggleSelect }) {
14304
14475
  const { _: _t3 } = useLingui();
14305
14476
  const title = getItemTitle$1(item);
14306
14477
  const date = new Date(item.updatedAt || item.createdAt);
14307
14478
  return /* @__PURE__ */ jsxs("tr", {
14308
- className: "hover:bg-kumo-tint/25",
14479
+ className: cn("hover:bg-kumo-tint/25", selected && "bg-kumo-tint/40"),
14309
14480
  children: [
14481
+ selectable && /* @__PURE__ */ jsx("td", {
14482
+ className: "px-4 py-3",
14483
+ children: /* @__PURE__ */ jsx(Checkbox, {
14484
+ checked: !!selected,
14485
+ onCheckedChange: () => onToggleSelect?.(item.id),
14486
+ "aria-label": _t3({
14487
+ id: "135JuL",
14488
+ message: "Select {title}",
14489
+ values: { title }
14490
+ })
14491
+ })
14492
+ }),
14310
14493
  /* @__PURE__ */ jsx("td", {
14311
14494
  className: "px-4 py-3",
14312
14495
  children: /* @__PURE__ */ jsx(Link$1, {
@@ -15876,7 +16059,7 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
15876
16059
  className: "bg-kumo-tint px-1.5 py-0.5 rounded",
15877
16060
  children: collection?.slug
15878
16061
  }), isFromCode && /* @__PURE__ */ jsx("span", {
15879
- className: "ms-2 text-purple-600 dark:text-purple-400",
16062
+ className: "ms-2 text-kumo-info",
15880
16063
  children: _t({
15881
16064
  id: "7tGkih",
15882
16065
  message: "Defined in code"
@@ -15885,11 +16068,11 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
15885
16068
  })]
15886
16069
  }),
15887
16070
  isFromCode && /* @__PURE__ */ jsx("div", {
15888
- className: "rounded-lg border border-purple-200 dark:border-purple-800 bg-purple-50 dark:bg-purple-950 p-4",
16071
+ className: "rounded-lg border border-kumo-info/50 bg-kumo-info-tint p-4",
15889
16072
  children: /* @__PURE__ */ jsxs("div", {
15890
16073
  className: "flex items-center space-x-2",
15891
- children: [/* @__PURE__ */ jsx(FileText, { className: "h-5 w-5 text-purple-600 dark:text-purple-400" }), /* @__PURE__ */ jsx("p", {
15892
- className: "text-sm text-purple-700 dark:text-purple-300",
16074
+ children: [/* @__PURE__ */ jsx(FileText, { className: "h-5 w-5 text-kumo-info" }), /* @__PURE__ */ jsx("p", {
16075
+ className: "text-sm text-kumo-subtle",
15893
16076
  children: _t({
15894
16077
  id: "bT3F9b",
15895
16078
  message: "This collection is defined in code. Some settings cannot be changed here. Edit your live.config.ts file to modify the schema."
@@ -16455,21 +16638,21 @@ function ContentTypeList({ collections, orphanedTables, isLoading, onDelete, onR
16455
16638
  })]
16456
16639
  }),
16457
16640
  hasOrphans && /* @__PURE__ */ jsx("div", {
16458
- className: "rounded-md border border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950 p-4",
16641
+ className: "rounded-md border border-kumo-warning/50 bg-kumo-warning-tint p-4",
16459
16642
  children: /* @__PURE__ */ jsxs("div", {
16460
16643
  className: "flex items-start gap-3",
16461
- children: [/* @__PURE__ */ jsx(Warning, { className: "h-5 w-5 text-amber-600 dark:text-amber-400 mt-0.5" }), /* @__PURE__ */ jsxs("div", {
16644
+ children: [/* @__PURE__ */ jsx(Warning, { className: "h-5 w-5 text-kumo-warning mt-0.5" }), /* @__PURE__ */ jsxs("div", {
16462
16645
  className: "flex-1",
16463
16646
  children: [
16464
16647
  /* @__PURE__ */ jsx("h3", {
16465
- className: "font-medium text-amber-800 dark:text-amber-200",
16648
+ className: "font-medium text-kumo-warning",
16466
16649
  children: _t({
16467
16650
  id: "og4Qwq",
16468
16651
  message: "Unregistered Content Tables Found"
16469
16652
  })
16470
16653
  }),
16471
16654
  /* @__PURE__ */ jsx("p", {
16472
- className: "text-sm text-amber-700 dark:text-amber-300 mt-1",
16655
+ className: "text-sm text-kumo-subtle mt-1",
16473
16656
  children: _t({
16474
16657
  id: "ebLo22",
16475
16658
  message: "The following tables contain content but aren't registered as collections. Register them to manage this content in the admin."
@@ -16478,7 +16661,7 @@ function ContentTypeList({ collections, orphanedTables, isLoading, onDelete, onR
16478
16661
  /* @__PURE__ */ jsx("div", {
16479
16662
  className: "mt-3 space-y-2",
16480
16663
  children: orphanedTables.map((orphan) => /* @__PURE__ */ jsxs("div", {
16481
- className: "flex items-center justify-between bg-white dark:bg-amber-900/50 rounded-md px-3 py-2",
16664
+ className: "flex items-center justify-between bg-kumo-base rounded-md px-3 py-2",
16482
16665
  children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("code", {
16483
16666
  className: "text-sm font-medium",
16484
16667
  children: orphan.slug
@@ -16630,7 +16813,7 @@ function ContentTypeRow({ collection, onRequestDelete }) {
16630
16813
  children: /* @__PURE__ */ jsxs("div", {
16631
16814
  className: "flex items-center space-x-3",
16632
16815
  children: [/* @__PURE__ */ jsx("div", {
16633
- className: cn("flex h-8 w-8 items-center justify-center rounded-lg", isFromCode ? "bg-purple-100 text-purple-600 dark:bg-purple-900 dark:text-purple-300" : "bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-300"),
16816
+ className: cn("flex h-8 w-8 items-center justify-center rounded-lg", isFromCode ? "bg-kumo-badge-purple text-white" : "bg-kumo-badge-blue text-white"),
16634
16817
  children: isFromCode ? /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Database, { className: "h-4 w-4" })
16635
16818
  }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Link$1, {
16636
16819
  to: "/content-types/$slug",
@@ -16765,8 +16948,16 @@ function SandboxedPluginWidget({ pluginId, widgetId }) {
16765
16948
  sendInteraction(interaction);
16766
16949
  }, [sendInteraction]);
16767
16950
  if (loading) return /* @__PURE__ */ jsx("div", {
16768
- className: "flex items-center justify-center py-6",
16769
- children: /* @__PURE__ */ jsx(CircleNotch, { className: "h-5 w-5 animate-spin text-kumo-subtle" })
16951
+ className: "space-y-3 py-1",
16952
+ children: [
16953
+ 1,
16954
+ 2,
16955
+ 3
16956
+ ].map((i) => /* @__PURE__ */ jsx(SkeletonLine, {
16957
+ blockHeight: 24,
16958
+ minWidth: 45,
16959
+ maxWidth: 90
16960
+ }, i))
16770
16961
  });
16771
16962
  if (error) return /* @__PURE__ */ jsx("p", {
16772
16963
  className: "text-sm text-kumo-subtle",
@@ -16792,11 +16983,12 @@ function SandboxedPluginWidget({ pluginId, widgetId }) {
16792
16983
  */
16793
16984
  function Dashboard({ manifest }) {
16794
16985
  const { _: _t } = useLingui();
16795
- const { data: stats, isLoading } = useQuery({
16986
+ const { data: stats, isLoading, isError } = useQuery({
16796
16987
  queryKey: ["dashboard-stats"],
16797
16988
  queryFn: fetchDashboardStats,
16798
16989
  refetchOnWindowFocus: true
16799
16990
  });
16991
+ const showDashboardData = !isError || stats !== void 0;
16800
16992
  return /* @__PURE__ */ jsxs("div", {
16801
16993
  className: "space-y-6",
16802
16994
  children: [
@@ -16810,11 +17002,11 @@ function Dashboard({ manifest }) {
16810
17002
  })
16811
17003
  }), /* @__PURE__ */ jsx(QuickActions, { manifest })]
16812
17004
  }),
16813
- /* @__PURE__ */ jsx(StatusBar, {
17005
+ isError && /* @__PURE__ */ jsx(DashboardDataError, {}),
17006
+ showDashboardData && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SummaryMetrics, {
16814
17007
  stats,
16815
17008
  loading: isLoading
16816
- }),
16817
- /* @__PURE__ */ jsxs("div", {
17009
+ }), /* @__PURE__ */ jsxs("div", {
16818
17010
  className: "grid gap-6 lg:grid-cols-2",
16819
17011
  children: [/* @__PURE__ */ jsx(CollectionList, {
16820
17012
  collections: stats?.collections ?? [],
@@ -16824,232 +17016,304 @@ function Dashboard({ manifest }) {
16824
17016
  items: stats?.recentItems ?? [],
16825
17017
  loading: isLoading
16826
17018
  })]
16827
- }),
17019
+ })] }),
16828
17020
  /* @__PURE__ */ jsx(PluginWidgets, { manifest })
16829
17021
  ]
16830
17022
  });
16831
17023
  }
16832
- function QuickActions({ manifest }) {
17024
+ function DashboardDataError() {
16833
17025
  const { _: _t2 } = useLingui();
17026
+ return /* @__PURE__ */ jsx(Banner, {
17027
+ variant: "error",
17028
+ title: _t2({
17029
+ id: "hnBEKE",
17030
+ message: "Could not load dashboard data"
17031
+ }),
17032
+ description: _t2({
17033
+ id: "ajEWgm",
17034
+ message: "Refresh the page or try again."
17035
+ })
17036
+ });
17037
+ }
17038
+ function QuickActions({ manifest }) {
17039
+ const { _: _t3 } = useLingui();
16834
17040
  return /* @__PURE__ */ jsxs("div", {
16835
- className: "flex flex-wrap gap-2",
16836
- children: [Object.entries(manifest.collections).map(([slug, config]) => /* @__PURE__ */ jsxs(Link$1, {
16837
- to: "/content/$collection",
17041
+ className: "flex flex-wrap items-center gap-2",
17042
+ children: [Object.entries(manifest.collections).map(([slug, config]) => /* @__PURE__ */ jsx(RouterLinkButton, {
17043
+ to: "/content/$collection/new",
16838
17044
  params: { collection: slug },
16839
17045
  search: { locale: void 0 },
16840
- className: "inline-flex items-center gap-1.5 rounded-md border bg-kumo-base px-3 py-1.5 text-sm font-medium transition-colors hover:bg-kumo-tint",
16841
- children: [/* @__PURE__ */ jsx(Plus, {
16842
- className: "h-3.5 w-3.5",
16843
- "aria-hidden": "true"
16844
- }), config.labelSingular ?? config.label]
16845
- }, slug)), /* @__PURE__ */ jsxs(Link$1, {
17046
+ variant: "secondary",
17047
+ icon: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" }),
17048
+ children: config.labelSingular ?? config.label
17049
+ }, slug)), /* @__PURE__ */ jsx(RouterLinkButton, {
16846
17050
  to: "/media",
16847
- className: "inline-flex items-center gap-1.5 rounded-md border bg-kumo-base px-3 py-1.5 text-sm font-medium transition-colors hover:bg-kumo-tint",
16848
- children: [/* @__PURE__ */ jsx(Upload, {
16849
- className: "h-3.5 w-3.5",
16850
- "aria-hidden": "true"
16851
- }), _t2({
17051
+ variant: "secondary",
17052
+ icon: /* @__PURE__ */ jsx(Upload, { "aria-hidden": "true" }),
17053
+ children: _t3({
16852
17054
  id: "xfvWkE",
16853
17055
  message: "Upload Media"
16854
- })]
17056
+ })
16855
17057
  })]
16856
17058
  });
16857
17059
  }
16858
- function StatusBar({ stats, loading }) {
16859
- if (loading) return /* @__PURE__ */ jsx("div", { className: "flex h-9 animate-pulse rounded-lg border bg-kumo-tint" });
17060
+ function SummaryMetrics({ stats, loading }) {
17061
+ if (loading) return /* @__PURE__ */ jsx("div", {
17062
+ className: "grid gap-4 sm:grid-cols-3",
17063
+ children: [
17064
+ 1,
17065
+ 2,
17066
+ 3
17067
+ ].map((i) => /* @__PURE__ */ jsxs(LayerCard, { children: [/* @__PURE__ */ jsx(LayerCard.Secondary, { children: /* @__PURE__ */ jsx(SkeletonLine, {
17068
+ minWidth: 45,
17069
+ maxWidth: 70
17070
+ }) }), /* @__PURE__ */ jsx(LayerCard.Primary, {
17071
+ className: "text-2xl font-semibold",
17072
+ children: /* @__PURE__ */ jsx(SkeletonLine, {
17073
+ minWidth: 20,
17074
+ maxWidth: 35
17075
+ })
17076
+ })] }, i))
17077
+ });
16860
17078
  if (!stats) return null;
16861
17079
  const totalDrafts = stats.collections.reduce((sum, c) => sum + c.draft, 0);
16862
- const totalScheduled = stats.collections.reduce((sum, c) => sum + (c.total - c.published - c.draft), 0);
17080
+ const totalScheduled = stats.collections.reduce((sum, c) => sum + c.scheduled, 0);
17081
+ const hasScheduledContent = totalScheduled > 0;
17082
+ const metrics = [
17083
+ {
17084
+ icon: PencilSimple,
17085
+ label: i18n._({
17086
+ id: "Rj2Y2b",
17087
+ message: "{totalDrafts, plural, one {Draft} other {Drafts}}",
17088
+ values: { totalDrafts }
17089
+ }),
17090
+ value: totalDrafts
17091
+ },
17092
+ ...hasScheduledContent ? [{
17093
+ icon: CalendarBlank,
17094
+ label: i18n._({
17095
+ id: "kG6wfm",
17096
+ message: "{totalScheduled, plural, one {Scheduled} other {Scheduled}}",
17097
+ values: { totalScheduled }
17098
+ }),
17099
+ value: totalScheduled
17100
+ }] : [],
17101
+ {
17102
+ icon: Image$1,
17103
+ label: i18n._({
17104
+ id: "YF5avu",
17105
+ message: "{0, plural, one {Media file} other {Media files}}",
17106
+ values: { 0: stats.mediaCount }
17107
+ }),
17108
+ value: stats.mediaCount
17109
+ },
17110
+ {
17111
+ icon: Users,
17112
+ label: i18n._({
17113
+ id: "r7ZckI",
17114
+ message: "{0, plural, one {User} other {Users}}",
17115
+ values: { 0: stats.userCount }
17116
+ }),
17117
+ value: stats.userCount
17118
+ }
17119
+ ];
16863
17120
  return /* @__PURE__ */ jsx("div", {
16864
- className: "flex flex-wrap items-center gap-x-4 gap-y-1 rounded-lg border bg-kumo-base px-4 py-2 text-sm",
16865
- children: [
16866
- totalDrafts > 0 && {
16867
- icon: PencilSimple,
16868
- label: i18n._({
16869
- id: "PT4q12",
16870
- message: "{totalDrafts, plural, one {# draft} other {# drafts}}",
16871
- values: { totalDrafts }
16872
- }),
16873
- className: "text-amber-700 dark:text-amber-400"
16874
- },
16875
- totalScheduled > 0 && {
16876
- icon: CalendarBlank,
16877
- label: i18n._({
16878
- id: "XeGNNG",
16879
- message: "{totalScheduled, plural, one {# scheduled} other {# scheduled}}",
16880
- values: { totalScheduled }
16881
- }),
16882
- className: "text-blue-600 dark:text-blue-400"
16883
- },
16884
- {
16885
- icon: Image$1,
16886
- label: i18n._({
16887
- id: "7Taevp",
16888
- message: "{0, plural, one {# media file} other {# media files}}",
16889
- values: { 0: stats.mediaCount }
16890
- }),
16891
- className: "text-kumo-subtle"
16892
- },
16893
- {
16894
- icon: Users,
16895
- label: i18n._({
16896
- id: "V4WrGy",
16897
- message: "{0, plural, one {# user} other {# users}}",
16898
- values: { 0: stats.userCount }
16899
- }),
16900
- className: "text-kumo-subtle"
16901
- }
16902
- ].filter(Boolean).map((ind) => /* @__PURE__ */ jsxs("span", {
16903
- className: `inline-flex items-center gap-1.5 ${ind.className}`,
16904
- children: [/* @__PURE__ */ jsx(ind.icon, {
16905
- className: "h-3.5 w-3.5",
17121
+ className: hasScheduledContent ? "grid gap-4 sm:grid-cols-2 lg:grid-cols-4" : "grid gap-4 sm:grid-cols-3",
17122
+ children: metrics.map((metric) => /* @__PURE__ */ jsxs(LayerCard, { children: [/* @__PURE__ */ jsxs(LayerCard.Secondary, {
17123
+ className: "flex items-center gap-2 text-kumo-subtle",
17124
+ children: [/* @__PURE__ */ jsx(metric.icon, {
17125
+ className: "h-4 w-4",
16906
17126
  "aria-hidden": "true"
16907
- }), ind.label]
16908
- }, ind.label))
17127
+ }), /* @__PURE__ */ jsx("span", { children: metric.label })]
17128
+ }), /* @__PURE__ */ jsx(LayerCard.Primary, {
17129
+ className: "text-2xl font-semibold tabular-nums",
17130
+ children: metric.value
17131
+ })] }, metric.label))
17132
+ });
17133
+ }
17134
+ function SkeletonRows({ count }) {
17135
+ return /* @__PURE__ */ jsx("div", {
17136
+ className: "space-y-3 px-3",
17137
+ children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx(SkeletonLine, {
17138
+ blockHeight: 40,
17139
+ minWidth: 65,
17140
+ maxWidth: 95
17141
+ }, i))
16909
17142
  });
16910
17143
  }
16911
17144
  function CollectionList({ collections, manifest, loading }) {
16912
- const { _: _t3 } = useLingui();
16913
- return /* @__PURE__ */ jsxs("div", {
16914
- className: "rounded-lg border bg-kumo-base p-4 sm:p-6",
16915
- children: [/* @__PURE__ */ jsx("h2", {
16916
- className: "mb-4 text-lg font-semibold",
16917
- children: _t3({
17145
+ const { _: _t4 } = useLingui();
17146
+ return /* @__PURE__ */ jsxs(LayerCard, {
17147
+ className: "h-full",
17148
+ children: [/* @__PURE__ */ jsx(LayerCard.Secondary, { children: /* @__PURE__ */ jsx("h2", {
17149
+ className: "px-3",
17150
+ children: _t4({
16918
17151
  id: "4b3oEV",
16919
17152
  message: "Content"
16920
17153
  })
16921
- }), loading ? /* @__PURE__ */ jsx("div", {
16922
- className: "space-y-3",
16923
- children: [
16924
- 1,
16925
- 2,
16926
- 3
16927
- ].map((i) => /* @__PURE__ */ jsx("div", { className: "h-10 animate-pulse rounded-md bg-kumo-tint" }, i))
16928
- }) : collections.length === 0 ? /* @__PURE__ */ jsx("p", {
16929
- className: "text-sm text-kumo-subtle",
16930
- children: _t3({
16931
- id: "VxhRZV",
16932
- message: "No collections configured"
16933
- })
16934
- }) : /* @__PURE__ */ jsx("div", {
16935
- className: "space-y-1",
16936
- children: collections.map((col) => {
16937
- const config = manifest.collections[col.slug];
16938
- return /* @__PURE__ */ jsxs(Link$1, {
16939
- to: "/content/$collection",
16940
- params: { collection: col.slug },
16941
- search: { locale: void 0 },
16942
- className: "group flex items-center justify-between rounded-md px-3 py-2 hover:bg-kumo-tint",
16943
- children: [/* @__PURE__ */ jsx("span", {
16944
- className: "font-medium",
16945
- children: config?.label ?? col.label
16946
- }), /* @__PURE__ */ jsxs("span", {
16947
- className: "flex items-center gap-3 text-xs text-kumo-subtle",
16948
- children: [
16949
- /* @__PURE__ */ jsx(CountBadge, {
16950
- icon: CheckCircle,
16951
- count: col.published,
16952
- title: _t3({
16953
- id: "u3wRF+",
16954
- message: "Published"
16955
- })
16956
- }),
16957
- /* @__PURE__ */ jsx(CountBadge, {
16958
- icon: PencilSimple,
16959
- count: col.draft,
16960
- title: _t3({
16961
- id: "M8kJqa",
16962
- message: "Drafts"
17154
+ }) }), /* @__PURE__ */ jsx(LayerCard.Primary, {
17155
+ className: "flex-1",
17156
+ children: loading ? /* @__PURE__ */ jsx(SkeletonRows, { count: 3 }) : collections.length === 0 ? /* @__PURE__ */ jsx("p", {
17157
+ className: "px-3 text-sm text-kumo-subtle",
17158
+ children: _t4({
17159
+ id: "VxhRZV",
17160
+ message: "No collections configured"
17161
+ })
17162
+ }) : /* @__PURE__ */ jsx("div", {
17163
+ className: "space-y-1",
17164
+ children: collections.map((col) => {
17165
+ const config = manifest.collections[col.slug];
17166
+ return /* @__PURE__ */ jsxs(Link$1, {
17167
+ to: "/content/$collection",
17168
+ params: { collection: col.slug },
17169
+ search: { locale: void 0 },
17170
+ className: "group flex items-center justify-between gap-2 rounded-md px-3 py-2 hover:bg-kumo-tint",
17171
+ children: [/* @__PURE__ */ jsx("span", {
17172
+ className: "font-medium",
17173
+ children: config?.label ?? col.label
17174
+ }), /* @__PURE__ */ jsxs("span", {
17175
+ className: "flex shrink-0 items-center gap-2",
17176
+ children: [
17177
+ /* @__PURE__ */ jsx(CountBadge, {
17178
+ icon: CheckCircle,
17179
+ count: col.published,
17180
+ variant: "success",
17181
+ label: _t4({
17182
+ id: "u3wRF+",
17183
+ message: "Published"
17184
+ })
17185
+ }),
17186
+ /* @__PURE__ */ jsx(CountBadge, {
17187
+ icon: PencilSimple,
17188
+ count: col.draft,
17189
+ variant: "secondary",
17190
+ label: _t4({
17191
+ id: "M8kJqa",
17192
+ message: "Drafts"
17193
+ })
17194
+ }),
17195
+ /* @__PURE__ */ jsx(ArrowNext, {
17196
+ className: "h-3.5 w-3.5 text-kumo-subtle opacity-0 transition-opacity group-hover:opacity-100",
17197
+ "aria-hidden": "true"
16963
17198
  })
16964
- }),
16965
- /* @__PURE__ */ jsx(ArrowRight, {
16966
- className: "h-3.5 w-3.5 opacity-0 transition-opacity group-hover:opacity-100",
16967
- "aria-hidden": "true"
16968
- })
16969
- ]
16970
- })]
16971
- }, col.slug);
17199
+ ]
17200
+ })]
17201
+ }, col.slug);
17202
+ })
16972
17203
  })
16973
17204
  })]
16974
17205
  });
16975
17206
  }
16976
- function CountBadge({ icon: Icon, count, title }) {
17207
+ function CountBadge({ icon: Icon, count, variant, label }) {
16977
17208
  if (count === 0) return null;
16978
- return /* @__PURE__ */ jsxs("span", {
16979
- className: "inline-flex items-center gap-1",
16980
- title,
16981
- children: [/* @__PURE__ */ jsx(Icon, {
16982
- className: "h-3 w-3",
16983
- "aria-hidden": "true"
16984
- }), count]
17209
+ return /* @__PURE__ */ jsxs(Badge, {
17210
+ variant,
17211
+ className: "gap-1",
17212
+ children: [
17213
+ /* @__PURE__ */ jsx(Icon, {
17214
+ className: "h-3 w-3",
17215
+ "aria-hidden": "true"
17216
+ }),
17217
+ /* @__PURE__ */ jsx("span", {
17218
+ className: "sr-only",
17219
+ children: label
17220
+ }),
17221
+ count
17222
+ ]
16985
17223
  });
16986
17224
  }
16987
17225
  function RecentActivity({ items, loading }) {
16988
- const { _: _t4 } = useLingui();
16989
- return /* @__PURE__ */ jsxs("div", {
16990
- className: "rounded-lg border bg-kumo-base p-4 sm:p-6",
16991
- children: [/* @__PURE__ */ jsx("h2", {
16992
- className: "mb-4 text-lg font-semibold",
16993
- children: _t4({
17226
+ const { _: _t5 } = useLingui();
17227
+ return /* @__PURE__ */ jsxs(LayerCard, {
17228
+ className: "h-full",
17229
+ children: [/* @__PURE__ */ jsx(LayerCard.Secondary, { children: /* @__PURE__ */ jsx("h2", {
17230
+ className: "px-3",
17231
+ children: _t5({
16994
17232
  id: "XxlcGv",
16995
17233
  message: "Recent Activity"
16996
17234
  })
16997
- }), loading ? /* @__PURE__ */ jsx("div", {
16998
- className: "space-y-3",
16999
- children: [
17000
- 1,
17001
- 2,
17002
- 3,
17003
- 4,
17004
- 5
17005
- ].map((i) => /* @__PURE__ */ jsx("div", { className: "h-10 animate-pulse rounded-md bg-kumo-tint" }, i))
17006
- }) : items.length === 0 ? /* @__PURE__ */ jsx("p", {
17007
- className: "text-sm text-kumo-subtle",
17008
- children: _t4({
17009
- id: "m0I2ba",
17010
- message: "No recent activity"
17011
- })
17012
- }) : /* @__PURE__ */ jsx("div", {
17013
- className: "space-y-1",
17014
- children: items.map((item) => /* @__PURE__ */ jsxs(Link$1, {
17015
- to: "/content/$collection/$id",
17016
- params: {
17017
- collection: item.collection,
17018
- id: item.id
17019
- },
17020
- className: "group flex items-center justify-between gap-2 rounded-md px-3 py-2 hover:bg-kumo-tint",
17021
- children: [/* @__PURE__ */ jsxs("div", {
17022
- className: "flex min-w-0 items-center gap-2",
17023
- children: [
17024
- /* @__PURE__ */ jsx(StatusDot, { status: item.status }),
17025
- /* @__PURE__ */ jsx("span", {
17026
- className: "truncate font-medium",
17027
- children: item.title || item.slug || _t4({
17028
- id: "wja8aL",
17029
- message: "Untitled"
17235
+ }) }), /* @__PURE__ */ jsx(LayerCard.Primary, {
17236
+ className: "flex-1",
17237
+ children: loading ? /* @__PURE__ */ jsx(SkeletonRows, { count: 5 }) : items.length === 0 ? /* @__PURE__ */ jsx("p", {
17238
+ className: "px-3 text-sm text-kumo-subtle",
17239
+ children: _t5({
17240
+ id: "m0I2ba",
17241
+ message: "No recent activity"
17242
+ })
17243
+ }) : /* @__PURE__ */ jsx("div", {
17244
+ className: "space-y-1",
17245
+ children: items.map((item) => /* @__PURE__ */ jsxs(Link$1, {
17246
+ to: "/content/$collection/$id",
17247
+ params: {
17248
+ collection: item.collection,
17249
+ id: item.id
17250
+ },
17251
+ className: "group flex items-center justify-between gap-2 rounded-md px-3 py-2 hover:bg-kumo-tint",
17252
+ children: [/* @__PURE__ */ jsxs("div", {
17253
+ className: "flex min-w-0 items-center gap-2",
17254
+ children: [
17255
+ /* @__PURE__ */ jsx(StatusDot, { status: item.status }),
17256
+ /* @__PURE__ */ jsx("span", {
17257
+ className: "truncate font-medium",
17258
+ children: item.title || item.slug || _t5({
17259
+ id: "wja8aL",
17260
+ message: "Untitled"
17261
+ })
17262
+ }),
17263
+ /* @__PURE__ */ jsx("span", {
17264
+ className: "hidden shrink-0 text-xs text-kumo-subtle sm:inline",
17265
+ children: item.collectionLabel
17030
17266
  })
17031
- }),
17032
- /* @__PURE__ */ jsx("span", {
17033
- className: "hidden shrink-0 text-xs text-kumo-subtle sm:inline",
17034
- children: item.collectionLabel
17035
- })
17036
- ]
17037
- }), /* @__PURE__ */ jsx("span", {
17038
- className: "shrink-0 text-xs text-kumo-subtle",
17039
- children: formatRelativeTime$1(item.updatedAt)
17040
- })]
17041
- }, `${item.collection}-${item.id}`))
17267
+ ]
17268
+ }), /* @__PURE__ */ jsx("span", {
17269
+ className: "shrink-0 text-xs text-kumo-subtle",
17270
+ children: formatRelativeTime$1(item.updatedAt)
17271
+ })]
17272
+ }, `${item.collection}-${item.id}`))
17273
+ })
17042
17274
  })]
17043
17275
  });
17044
17276
  }
17045
17277
  function StatusDot({ status }) {
17278
+ const { _: _t6 } = useLingui();
17279
+ const colors = {
17280
+ published: "text-kumo-success",
17281
+ draft: "text-kumo-warning",
17282
+ scheduled: "text-kumo-info"
17283
+ };
17284
+ const labels = {
17285
+ published: _t6({
17286
+ id: "u3wRF+",
17287
+ message: "Published"
17288
+ }),
17289
+ draft: _t6({
17290
+ id: "eneWvv",
17291
+ message: "Draft"
17292
+ }),
17293
+ scheduled: _t6({
17294
+ id: "4ba0NE",
17295
+ message: "Scheduled"
17296
+ }),
17297
+ pending: _t6({
17298
+ id: "UbRKMZ",
17299
+ message: "Pending"
17300
+ }),
17301
+ private: _t6({
17302
+ id: "zwBp5t",
17303
+ message: "Private"
17304
+ }),
17305
+ archived: _t6({
17306
+ id: "TdfEV7",
17307
+ message: "Archived"
17308
+ })
17309
+ };
17046
17310
  return /* @__PURE__ */ jsx(status === "published" ? CheckCircle : CircleDashed, {
17047
- className: `h-3.5 w-3.5 shrink-0 ${{
17048
- published: "text-green-500",
17049
- draft: "text-amber-500",
17050
- scheduled: "text-blue-500"
17051
- }[status] ?? "text-kumo-subtle"}`,
17052
- "aria-label": status
17311
+ className: `h-3.5 w-3.5 shrink-0 ${colors[status] ?? "text-kumo-subtle"}`,
17312
+ "aria-label": labels[status] ?? _t6({
17313
+ id: "OBvvgU",
17314
+ message: "Status: {status}",
17315
+ values: { status }
17316
+ })
17053
17317
  });
17054
17318
  }
17055
17319
  function PluginWidgets({ manifest }) {
@@ -17071,14 +17335,20 @@ function PluginWidgets({ manifest }) {
17071
17335
  }
17072
17336
  function PluginWidgetCard({ widget }) {
17073
17337
  const WidgetComponent = usePluginWidget(widget.pluginId, widget.id);
17074
- return /* @__PURE__ */ jsxs("div", {
17075
- className: "rounded-lg border bg-kumo-base p-4 sm:p-6",
17076
- children: [/* @__PURE__ */ jsx("h2", {
17077
- className: "text-lg font-semibold mb-4",
17338
+ return /* @__PURE__ */ jsxs(LayerCard, {
17339
+ className: "h-full",
17340
+ children: [/* @__PURE__ */ jsx(LayerCard.Secondary, { children: /* @__PURE__ */ jsx("h2", {
17341
+ className: "px-3",
17078
17342
  children: widget.title || widget.id
17079
- }), WidgetComponent ? /* @__PURE__ */ jsx(WidgetComponent, {}) : /* @__PURE__ */ jsx(SandboxedPluginWidget, {
17080
- pluginId: widget.pluginId,
17081
- widgetId: widget.id
17343
+ }) }), /* @__PURE__ */ jsx(LayerCard.Primary, {
17344
+ className: "flex-1",
17345
+ children: /* @__PURE__ */ jsx("div", {
17346
+ className: "px-3",
17347
+ children: WidgetComponent ? /* @__PURE__ */ jsx(WidgetComponent, {}) : /* @__PURE__ */ jsx(SandboxedPluginWidget, {
17348
+ pluginId: widget.pluginId,
17349
+ widgetId: widget.id
17350
+ })
17351
+ })
17082
17352
  })]
17083
17353
  });
17084
17354
  }
@@ -17221,21 +17491,21 @@ function DeviceAuthorizePage() {
17221
17491
  ]
17222
17492
  }),
17223
17493
  pageState === "success" && /* @__PURE__ */ jsxs("div", {
17224
- className: "rounded-lg border border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950/50 p-6 text-center",
17494
+ className: "rounded-lg border border-kumo-success/50 bg-kumo-success-tint p-6 text-center",
17225
17495
  children: [
17226
17496
  /* @__PURE__ */ jsx("div", {
17227
- className: "inline-flex items-center justify-center w-10 h-10 rounded-full bg-green-100 dark:bg-green-900/50 mb-3",
17228
- children: /* @__PURE__ */ jsx(CheckIcon, { className: "w-5 h-5 text-green-600 dark:text-green-400" })
17497
+ className: "inline-flex items-center justify-center w-10 h-10 rounded-full bg-kumo-success/15 mb-3",
17498
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "w-5 h-5 text-kumo-success" })
17229
17499
  }),
17230
17500
  /* @__PURE__ */ jsx("h2", {
17231
- className: "font-medium text-green-900 dark:text-green-100",
17501
+ className: "font-medium text-kumo-success",
17232
17502
  children: _t({
17233
17503
  id: "BaDjZ4",
17234
17504
  message: "Device authorized"
17235
17505
  })
17236
17506
  }),
17237
17507
  /* @__PURE__ */ jsx("p", {
17238
- className: "text-sm text-green-700 dark:text-green-300 mt-1",
17508
+ className: "text-sm text-kumo-subtle mt-1",
17239
17509
  children: _t({
17240
17510
  id: "qxMbTz",
17241
17511
  message: "You can close this page and return to your terminal."
@@ -17721,7 +17991,7 @@ function PasskeyRegistration({ optionsEndpoint, verifyEndpoint, onSuccess, onErr
17721
17991
  children: state.message
17722
17992
  }),
17723
17993
  state.status === "success" && /* @__PURE__ */ jsx("div", {
17724
- className: "rounded-lg bg-green-500/10 p-4 text-sm text-green-700 dark:text-green-400",
17994
+ className: "rounded-lg bg-kumo-success/10 p-4 text-sm text-kumo-success",
17725
17995
  children: _t({
17726
17996
  id: "TZktjo",
17727
17997
  message: "Passkey registered successfully!"
@@ -19254,7 +19524,7 @@ function PluginAvatar({ name }) {
19254
19524
  function AuditBadge({ verdict }) {
19255
19525
  const { _: _t3 } = useLingui();
19256
19526
  if (verdict === "pass") return /* @__PURE__ */ jsxs("span", {
19257
- className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs bg-green-500/10 text-green-600",
19527
+ className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs bg-kumo-success/10 text-kumo-success",
19258
19528
  title: _t3({
19259
19529
  id: "BZ1XSW",
19260
19530
  message: "Security audit passed"
@@ -19265,7 +19535,7 @@ function AuditBadge({ verdict }) {
19265
19535
  })]
19266
19536
  });
19267
19537
  if (verdict === "warn") return /* @__PURE__ */ jsxs("span", {
19268
- className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs bg-warning/10 text-warning",
19538
+ className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs bg-kumo-warning/10 text-kumo-warning",
19269
19539
  title: _t3({
19270
19540
  id: "pQszWq",
19271
19541
  message: "Security audit flagged concerns"
@@ -19428,12 +19698,12 @@ function CapabilityConsentDialog({ mode, pluginName, capabilities, allowedHosts,
19428
19698
  capabilities.map((cap) => {
19429
19699
  const isNew = newSet.has(cap);
19430
19700
  return /* @__PURE__ */ jsxs("div", {
19431
- className: cn("flex items-start gap-3 rounded-md p-2 text-sm", isNew ? "bg-warning/10 border border-warning/30" : "bg-kumo-tint/50"),
19432
- children: [/* @__PURE__ */ jsx(ShieldCheck, { className: cn("mt-0.5 h-4 w-4 shrink-0", isNew ? "text-warning" : "text-kumo-subtle") }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
19701
+ className: cn("flex items-start gap-3 rounded-md p-2 text-sm", isNew ? "bg-kumo-warning/10 border border-kumo-warning/30" : "bg-kumo-tint/50"),
19702
+ children: [/* @__PURE__ */ jsx(ShieldCheck, { className: cn("mt-0.5 h-4 w-4 shrink-0", isNew ? "text-kumo-warning" : "text-kumo-subtle") }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
19433
19703
  className: cn(isNew && "font-medium"),
19434
19704
  children: describeCapability(cap, allowedHosts)
19435
19705
  }), isNew && /* @__PURE__ */ jsx("span", {
19436
- className: "ms-2 text-xs text-warning font-medium",
19706
+ className: "ms-2 text-xs text-kumo-warning font-medium",
19437
19707
  children: _t({
19438
19708
  id: "p6NueD",
19439
19709
  message: "NEW"
@@ -19442,10 +19712,10 @@ function CapabilityConsentDialog({ mode, pluginName, capabilities, allowedHosts,
19442
19712
  }, cap);
19443
19713
  }),
19444
19714
  newlyPublicRoutes.length > 0 && /* @__PURE__ */ jsxs("div", {
19445
- className: "rounded-md border border-warning/30 bg-warning/10 p-3 text-sm",
19715
+ className: "rounded-md border border-kumo-warning/30 bg-kumo-warning/10 p-3 text-sm",
19446
19716
  children: [
19447
19717
  /* @__PURE__ */ jsxs("div", {
19448
- className: "flex items-center gap-2 font-medium text-warning",
19718
+ className: "flex items-center gap-2 font-medium text-kumo-warning",
19449
19719
  children: [/* @__PURE__ */ jsx(Warning, { className: "h-4 w-4 shrink-0" }), _t({
19450
19720
  id: "NXruDe",
19451
19721
  message: "New public routes"
@@ -19468,7 +19738,7 @@ function CapabilityConsentDialog({ mode, pluginName, capabilities, allowedHosts,
19468
19738
  ]
19469
19739
  }),
19470
19740
  auditVerdict && auditVerdict !== "pass" && /* @__PURE__ */ jsxs("div", {
19471
- className: cn("flex items-center gap-2 rounded-md p-3 text-sm mt-2", auditVerdict === "warn" ? "bg-warning/10 text-warning" : "bg-kumo-danger/10 text-kumo-danger"),
19741
+ className: cn("flex items-center gap-2 rounded-md p-3 text-sm mt-2", auditVerdict === "warn" ? "bg-kumo-warning/10 text-kumo-warning" : "bg-kumo-danger/10 text-kumo-danger"),
19472
19742
  children: [auditVerdict === "warn" ? /* @__PURE__ */ jsx(Warning, { className: "h-4 w-4 shrink-0" }) : /* @__PURE__ */ jsx(ShieldWarning, { className: "h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", { children: auditVerdict === "warn" ? _t({
19473
19743
  id: "zPUuMZ",
19474
19744
  message: "Security audit flagged potential concerns with this plugin."
@@ -22799,7 +23069,7 @@ function ContentPickerModal({ open, onOpenChange, onSelect }) {
22799
23069
  }), /* @__PURE__ */ jsxs("div", {
22800
23070
  className: "text-sm text-kumo-subtle flex items-center gap-2",
22801
23071
  children: [
22802
- /* @__PURE__ */ jsx("span", { className: cn("inline-block h-2 w-2 rounded-full", status === "published" ? "bg-green-500" : status === "published_with_changes" ? "bg-yellow-500" : "bg-gray-400") }),
23072
+ /* @__PURE__ */ jsx("span", { className: cn("inline-block h-2 w-2 rounded-full", status === "published" ? "bg-kumo-success" : status === "published_with_changes" ? "bg-kumo-warning" : "bg-kumo-fill") }),
22803
23073
  status === "published" ? _t({
22804
23074
  id: "u3wRF+",
22805
23075
  message: "Published"
@@ -25862,7 +26132,7 @@ function SandboxedPluginPage({ pluginId, page }) {
25862
26132
  return /* @__PURE__ */ jsxs("div", {
25863
26133
  className: "relative",
25864
26134
  children: [toast && /* @__PURE__ */ jsx("div", {
25865
- className: `fixed end-4 top-4 z-50 rounded-lg border px-4 py-3 text-sm shadow-lg ${toast.type === "success" ? "border-green-200 bg-green-50 text-green-800" : toast.type === "error" ? "border-red-200 bg-red-50 text-red-800" : "border-blue-200 bg-blue-50 text-blue-800"}`,
26135
+ className: `fixed end-4 top-4 z-50 rounded-lg border px-4 py-3 text-sm shadow-lg ${toast.type === "success" ? "border-kumo-success/50 bg-kumo-success-tint text-kumo-success" : toast.type === "error" ? "border-kumo-danger/50 bg-kumo-danger/10 text-kumo-danger" : "border-kumo-info/50 bg-kumo-info-tint text-kumo-info"}`,
25866
26136
  children: toast.message
25867
26137
  }), /* @__PURE__ */ jsx(BlockRenderer, {
25868
26138
  blocks,
@@ -27756,16 +28026,16 @@ function ApiTokenSettings() {
27756
28026
  })] })]
27757
28027
  }),
27758
28028
  newToken && /* @__PURE__ */ jsx("div", {
27759
- className: "rounded-lg border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-950/30 p-4",
28029
+ className: "rounded-lg border border-kumo-success/50 bg-kumo-success-tint p-4",
27760
28030
  children: /* @__PURE__ */ jsxs("div", {
27761
28031
  className: "flex items-start gap-3",
27762
28032
  children: [
27763
- /* @__PURE__ */ jsx(Key, { className: "h-5 w-5 text-green-600 dark:text-green-400 mt-0.5 shrink-0" }),
28033
+ /* @__PURE__ */ jsx(Key, { className: "h-5 w-5 text-kumo-success mt-0.5 shrink-0" }),
27764
28034
  /* @__PURE__ */ jsxs("div", {
27765
28035
  className: "flex-1 min-w-0",
27766
28036
  children: [
27767
28037
  /* @__PURE__ */ jsx("p", {
27768
- className: "font-medium text-green-800 dark:text-green-200",
28038
+ className: "font-medium text-kumo-success",
27769
28039
  children: _t({
27770
28040
  id: "eoLxnB",
27771
28041
  message: "Token created: {0}",
@@ -27773,7 +28043,7 @@ function ApiTokenSettings() {
27773
28043
  })
27774
28044
  }),
27775
28045
  /* @__PURE__ */ jsx("p", {
27776
- className: "text-sm text-green-700 dark:text-green-300 mt-1",
28046
+ className: "text-sm text-kumo-subtle mt-1",
27777
28047
  children: _t({
27778
28048
  id: "DyPcUA",
27779
28049
  message: "Copy this token now — it won't be shown again."
@@ -27783,7 +28053,7 @@ function ApiTokenSettings() {
27783
28053
  className: "mt-3 flex items-center gap-2",
27784
28054
  children: [
27785
28055
  /* @__PURE__ */ jsx("code", {
27786
- className: "flex-1 rounded bg-white dark:bg-black/30 px-3 py-2 text-sm font-mono border truncate",
28056
+ className: "flex-1 rounded bg-kumo-base px-3 py-2 text-sm font-mono border truncate",
27787
28057
  children: tokenVisible ? newToken.token : "••••••••••••••••••••••••••••"
27788
28058
  }),
27789
28059
  /* @__PURE__ */ jsx(Button, {
@@ -27812,7 +28082,7 @@ function ApiTokenSettings() {
27812
28082
  ]
27813
28083
  }),
27814
28084
  copied && /* @__PURE__ */ jsx("p", {
27815
- className: "text-xs text-green-600 dark:text-green-400 mt-1",
28085
+ className: "text-xs text-kumo-success mt-1",
27816
28086
  children: _t({
27817
28087
  id: "FxVG/l",
27818
28088
  message: "Copied to clipboard"
@@ -28148,7 +28418,7 @@ function EmailSettings() {
28148
28418
  })
28149
28419
  })]
28150
28420
  }), /* @__PURE__ */ jsxs("div", {
28151
- className: "flex items-center gap-2 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-800 dark:border-red-800 dark:bg-red-950/30 dark:text-red-200",
28421
+ className: "flex items-center gap-2 rounded-lg border border-kumo-danger/50 bg-kumo-danger/10 p-3 text-sm text-kumo-danger",
28152
28422
  children: [/* @__PURE__ */ jsx(WarningCircle, { className: "h-4 w-4 flex-shrink-0" }), getMutationError(fetchError) || _t({
28153
28423
  id: "4zmChb",
28154
28424
  message: "Failed to load email settings"
@@ -28241,26 +28511,26 @@ function PipelineStatus({ settings }) {
28241
28511
  const { _: _t2 } = useLingui();
28242
28512
  if (!settings) return null;
28243
28513
  if (!settings.available) return /* @__PURE__ */ jsx("div", {
28244
- className: "rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 p-4",
28514
+ className: "rounded-lg border border-kumo-warning/50 bg-kumo-warning-tint p-4",
28245
28515
  children: /* @__PURE__ */ jsxs("div", {
28246
28516
  className: "flex items-start gap-3",
28247
- children: [/* @__PURE__ */ jsx(WarningCircle, { className: "h-5 w-5 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [
28517
+ children: [/* @__PURE__ */ jsx(WarningCircle, { className: "h-5 w-5 text-kumo-warning mt-0.5 flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [
28248
28518
  /* @__PURE__ */ jsx("p", {
28249
- className: "text-sm font-medium text-amber-800 dark:text-amber-200",
28519
+ className: "text-sm font-medium text-kumo-warning",
28250
28520
  children: _t2({
28251
28521
  id: "i5hIWi",
28252
28522
  message: "No email provider configured"
28253
28523
  })
28254
28524
  }),
28255
28525
  /* @__PURE__ */ jsx("p", {
28256
- className: "text-sm text-amber-700 dark:text-amber-300 mt-1",
28526
+ className: "text-sm text-kumo-subtle mt-1",
28257
28527
  children: _t2({
28258
28528
  id: "ngArkG",
28259
28529
  message: "Install and activate an email provider plugin to enable email features like invitations, magic links, and password recovery."
28260
28530
  })
28261
28531
  }),
28262
28532
  /* @__PURE__ */ jsx("p", {
28263
- className: "text-sm text-amber-700 dark:text-amber-300 mt-2",
28533
+ className: "text-sm text-kumo-subtle mt-2",
28264
28534
  children: _t2({
28265
28535
  id: "pZ5czc",
28266
28536
  message: "Without an email provider, invite links must be shared manually."
@@ -28273,15 +28543,15 @@ function PipelineStatus({ settings }) {
28273
28543
  className: "space-y-4",
28274
28544
  children: [
28275
28545
  /* @__PURE__ */ jsxs("div", {
28276
- className: "flex items-center gap-3 p-3 rounded-md bg-green-50 dark:bg-green-950/20 border border-green-200 dark:border-green-800",
28277
- children: [/* @__PURE__ */ jsx(CheckCircle, { className: "h-5 w-5 text-green-600 dark:text-green-400 flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
28278
- className: "text-sm font-medium text-green-800 dark:text-green-200",
28546
+ className: "flex items-center gap-3 p-3 rounded-md bg-kumo-success-tint border border-kumo-success/50",
28547
+ children: [/* @__PURE__ */ jsx(CheckCircle, { className: "h-5 w-5 text-kumo-success flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
28548
+ className: "text-sm font-medium text-kumo-success",
28279
28549
  children: _t2({
28280
28550
  id: "dXoz4H",
28281
28551
  message: "Email provider active"
28282
28552
  })
28283
28553
  }), /* @__PURE__ */ jsxs("p", {
28284
- className: "text-sm text-green-700 dark:text-green-300",
28554
+ className: "text-sm text-kumo-subtle",
28285
28555
  children: [
28286
28556
  _t2({
28287
28557
  id: "2zQVV5",
@@ -28289,7 +28559,7 @@ function PipelineStatus({ settings }) {
28289
28559
  }),
28290
28560
  " ",
28291
28561
  /* @__PURE__ */ jsx("code", {
28292
- className: "rounded bg-green-100 dark:bg-green-900/40 px-1.5 py-0.5 text-xs",
28562
+ className: "rounded bg-kumo-tint px-1.5 py-0.5 text-xs",
28293
28563
  children: settings.selectedProviderId || "default"
28294
28564
  })
28295
28565
  ]
@@ -28881,7 +29151,7 @@ function PasskeyItem({ passkey, canDelete, onRename, onDelete, isDeleting, isRen
28881
29151
  /* @__PURE__ */ jsxs("div", {
28882
29152
  className: "text-sm text-kumo-subtle",
28883
29153
  children: [deviceTypeLabel, passkey.backedUp && /* @__PURE__ */ jsxs("span", {
28884
- className: "text-green-600 dark:text-green-400",
29154
+ className: "text-kumo-success",
28885
29155
  children: [" ", _t({
28886
29156
  id: "q/13RP",
28887
29157
  message: "(synced)"
@@ -31205,6 +31475,7 @@ function ThemeToggle() {
31205
31475
  return /* @__PURE__ */ jsxs(Button, {
31206
31476
  variant: "ghost",
31207
31477
  shape: "square",
31478
+ size: "sm",
31208
31479
  "aria-label": _t({
31209
31480
  id: "6o2PVv",
31210
31481
  message: "Toggle theme (current: {label})",
@@ -31216,7 +31487,7 @@ function ThemeToggle() {
31216
31487
  message: "Theme: {label}",
31217
31488
  values: { label }
31218
31489
  }),
31219
- children: [theme === "system" ? /* @__PURE__ */ jsx(Monitor, { className: "h-5 w-5" }) : theme === "light" ? /* @__PURE__ */ jsx(Sun, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Moon, { className: "h-5 w-5" }), /* @__PURE__ */ jsx("span", {
31490
+ children: [theme === "system" ? /* @__PURE__ */ jsx(Monitor, { className: "h-4 w-4" }) : theme === "light" ? /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
31220
31491
  className: "sr-only",
31221
31492
  children: _t({
31222
31493
  id: "6o2PVv",
@@ -31230,6 +31501,9 @@ function ThemeToggle() {
31230
31501
  //#endregion
31231
31502
  //#region src/components/Header.tsx
31232
31503
  async function handleLogout() {
31504
+ try {
31505
+ localStorage.removeItem("emdash-editor");
31506
+ } catch {}
31233
31507
  const res = await apiFetch("/_emdash/api/auth/logout?redirect=/_emdash/admin/login", {
31234
31508
  method: "POST",
31235
31509
  credentials: "same-origin"
@@ -31274,13 +31548,13 @@ function Header() {
31274
31548
  children: /* @__PURE__ */ jsxs(Button, {
31275
31549
  variant: "ghost",
31276
31550
  size: "sm",
31277
- className: "gap-2 py-1 h-auto",
31551
+ className: "gap-2",
31278
31552
  children: [user?.avatarUrl ? /* @__PURE__ */ jsx("img", {
31279
31553
  src: user.avatarUrl,
31280
31554
  alt: "",
31281
- className: "h-6 w-6 rounded-full object-cover"
31555
+ className: "h-5 w-5 rounded-full object-cover"
31282
31556
  }) : /* @__PURE__ */ jsx("div", {
31283
- className: "h-6 w-6 rounded-full bg-kumo-brand/10 flex items-center justify-center text-xs font-medium",
31557
+ className: "h-5 w-5 rounded-full bg-kumo-brand/10 flex items-center justify-center text-[10px] font-medium",
31284
31558
  children: initials
31285
31559
  }), /* @__PURE__ */ jsx("span", {
31286
31560
  className: "hidden sm:inline max-w-[120px] truncate",
@@ -31556,6 +31830,15 @@ function Shell({ children, manifest }) {
31556
31830
  React$1.useEffect(() => {
31557
31831
  if (user?.isFirstLogin) setWelcomeModalOpen(true);
31558
31832
  }, [user?.isFirstLogin]);
31833
+ React$1.useEffect(() => {
31834
+ if (!user) return;
31835
+ try {
31836
+ if (user.role >= 30) {
31837
+ localStorage.setItem("emdash-editor", "1");
31838
+ localStorage.removeItem("emdash-toolbar-dismissed");
31839
+ } else localStorage.removeItem("emdash-editor");
31840
+ } catch {}
31841
+ }, [user]);
31559
31842
  return /* @__PURE__ */ jsxs(KumoSidebar.Provider, {
31560
31843
  defaultOpen: true,
31561
31844
  side: sidebarSide,
@@ -31769,9 +32052,9 @@ function VerifyStep({ verifyResult, token, onBack: _onBack }) {
31769
32052
  className: "text-center",
31770
32053
  children: [
31771
32054
  /* @__PURE__ */ jsx("div", {
31772
- className: "inline-flex items-center justify-center w-16 h-16 rounded-full bg-green-500/10 mx-auto mb-4",
32055
+ className: "inline-flex items-center justify-center w-16 h-16 rounded-full bg-kumo-success/10 mx-auto mb-4",
31773
32056
  children: /* @__PURE__ */ jsx("svg", {
31774
- className: "w-8 h-8 text-green-600",
32057
+ className: "w-8 h-8 text-kumo-success",
31775
32058
  fill: "none",
31776
32059
  stroke: "currentColor",
31777
32060
  viewBox: "0 0 24 24",
@@ -35719,10 +36002,10 @@ function ProbeResultStep({ result, onUploadFile, onPluginConnect, onPluginManual
35719
36002
  if (!result.isWordPress) return /* @__PURE__ */ jsxs("div", {
35720
36003
  className: "space-y-6",
35721
36004
  children: [/* @__PURE__ */ jsx("div", {
35722
- className: "rounded-lg border-s-4 border-s-orange-500 border border-kumo-line bg-kumo-base p-6",
36005
+ className: "rounded-lg border-s-4 border-s-kumo-warning border border-kumo-line bg-kumo-base p-6",
35723
36006
  children: /* @__PURE__ */ jsxs("div", {
35724
36007
  className: "flex items-start gap-4",
35725
- children: [/* @__PURE__ */ jsx(Warning, { className: "h-6 w-6 text-orange-500 flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
36008
+ children: [/* @__PURE__ */ jsx(Warning, { className: "h-6 w-6 text-kumo-warning flex-shrink-0" }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
35726
36009
  className: "font-medium",
35727
36010
  children: _t4({
35728
36011
  id: "W9GZ3f",
@@ -37351,6 +37634,39 @@ function AuthorMappingStep({ authorMappings, emdashUsers, onMappingChange, onCon
37351
37634
  });
37352
37635
  }
37353
37636
 
37637
+ //#endregion
37638
+ //#region src/lib/bulk.ts
37639
+ /**
37640
+ * Concurrency-limited fan-out for bulk content actions.
37641
+ *
37642
+ * Bulk publish/draft/trash reuse the existing per-entry endpoints, so a
37643
+ * selection of N entries means N requests. Selection persists across
37644
+ * pagination, so N can grow large — an unbounded `Promise.allSettled`
37645
+ * fan-out would fire them all at once. This runs at most `concurrency`
37646
+ * requests in flight and reports which ids failed so the caller can keep
37647
+ * them selected for a retry.
37648
+ */
37649
+ /** Max in-flight requests per bulk action. */
37650
+ const BULK_CONCURRENCY = 5;
37651
+ async function runBulkAction(ids, action, concurrency = BULK_CONCURRENCY) {
37652
+ const failed = /* @__PURE__ */ new Set();
37653
+ let nextIndex = 0;
37654
+ async function drain() {
37655
+ while (nextIndex < ids.length) {
37656
+ const id = ids[nextIndex++];
37657
+ if (id === void 0) continue;
37658
+ try {
37659
+ await action(id);
37660
+ } catch {
37661
+ failed.add(id);
37662
+ }
37663
+ }
37664
+ }
37665
+ const workerCount = Math.max(1, Math.min(concurrency, ids.length));
37666
+ await Promise.all(Array.from({ length: workerCount }, () => drain()));
37667
+ return { failedIds: ids.filter((id) => failed.has(id)) };
37668
+ }
37669
+
37354
37670
  //#endregion
37355
37671
  //#region src/components/BylineFieldEditor.tsx
37356
37672
  /**
@@ -38877,27 +39193,35 @@ function CustomFieldInput({ field, value, onChange }) {
38877
39193
  //#endregion
38878
39194
  //#region src/components/users/RoleBadge.tsx
38879
39195
  /**
38880
- * Role badge component with semantic colors
39196
+ * Maps a role's semantic color name to a Kumo Badge token variant, so
39197
+ * light/dark theming comes from tokens rather than hard-coded palette classes.
39198
+ */
39199
+ const ROLE_VARIANTS = {
39200
+ gray: "neutral",
39201
+ blue: "blue",
39202
+ green: "green",
39203
+ purple: "purple",
39204
+ red: "red"
39205
+ };
39206
+ /**
39207
+ * Role badge component built on Kumo Badge semantic variants.
38881
39208
  */
38882
39209
  function RoleBadge({ role, size = "sm", showDescription = false, className }) {
38883
39210
  const { _: _t } = useLingui();
38884
39211
  const config = getRoleConfig(role);
38885
- return /* @__PURE__ */ jsxs("span", {
38886
- className: cn("inline-flex items-center rounded-full font-medium", {
38887
- sm: "px-2 py-0.5 text-xs",
38888
- md: "px-2.5 py-1 text-sm"
38889
- }[size], {
38890
- gray: "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200",
38891
- blue: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
38892
- green: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
38893
- purple: "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200",
38894
- red: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"
38895
- }[config.color], className),
39212
+ return /* @__PURE__ */ jsx("span", {
38896
39213
  title: showDescription ? void 0 : _t(config.description),
38897
- children: [_t(config.label), showDescription && /* @__PURE__ */ jsxs("span", {
38898
- className: "ms-1 opacity-75",
38899
- children: ["- ", _t(config.description)]
38900
- })]
39214
+ children: /* @__PURE__ */ jsxs(Badge, {
39215
+ variant: ROLE_VARIANTS[config.color] ?? "neutral",
39216
+ className: cn({
39217
+ sm: "text-xs",
39218
+ md: "px-2.5 py-1 text-sm"
39219
+ }[size], className),
39220
+ children: [_t(config.label), showDescription && /* @__PURE__ */ jsxs("span", {
39221
+ className: "ms-1 opacity-75",
39222
+ children: ["- ", _t(config.description)]
39223
+ })]
39224
+ })
38901
39225
  });
38902
39226
  }
38903
39227
 
@@ -39143,7 +39467,7 @@ function UserListRow({ user, onSelect }) {
39143
39467
  message: "Disabled"
39144
39468
  })]
39145
39469
  }) : /* @__PURE__ */ jsxs("span", {
39146
- className: "inline-flex items-center gap-1 text-sm text-green-600 dark:text-green-400",
39470
+ className: "inline-flex items-center gap-1 text-sm text-kumo-success",
39147
39471
  children: [/* @__PURE__ */ jsx(CheckCircle, {
39148
39472
  className: "h-3.5 w-3.5",
39149
39473
  "aria-hidden": "true"
@@ -39351,7 +39675,7 @@ function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, reco
39351
39675
  message: "Disabled"
39352
39676
  })]
39353
39677
  }) : /* @__PURE__ */ jsxs("span", {
39354
- className: "inline-flex items-center gap-1 text-sm text-green-600 dark:text-green-400",
39678
+ className: "inline-flex items-center gap-1 text-sm text-kumo-success",
39355
39679
  children: [/* @__PURE__ */ jsx(CheckCircle, {
39356
39680
  className: "h-3.5 w-3.5",
39357
39681
  "aria-hidden": "true"
@@ -39568,7 +39892,7 @@ function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, reco
39568
39892
  })
39569
39893
  }),
39570
39894
  recoverySent && /* @__PURE__ */ jsx("p", {
39571
- className: "text-xs text-green-600 dark:text-green-400 text-center",
39895
+ className: "text-xs text-kumo-success text-center",
39572
39896
  children: _t({
39573
39897
  id: "SLJUHb",
39574
39898
  message: "Recovery link sent to {0}",
@@ -39711,15 +40035,15 @@ function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onIn
39711
40035
  className: "py-4 space-y-4",
39712
40036
  children: [
39713
40037
  /* @__PURE__ */ jsxs("div", {
39714
- className: "rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 p-4",
40038
+ className: "rounded-lg border border-kumo-warning/50 bg-kumo-warning-tint p-4",
39715
40039
  children: [/* @__PURE__ */ jsx("p", {
39716
- className: "text-sm text-amber-800 dark:text-amber-200 font-medium",
40040
+ className: "text-sm text-kumo-warning font-medium",
39717
40041
  children: _t({
39718
40042
  id: "khD71f",
39719
40043
  message: "Share this link with the invited user"
39720
40044
  })
39721
40045
  }), /* @__PURE__ */ jsx("p", {
39722
- className: "text-xs text-amber-700 dark:text-amber-300 mt-1",
40046
+ className: "text-xs text-kumo-subtle mt-1",
39723
40047
  children: _t({
39724
40048
  id: "2wySqx",
39725
40049
  message: "This link expires in 7 days and can only be used once."
@@ -39739,18 +40063,18 @@ function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onIn
39739
40063
  id: "x7uIlL",
39740
40064
  message: "Copy invite link"
39741
40065
  }),
39742
- children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-green-600" }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
40066
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-kumo-success" }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
39743
40067
  })]
39744
40068
  }),
39745
40069
  copied && /* @__PURE__ */ jsx("p", {
39746
- className: "text-xs text-green-600 dark:text-green-400",
40070
+ className: "text-xs text-kumo-success",
39747
40071
  children: _t({
39748
40072
  id: "FxVG/l",
39749
40073
  message: "Copied to clipboard"
39750
40074
  })
39751
40075
  }),
39752
40076
  copyError && /* @__PURE__ */ jsx("p", {
39753
- className: "text-xs text-amber-600 dark:text-amber-400",
40077
+ className: "text-xs text-kumo-warning",
39754
40078
  children: _t({
39755
40079
  id: "6pCl1F",
39756
40080
  message: "Could not copy automatically. Please select the URL above and copy manually."
@@ -40388,6 +40712,122 @@ function ContentListPage() {
40388
40712
  });
40389
40713
  }
40390
40714
  });
40715
+ const bulkPublishMutation = useMutation({
40716
+ mutationFn: async (ids) => {
40717
+ const { failedIds } = await runBulkAction(ids, (id) => publishContent(collection, id, { locale: activeLocale }));
40718
+ return {
40719
+ total: ids.length,
40720
+ failedIds
40721
+ };
40722
+ },
40723
+ onSuccess: ({ total, failedIds }) => {
40724
+ if (failedIds.length === 0) toastManager.add({
40725
+ title: _t2({
40726
+ id: "XSnkda",
40727
+ message: "Published {total} items",
40728
+ values: { total }
40729
+ }),
40730
+ type: "success"
40731
+ });
40732
+ else toastManager.add({
40733
+ title: _t2({
40734
+ id: "pxQAFW",
40735
+ message: "Failed to publish"
40736
+ }),
40737
+ description: _t2({
40738
+ id: "u4L+qv",
40739
+ message: "{0} of {total} could not be published",
40740
+ values: {
40741
+ 0: failedIds.length,
40742
+ total
40743
+ }
40744
+ }),
40745
+ type: "error"
40746
+ });
40747
+ },
40748
+ onSettled: () => {
40749
+ queryClient.invalidateQueries({ queryKey: ["content", collection] });
40750
+ }
40751
+ });
40752
+ const bulkUnpublishMutation = useMutation({
40753
+ mutationFn: async (ids) => {
40754
+ const { failedIds } = await runBulkAction(ids, (id) => unpublishContent(collection, id, { locale: activeLocale }));
40755
+ return {
40756
+ total: ids.length,
40757
+ failedIds
40758
+ };
40759
+ },
40760
+ onSuccess: ({ total, failedIds }) => {
40761
+ if (failedIds.length === 0) toastManager.add({
40762
+ title: _t2({
40763
+ id: "IYdDk3",
40764
+ message: "Moved {total} items to draft",
40765
+ values: { total }
40766
+ }),
40767
+ type: "success"
40768
+ });
40769
+ else toastManager.add({
40770
+ title: _t2({
40771
+ id: "u2HXZY",
40772
+ message: "Failed to update"
40773
+ }),
40774
+ description: _t2({
40775
+ id: "seoGtg",
40776
+ message: "{0} of {total} could not be updated",
40777
+ values: {
40778
+ 0: failedIds.length,
40779
+ total
40780
+ }
40781
+ }),
40782
+ type: "error"
40783
+ });
40784
+ },
40785
+ onSettled: () => {
40786
+ queryClient.invalidateQueries({ queryKey: ["content", collection] });
40787
+ }
40788
+ });
40789
+ const bulkDeleteMutation = useMutation({
40790
+ mutationFn: async (ids) => {
40791
+ const { failedIds } = await runBulkAction(ids, (id) => deleteContent(collection, id));
40792
+ return {
40793
+ total: ids.length,
40794
+ failedIds
40795
+ };
40796
+ },
40797
+ onSuccess: ({ total, failedIds }) => {
40798
+ if (failedIds.length === 0) toastManager.add({
40799
+ title: _t2({
40800
+ id: "HEBFEG",
40801
+ message: "Moved {total} items to trash",
40802
+ values: { total }
40803
+ }),
40804
+ type: "success"
40805
+ });
40806
+ else toastManager.add({
40807
+ title: _t2({
40808
+ id: "92o1+U",
40809
+ message: "Failed to delete"
40810
+ }),
40811
+ description: _t2({
40812
+ id: "zu/kzk",
40813
+ message: "{0} of {total} could not be deleted",
40814
+ values: {
40815
+ 0: failedIds.length,
40816
+ total
40817
+ }
40818
+ }),
40819
+ type: "error"
40820
+ });
40821
+ },
40822
+ onSettled: () => {
40823
+ queryClient.invalidateQueries({ queryKey: ["content", collection] });
40824
+ queryClient.invalidateQueries({ queryKey: [
40825
+ "content",
40826
+ collection,
40827
+ "trash"
40828
+ ] });
40829
+ }
40830
+ });
40391
40831
  const items = React$1.useMemo(() => {
40392
40832
  return data?.pages.flatMap((page) => page.items) || [];
40393
40833
  }, [data]);
@@ -40432,7 +40872,10 @@ function ContentListPage() {
40432
40872
  authorFilter,
40433
40873
  onAuthorFilterChange: setAuthorFilter,
40434
40874
  dateFilter,
40435
- onDateFilterChange: setDateFilter
40875
+ onDateFilterChange: setDateFilter,
40876
+ onBulkPublish: (ids) => bulkPublishMutation.mutateAsync(ids).then((r) => r.failedIds),
40877
+ onBulkUnpublish: (ids) => bulkUnpublishMutation.mutateAsync(ids).then((r) => r.failedIds),
40878
+ onBulkDelete: (ids) => bulkDeleteMutation.mutateAsync(ids).then((r) => r.failedIds)
40436
40879
  });
40437
40880
  }
40438
40881
  const contentNewRoute = createRoute({
@@ -41817,6 +42260,7 @@ function normalizeAdminHref(href) {
41817
42260
  if (href === ADMIN_BASEPATH) return "/";
41818
42261
  if (href.startsWith(`${ADMIN_BASEPATH}/`)) return href.slice(14);
41819
42262
  if (href.startsWith(`${ADMIN_BASEPATH}?`) || href.startsWith(`${ADMIN_BASEPATH}#`)) return `/${href.slice(14)}`;
42263
+ if (href.startsWith("/_emdash/")) return "";
41820
42264
  return href;
41821
42265
  }
41822
42266
  function getAnchorHref(destination, routerDestination) {