@emdash-cms/admin 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{LocaleDirectionProvider-McGbBpFz.js → LocaleDirectionProvider-CzUzBk_M.js} +27 -27
- package/dist/{LocaleDirectionProvider-McGbBpFz.js.map → LocaleDirectionProvider-CzUzBk_M.js.map} +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1353 -336
- package/dist/index.js.map +1 -1
- package/dist/locales/ar/messages.mjs +1 -1
- package/dist/locales/ca/messages.mjs +1 -1
- package/dist/locales/de/messages.mjs +1 -1
- package/dist/locales/en/messages.mjs +1 -1
- package/dist/locales/en-GB/messages.mjs +1 -1
- package/dist/locales/es-419/messages.mjs +1 -1
- package/dist/locales/es-ES/messages.mjs +1 -1
- package/dist/locales/eu/messages.mjs +1 -1
- package/dist/locales/fa/messages.mjs +1 -1
- package/dist/locales/fr/messages.mjs +1 -1
- package/dist/locales/hu/messages.mjs +1 -1
- package/dist/locales/id/messages.mjs +1 -1
- package/dist/locales/index.js +1 -1
- package/dist/locales/ja/messages.mjs +1 -1
- package/dist/locales/ko/messages.mjs +1 -1
- package/dist/locales/nb/messages.mjs +1 -1
- package/dist/locales/nl/messages.mjs +1 -1
- package/dist/locales/pl/messages.mjs +1 -1
- package/dist/locales/pseudo/messages.mjs +1 -1
- package/dist/locales/pt-BR/messages.mjs +1 -1
- package/dist/locales/sr-Latn/messages.mjs +1 -1
- package/dist/locales/sv/messages.mjs +1 -1
- package/dist/locales/th/messages.mjs +1 -1
- package/dist/locales/tr/messages.mjs +1 -1
- package/dist/locales/uk/messages.mjs +1 -1
- package/dist/locales/zh-CN/messages.mjs +1 -1
- package/dist/locales/zh-TW/messages.mjs +1 -1
- package/dist/messages-4E6Xx17o.js +6 -0
- package/dist/messages-4E6Xx17o.js.map +1 -0
- package/dist/messages-BAcc2d5l.js +6 -0
- package/dist/messages-BAcc2d5l.js.map +1 -0
- package/dist/messages-BKn4pcjV.js +6 -0
- package/dist/messages-BKn4pcjV.js.map +1 -0
- package/dist/messages-BbxsgV1o.js +6 -0
- package/dist/messages-BbxsgV1o.js.map +1 -0
- package/dist/messages-Bq0YC7aR.js +6 -0
- package/dist/messages-Bq0YC7aR.js.map +1 -0
- package/dist/messages-C5xrZ8Mt.js +6 -0
- package/dist/messages-C5xrZ8Mt.js.map +1 -0
- package/dist/messages-CK9KaPjU.js +6 -0
- package/dist/messages-CK9KaPjU.js.map +1 -0
- package/dist/messages-CQk8YErW.js +6 -0
- package/dist/messages-CQk8YErW.js.map +1 -0
- package/dist/messages-CSfIGWK3.js +6 -0
- package/dist/messages-CSfIGWK3.js.map +1 -0
- package/dist/messages-CYswqaSQ.js +6 -0
- package/dist/messages-CYswqaSQ.js.map +1 -0
- package/dist/messages-Cjo7q43O.js +6 -0
- package/dist/messages-Cjo7q43O.js.map +1 -0
- package/dist/messages-Cnh1qPI1.js +6 -0
- package/dist/messages-Cnh1qPI1.js.map +1 -0
- package/dist/messages-Cu49SHtz.js +6 -0
- package/dist/messages-Cu49SHtz.js.map +1 -0
- package/dist/messages-DJG5FSHH.js +6 -0
- package/dist/messages-DJG5FSHH.js.map +1 -0
- package/dist/messages-DhNXuJB7.js +6 -0
- package/dist/messages-DhNXuJB7.js.map +1 -0
- package/dist/messages-DiCVcFcv.js +6 -0
- package/dist/messages-DiCVcFcv.js.map +1 -0
- package/dist/messages-DivwCvnm.js +6 -0
- package/dist/messages-DivwCvnm.js.map +1 -0
- package/dist/messages-DknOk2F9.js +6 -0
- package/dist/messages-DknOk2F9.js.map +1 -0
- package/dist/messages-DtOKaZNy.js +6 -0
- package/dist/messages-DtOKaZNy.js.map +1 -0
- package/dist/messages-DwLBUVeM.js +6 -0
- package/dist/messages-DwLBUVeM.js.map +1 -0
- package/dist/messages-DwSraJxw.js +6 -0
- package/dist/messages-DwSraJxw.js.map +1 -0
- package/dist/messages-Qm7DJ8iu.js +6 -0
- package/dist/messages-Qm7DJ8iu.js.map +1 -0
- package/dist/messages-WBTztu_7.js +6 -0
- package/dist/messages-WBTztu_7.js.map +1 -0
- package/dist/messages-WqjpUMW1.js +6 -0
- package/dist/messages-WqjpUMW1.js.map +1 -0
- package/dist/messages-XOyOBv6J.js +6 -0
- package/dist/messages-XOyOBv6J.js.map +1 -0
- package/dist/messages-gHwLtggX.js +6 -0
- package/dist/messages-gHwLtggX.js.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +4 -4
- package/dist/messages-30qbnmRx.js +0 -6
- package/dist/messages-30qbnmRx.js.map +0 -1
- package/dist/messages-Axst6gLr.js +0 -6
- package/dist/messages-Axst6gLr.js.map +0 -1
- package/dist/messages-B-bWgBX8.js +0 -6
- package/dist/messages-B-bWgBX8.js.map +0 -1
- package/dist/messages-B0QaP8co.js +0 -6
- package/dist/messages-B0QaP8co.js.map +0 -1
- package/dist/messages-BGf8F1lR.js +0 -6
- package/dist/messages-BGf8F1lR.js.map +0 -1
- package/dist/messages-BMgCc4cZ.js +0 -6
- package/dist/messages-BMgCc4cZ.js.map +0 -1
- package/dist/messages-BNhQh9T8.js +0 -6
- package/dist/messages-BNhQh9T8.js.map +0 -1
- package/dist/messages-BR-TSB_9.js +0 -6
- package/dist/messages-BR-TSB_9.js.map +0 -1
- package/dist/messages-BSqQiKKo.js +0 -6
- package/dist/messages-BSqQiKKo.js.map +0 -1
- package/dist/messages-Be0xmdDi.js +0 -6
- package/dist/messages-Be0xmdDi.js.map +0 -1
- package/dist/messages-BkOa_w3b.js +0 -6
- package/dist/messages-BkOa_w3b.js.map +0 -1
- package/dist/messages-Bqzqrw4i.js +0 -6
- package/dist/messages-Bqzqrw4i.js.map +0 -1
- package/dist/messages-CBWpqPBL.js +0 -6
- package/dist/messages-CBWpqPBL.js.map +0 -1
- package/dist/messages-CIkqn_8n.js +0 -6
- package/dist/messages-CIkqn_8n.js.map +0 -1
- package/dist/messages-CMbNQ7lX.js +0 -6
- package/dist/messages-CMbNQ7lX.js.map +0 -1
- package/dist/messages-CSAH0lQI.js +0 -6
- package/dist/messages-CSAH0lQI.js.map +0 -1
- package/dist/messages-CXUOdBIL.js +0 -6
- package/dist/messages-CXUOdBIL.js.map +0 -1
- package/dist/messages-CnNncIUV.js +0 -6
- package/dist/messages-CnNncIUV.js.map +0 -1
- package/dist/messages-CpRrAHoJ.js +0 -6
- package/dist/messages-CpRrAHoJ.js.map +0 -1
- package/dist/messages-D0KmmMuH.js +0 -6
- package/dist/messages-D0KmmMuH.js.map +0 -1
- package/dist/messages-D6A5PrwK.js +0 -6
- package/dist/messages-D6A5PrwK.js.map +0 -1
- package/dist/messages-DD28du-X.js +0 -6
- package/dist/messages-DD28du-X.js.map +0 -1
- package/dist/messages-DWuyZMXt.js +0 -6
- package/dist/messages-DWuyZMXt.js.map +0 -1
- package/dist/messages-JApRIdzY.js +0 -6
- package/dist/messages-JApRIdzY.js.map +0 -1
- package/dist/messages-l-TFOm7q.js +0 -6
- package/dist/messages-l-TFOm7q.js.map +0 -1
- package/dist/messages-lfFNZ58n.js +0 -6
- package/dist/messages-lfFNZ58n.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as fetchPlugins, c as updatePluginSettings, d as fetchAuthMode, f as fetchManifest, i as fetchPluginSettings, l as API_BASE, m as throwResponseError, n as enablePlugin, p as parseApiResponse, r as fetchPlugin, s as setPluginMcpEnabled, t as disablePlugin, u as apiFetch } from "./plugins-CQAV8Ap0.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-
|
|
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-CzUzBk_M.js";
|
|
3
3
|
import "./locales/index.js";
|
|
4
4
|
import { Autocomplete, Badge, Banner, Button, Checkbox, ClipboardText, Collapsible, Combobox, CommandPalette, Dialog, DropdownMenu, Input, InputArea, Label, LayerCard, LinkButton, LinkProvider, Loader, Popover, Select, Sidebar, Sidebar as KumoSidebar, SkeletonLine, Switch, Tabs, Text, Toast, Toasty, Tooltip, TooltipProvider, buttonVariants, useKumoToastManager, useSidebar, useSidebar as useSidebar$1 } from "@cloudflare/kumo";
|
|
5
5
|
import { i18n } from "@lingui/core";
|
|
@@ -13,11 +13,12 @@ import { Dialog as Dialog$1 } from "@cloudflare/kumo/primitives";
|
|
|
13
13
|
import { Archive, ArrowCounterClockwise, ArrowDown, ArrowRightIcon, ArrowSquareOut, ArrowUUpLeft, ArrowUUpRight, ArrowUp, ArrowsClockwise, ArrowsInSimple, ArrowsLeftRight, ArrowsOutSimple, Bell, BookOpen, BracketsAngle, BracketsCurly, Browser, Calendar, CalendarBlank, CardsThree, CaretDown, CaretRightIcon, CaretUp, CaretUpDown, ChartBar, ChartLine, Chats, Check, CheckCircle, CircleDashed, CircleNotch, ClockCounterClockwise, Cloud, CloudArrowUp, Code, CodeBlock, Columns, ColumnsPlusLeft, ColumnsPlusRight, Copy, Crop, Cube, Database, DeviceMobile, DotsSixVertical, Download, DownloadSimple, Envelope, EnvelopeSimple, Eye, EyeSlash, Faders, File, FileArrowDown, FileText, Files, FloppyDisk, Folder, FolderOpen, Folders, Gear, GithubLogo, Globe, GlobeSimple, GridFour, HardDrive, Hash, IdentificationCard, Image as Image$1, ImageBroken, ImageSquare, Images, ImagesSquare, Info, Key, Link as Link$2, LinkBreak, LinkSimple, List, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Medal, Minus, Monitor, Moon, Newspaper, Palette, PaperPlaneTilt, Paperclip, Paragraph, Path, Pencil, PencilSimple, Plug, PlugsConnected, Plus, Prohibit, PuzzlePiece, Quotes, Robot, Rows, RowsPlusBottom, RowsPlusTop, Ruler, ShareNetwork, Shield, ShieldCheck, ShieldWarning, SignOut, Signature, SlidersHorizontal, Sparkle, SquaresFour, Stack, Star, Storefront, Sun, Table, Tag, TextAlignCenter, TextAlignLeft, TextAlignRight, TextB, TextH, TextHFive, TextHFour, TextHOne, TextHSix, 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
|
-
import { DndContext, DragOverlay, KeyboardSensor, PointerSensor, closestCenter, rectIntersection, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
17
|
-
import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
16
|
+
import { DndContext, DragOverlay, KeyboardSensor, MeasuringStrategy, PointerSensor, closestCenter, rectIntersection, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
17
|
+
import { SortableContext, arrayMove, rectSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
18
18
|
import { CSS } from "@dnd-kit/utilities";
|
|
19
|
+
import { EditorContent, Node as Node$1, NodeViewContent, NodeViewWrapper, ReactNodeViewRenderer, mergeAttributes, useEditor, useEditorState } from "@tiptap/react";
|
|
19
20
|
import { Popover as Popover$1 } from "@cloudflare/kumo/primitives/popover";
|
|
20
|
-
import { Extension, InputRule, Node as Node$
|
|
21
|
+
import { Extension, InputRule, Node as Node$2, PasteRule, escapeForRegEx, mergeAttributes as mergeAttributes$1 } from "@tiptap/core";
|
|
21
22
|
import CharacterCount from "@tiptap/extension-character-count";
|
|
22
23
|
import Focus from "@tiptap/extension-focus";
|
|
23
24
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
@@ -29,7 +30,6 @@ import TextAlign from "@tiptap/extension-text-align";
|
|
|
29
30
|
import Typography from "@tiptap/extension-typography";
|
|
30
31
|
import { AllSelection, NodeSelection, Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
31
32
|
import { CellSelection } from "@tiptap/pm/tables";
|
|
32
|
-
import { EditorContent, Node as Node$2, NodeViewContent, NodeViewWrapper, ReactNodeViewRenderer, mergeAttributes as mergeAttributes$1, useEditor, useEditorState } from "@tiptap/react";
|
|
33
33
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
34
34
|
import StarterKit from "@tiptap/starter-kit";
|
|
35
35
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
@@ -3673,7 +3673,7 @@ function probeImageDimensions(url, errorMessage) {
|
|
|
3673
3673
|
img.src = url;
|
|
3674
3674
|
});
|
|
3675
3675
|
}
|
|
3676
|
-
function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "image/", mimeTypeFilters, fieldId, title: providedTitle, hideUrlInput = false, mediaKind = "image", localOnly = false }) {
|
|
3676
|
+
function MediaPickerModal({ open, onOpenChange, onSelect, multiple = false, onSelectMany, mimeTypeFilter = "image/", mimeTypeFilters, fieldId, title: providedTitle, hideUrlInput = false, mediaKind = "image", localOnly = false }) {
|
|
3677
3677
|
const { _: _t } = useLingui();
|
|
3678
3678
|
const isFileKind = mediaKind === "file";
|
|
3679
3679
|
const filters = React$1.useMemo(() => {
|
|
@@ -3704,6 +3704,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3704
3704
|
const EmptyStateIcon = isFileKind ? Paperclip : Image$1;
|
|
3705
3705
|
const queryClient = useQueryClient();
|
|
3706
3706
|
const [selectedItem, setSelectedItem] = React$1.useState(null);
|
|
3707
|
+
const [selectedItems, setSelectedItems] = React$1.useState([]);
|
|
3707
3708
|
const [activeProvider, setActiveProvider] = React$1.useState("local");
|
|
3708
3709
|
const [searchQuery, setSearchQuery] = React$1.useState("");
|
|
3709
3710
|
const debouncedSearch = useDebouncedValue$1(searchQuery, 300);
|
|
@@ -3715,6 +3716,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3715
3716
|
React$1.useEffect(() => {
|
|
3716
3717
|
if (open) {
|
|
3717
3718
|
setSelectedItem(null);
|
|
3719
|
+
setSelectedItems([]);
|
|
3718
3720
|
setActiveProvider("local");
|
|
3719
3721
|
setSearchQuery("");
|
|
3720
3722
|
setImageUrl("");
|
|
@@ -3787,7 +3789,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3787
3789
|
mutationFn: (file) => uploadMedia(file, { fieldId }),
|
|
3788
3790
|
onSuccess: (item) => {
|
|
3789
3791
|
queryClient.invalidateQueries({ queryKey: ["media"] });
|
|
3790
|
-
|
|
3792
|
+
if (multiple) setSelectedItems((prev) => [...prev, {
|
|
3793
|
+
providerId: "local",
|
|
3794
|
+
item
|
|
3795
|
+
}]);
|
|
3796
|
+
else setSelectedItem({
|
|
3791
3797
|
providerId: "local",
|
|
3792
3798
|
item
|
|
3793
3799
|
});
|
|
@@ -3801,7 +3807,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3801
3807
|
mutationFn: ({ providerId, file }) => uploadToProvider(providerId, file),
|
|
3802
3808
|
onSuccess: (item, { providerId }) => {
|
|
3803
3809
|
queryClient.invalidateQueries({ queryKey: ["provider-media", providerId] });
|
|
3804
|
-
|
|
3810
|
+
if (multiple) setSelectedItems((prev) => [...prev, {
|
|
3811
|
+
providerId,
|
|
3812
|
+
item
|
|
3813
|
+
}]);
|
|
3814
|
+
else setSelectedItem({
|
|
3805
3815
|
providerId,
|
|
3806
3816
|
item
|
|
3807
3817
|
});
|
|
@@ -3875,19 +3885,39 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3875
3885
|
}
|
|
3876
3886
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
3877
3887
|
};
|
|
3888
|
+
const toMediaItem = (selected) => {
|
|
3889
|
+
if (selected.providerId === "local") return selected.item;
|
|
3890
|
+
const providerItem = selected.item;
|
|
3891
|
+
const dims = providerDimensions[providerItem.id];
|
|
3892
|
+
const itemWithDims = dims ? {
|
|
3893
|
+
...providerItem,
|
|
3894
|
+
width: providerItem.width ?? dims.width,
|
|
3895
|
+
height: providerItem.height ?? dims.height
|
|
3896
|
+
} : providerItem;
|
|
3897
|
+
return providerItemToMediaItem(selected.providerId, itemWithDims);
|
|
3898
|
+
};
|
|
3899
|
+
const isItemSelected = (providerId, id) => multiple ? selectedItems.some((s) => s.providerId === providerId && s.item.id === id) : selectedItem?.providerId === providerId && selectedItem.item.id === id;
|
|
3900
|
+
const handleItemClick = (providerId, item) => {
|
|
3901
|
+
if (multiple) setSelectedItems((prev) => prev.some((s) => s.providerId === providerId && s.item.id === item.id) ? prev.filter((s) => !(s.providerId === providerId && s.item.id === item.id)) : [...prev, {
|
|
3902
|
+
providerId,
|
|
3903
|
+
item
|
|
3904
|
+
}]);
|
|
3905
|
+
else setSelectedItem({
|
|
3906
|
+
providerId,
|
|
3907
|
+
item
|
|
3908
|
+
});
|
|
3909
|
+
};
|
|
3878
3910
|
const handleConfirm = () => {
|
|
3911
|
+
if (multiple) {
|
|
3912
|
+
if (selectedItems.length === 0) return;
|
|
3913
|
+
onSelectMany?.(selectedItems.map(toMediaItem));
|
|
3914
|
+
onOpenChange(false);
|
|
3915
|
+
setSelectedItems([]);
|
|
3916
|
+
setImageUrl("");
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3879
3919
|
if (selectedItem) {
|
|
3880
|
-
|
|
3881
|
-
else {
|
|
3882
|
-
const providerItem = selectedItem.item;
|
|
3883
|
-
const dims = providerDimensions[providerItem.id];
|
|
3884
|
-
const itemWithDims = dims ? {
|
|
3885
|
-
...providerItem,
|
|
3886
|
-
width: providerItem.width ?? dims.width,
|
|
3887
|
-
height: providerItem.height ?? dims.height
|
|
3888
|
-
} : providerItem;
|
|
3889
|
-
onSelect(providerItemToMediaItem(selectedItem.providerId, itemWithDims));
|
|
3890
|
-
}
|
|
3920
|
+
onSelect(toMediaItem(selectedItem));
|
|
3891
3921
|
onOpenChange(false);
|
|
3892
3922
|
setSelectedItem(null);
|
|
3893
3923
|
setImageUrl("");
|
|
@@ -3896,6 +3926,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3896
3926
|
const handleClose = () => {
|
|
3897
3927
|
onOpenChange(false);
|
|
3898
3928
|
setSelectedItem(null);
|
|
3929
|
+
setSelectedItems([]);
|
|
3899
3930
|
setImageUrl("");
|
|
3900
3931
|
setUrlError(null);
|
|
3901
3932
|
};
|
|
@@ -3934,7 +3965,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3934
3965
|
id: "iC8xDQ",
|
|
3935
3966
|
message: "Failed to load image"
|
|
3936
3967
|
}));
|
|
3937
|
-
|
|
3968
|
+
const externalItem = {
|
|
3938
3969
|
id: "",
|
|
3939
3970
|
filename: url.pathname.split("/").pop() || "external-image",
|
|
3940
3971
|
mimeType: sniffedMime,
|
|
@@ -3944,7 +3975,9 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3944
3975
|
width: dimensions.width,
|
|
3945
3976
|
height: dimensions.height,
|
|
3946
3977
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3947
|
-
}
|
|
3978
|
+
};
|
|
3979
|
+
if (multiple) onSelectMany?.([externalItem]);
|
|
3980
|
+
else onSelect(externalItem);
|
|
3948
3981
|
onOpenChange(false);
|
|
3949
3982
|
setImageUrl("");
|
|
3950
3983
|
} catch {
|
|
@@ -4088,6 +4121,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
4088
4121
|
onClick: () => {
|
|
4089
4122
|
setActiveProvider(tab.id);
|
|
4090
4123
|
setSelectedItem(null);
|
|
4124
|
+
setSelectedItems([]);
|
|
4091
4125
|
setSearchQuery("");
|
|
4092
4126
|
},
|
|
4093
4127
|
className: cn("flex items-center gap-2 px-4 h-9 text-sm font-medium rounded-md transition-colors whitespace-nowrap", activeProvider === tab.id ? "bg-kumo-brand text-white" : "bg-kumo-tint hover:bg-kumo-tint/80 text-kumo-subtle"),
|
|
@@ -4208,24 +4242,26 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
4208
4242
|
}),
|
|
4209
4243
|
children: activeProvider === "local" ? items.map((item) => /* @__PURE__ */ jsx(MediaPickerItem, {
|
|
4210
4244
|
item,
|
|
4211
|
-
selected:
|
|
4212
|
-
onClick: () =>
|
|
4213
|
-
providerId: "local",
|
|
4214
|
-
item
|
|
4215
|
-
}),
|
|
4245
|
+
selected: isItemSelected("local", item.id),
|
|
4246
|
+
onClick: () => handleItemClick("local", item),
|
|
4216
4247
|
onDoubleClick: () => {
|
|
4248
|
+
if (multiple) {
|
|
4249
|
+
handleItemClick("local", item);
|
|
4250
|
+
return;
|
|
4251
|
+
}
|
|
4217
4252
|
onSelect(item);
|
|
4218
4253
|
onOpenChange(false);
|
|
4219
4254
|
},
|
|
4220
4255
|
onDimensionsDetected: handleDimensionsDetected
|
|
4221
4256
|
}, item.id)) : items.map((item) => /* @__PURE__ */ jsx(ProviderMediaItem, {
|
|
4222
4257
|
item,
|
|
4223
|
-
selected:
|
|
4224
|
-
onClick: () =>
|
|
4225
|
-
providerId: activeProvider,
|
|
4226
|
-
item
|
|
4227
|
-
}),
|
|
4258
|
+
selected: isItemSelected(activeProvider, item.id),
|
|
4259
|
+
onClick: () => handleItemClick(activeProvider, item),
|
|
4228
4260
|
onDoubleClick: () => {
|
|
4261
|
+
if (multiple) {
|
|
4262
|
+
handleItemClick(activeProvider, item);
|
|
4263
|
+
return;
|
|
4264
|
+
}
|
|
4229
4265
|
const dims = providerDimensions[item.id];
|
|
4230
4266
|
onSelect(providerItemToMediaItem(activeProvider, dims ? {
|
|
4231
4267
|
...item,
|
|
@@ -4266,7 +4302,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
4266
4302
|
children: [
|
|
4267
4303
|
/* @__PURE__ */ jsx("div", {
|
|
4268
4304
|
className: "flex-1 text-sm text-kumo-subtle",
|
|
4269
|
-
children:
|
|
4305
|
+
children: multiple ? selectedItems.length > 0 && /* @__PURE__ */ jsx("span", { children: i18n._({
|
|
4306
|
+
id: "agSO3s",
|
|
4307
|
+
message: "{0, plural, one {# item selected} other {# items selected}}",
|
|
4308
|
+
values: { 0: selectedItems.length }
|
|
4309
|
+
}) }) : selectedItem && /* @__PURE__ */ jsxs("span", { children: [
|
|
4270
4310
|
_t({
|
|
4271
4311
|
id: "SVRHAR",
|
|
4272
4312
|
message: "Selected:"
|
|
@@ -4293,7 +4333,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
4293
4333
|
}),
|
|
4294
4334
|
/* @__PURE__ */ jsx(Button, {
|
|
4295
4335
|
onClick: handleConfirm,
|
|
4296
|
-
disabled: !selectedItem,
|
|
4336
|
+
disabled: multiple ? selectedItems.length === 0 : !selectedItem,
|
|
4297
4337
|
children: _t({
|
|
4298
4338
|
id: "S8Yqbl",
|
|
4299
4339
|
message: "Insert"
|
|
@@ -4732,7 +4772,7 @@ function findCurrentHeading(headings, cursorPos) {
|
|
|
4732
4772
|
/**
|
|
4733
4773
|
* Document outline component showing heading tree structure
|
|
4734
4774
|
*/
|
|
4735
|
-
function DocumentOutline({ editor, className }) {
|
|
4775
|
+
function DocumentOutline({ editor, className, reserveHeaderEnd = false }) {
|
|
4736
4776
|
const { _: _t } = useLingui();
|
|
4737
4777
|
const [isExpanded, setIsExpanded] = React$1.useState(true);
|
|
4738
4778
|
const [headings, setHeadings] = React$1.useState([]);
|
|
@@ -4774,7 +4814,7 @@ function DocumentOutline({ editor, className }) {
|
|
|
4774
4814
|
variant: "ghost",
|
|
4775
4815
|
className: "relative justify-between",
|
|
4776
4816
|
style: {
|
|
4777
|
-
width: "calc(100% + 1.5rem)",
|
|
4817
|
+
width: reserveHeaderEnd ? "calc(100% - 1.5rem)" : "calc(100% + 1.5rem)",
|
|
4778
4818
|
insetInlineStart: "-0.75rem"
|
|
4779
4819
|
}
|
|
4780
4820
|
}),
|
|
@@ -4815,6 +4855,542 @@ function DocumentOutline({ editor, className }) {
|
|
|
4815
4855
|
});
|
|
4816
4856
|
}
|
|
4817
4857
|
|
|
4858
|
+
//#endregion
|
|
4859
|
+
//#region src/components/editor/GalleryNode.tsx
|
|
4860
|
+
/**
|
|
4861
|
+
* Gallery Node for TipTap
|
|
4862
|
+
*
|
|
4863
|
+
* Node view for the Portable Text `gallery` block (grid of images with
|
|
4864
|
+
* optional per-image captions and a column count). Provides a WYSIWYG grid
|
|
4865
|
+
* preview, selection state, and a settings button that opens the gallery
|
|
4866
|
+
* detail panel in the content sidebar (same wiring as ImageNode).
|
|
4867
|
+
*/
|
|
4868
|
+
/** Resolve the admin preview URL for a gallery image. */
|
|
4869
|
+
function galleryImageUrl(image) {
|
|
4870
|
+
if (image.asset.url) return image.asset.url;
|
|
4871
|
+
if (image.asset._ref) return `/_emdash/api/media/file/${encodeURIComponent(image.asset._ref)}`;
|
|
4872
|
+
return "";
|
|
4873
|
+
}
|
|
4874
|
+
function GalleryNodeView({ node, updateAttributes, selected, deleteNode, editor, getPos }) {
|
|
4875
|
+
const { _: _t } = useLingui();
|
|
4876
|
+
const sidebarOpenRef = React$1.useRef(false);
|
|
4877
|
+
const images = node.attrs.images ?? [];
|
|
4878
|
+
const columns = typeof node.attrs.columns === "number" ? node.attrs.columns : 3;
|
|
4879
|
+
const getAttrs = () => ({
|
|
4880
|
+
images: node.attrs.images ?? [],
|
|
4881
|
+
columns: typeof node.attrs.columns === "number" ? node.attrs.columns : void 0
|
|
4882
|
+
});
|
|
4883
|
+
const openSidebar = (selectedImageKey) => {
|
|
4884
|
+
const onOpen = editor.storage.gallery?.onOpenBlockSidebar;
|
|
4885
|
+
if (onOpen) {
|
|
4886
|
+
sidebarOpenRef.current = true;
|
|
4887
|
+
onOpen({
|
|
4888
|
+
type: "gallery",
|
|
4889
|
+
attrs: {
|
|
4890
|
+
...getAttrs(),
|
|
4891
|
+
selectedImageKey,
|
|
4892
|
+
nodeKey: String(getPos?.() ?? "")
|
|
4893
|
+
},
|
|
4894
|
+
onUpdate: (attrs) => updateAttributes(attrs),
|
|
4895
|
+
onReplace: (attrs) => updateAttributes(attrs),
|
|
4896
|
+
onDelete: () => deleteNode(),
|
|
4897
|
+
onClose: () => {
|
|
4898
|
+
sidebarOpenRef.current = false;
|
|
4899
|
+
}
|
|
4900
|
+
});
|
|
4901
|
+
}
|
|
4902
|
+
};
|
|
4903
|
+
const closeSidebar = () => {
|
|
4904
|
+
if (!sidebarOpenRef.current) return;
|
|
4905
|
+
const onClose = editor.storage.gallery?.onCloseBlockSidebar;
|
|
4906
|
+
if (onClose) {
|
|
4907
|
+
onClose();
|
|
4908
|
+
sidebarOpenRef.current = false;
|
|
4909
|
+
}
|
|
4910
|
+
};
|
|
4911
|
+
const toggleSidebar = () => {
|
|
4912
|
+
if (sidebarOpenRef.current) closeSidebar();
|
|
4913
|
+
else openSidebar();
|
|
4914
|
+
};
|
|
4915
|
+
React$1.useEffect(() => {
|
|
4916
|
+
if (!selected) closeSidebar();
|
|
4917
|
+
}, [selected]);
|
|
4918
|
+
return /* @__PURE__ */ jsxs(NodeViewWrapper, {
|
|
4919
|
+
className: cn("relative my-4 group", selected && "ring-2 ring-kumo-brand ring-offset-2 rounded-lg"),
|
|
4920
|
+
children: [images.length === 0 ? /* @__PURE__ */ jsx(Button, {
|
|
4921
|
+
type: "button",
|
|
4922
|
+
variant: "outline",
|
|
4923
|
+
className: "mt-2 w-full h-32 justify-center border-dashed",
|
|
4924
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4925
|
+
onClick: () => openSidebar(),
|
|
4926
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
4927
|
+
className: "flex flex-col items-center gap-2 text-kumo-subtle",
|
|
4928
|
+
children: [/* @__PURE__ */ jsx(Images, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", {
|
|
4929
|
+
className: "text-sm",
|
|
4930
|
+
children: _t({
|
|
4931
|
+
id: "Bk1Tv6",
|
|
4932
|
+
message: "Empty gallery — open settings to add images"
|
|
4933
|
+
})
|
|
4934
|
+
})]
|
|
4935
|
+
})
|
|
4936
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
4937
|
+
className: "grid gap-2 rounded-lg",
|
|
4938
|
+
style: { gridTemplateColumns: `repeat(${Math.max(1, columns)}, 1fr)` },
|
|
4939
|
+
children: images.map((image, index) => /* @__PURE__ */ jsxs("figure", {
|
|
4940
|
+
className: "m-0",
|
|
4941
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
4942
|
+
type: "button",
|
|
4943
|
+
className: "block w-full cursor-pointer",
|
|
4944
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4945
|
+
onClick: (e) => {
|
|
4946
|
+
e.stopPropagation();
|
|
4947
|
+
openSidebar(image._key);
|
|
4948
|
+
},
|
|
4949
|
+
"aria-label": _t({
|
|
4950
|
+
id: "FjJx2y",
|
|
4951
|
+
message: "Edit image {0}",
|
|
4952
|
+
values: { 0: index + 1 }
|
|
4953
|
+
}),
|
|
4954
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
4955
|
+
src: galleryImageUrl(image),
|
|
4956
|
+
alt: image.alt || "",
|
|
4957
|
+
className: "w-full aspect-square object-cover rounded-md border",
|
|
4958
|
+
draggable: false
|
|
4959
|
+
})
|
|
4960
|
+
}), image.caption && /* @__PURE__ */ jsx("figcaption", {
|
|
4961
|
+
className: "text-xs text-kumo-subtle mt-1 text-center truncate",
|
|
4962
|
+
children: image.caption
|
|
4963
|
+
})]
|
|
4964
|
+
}, image._key))
|
|
4965
|
+
}), selected && /* @__PURE__ */ jsxs("div", {
|
|
4966
|
+
className: "absolute top-2 end-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
4967
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
4968
|
+
type: "button",
|
|
4969
|
+
variant: "secondary",
|
|
4970
|
+
shape: "square",
|
|
4971
|
+
className: "h-8 w-8",
|
|
4972
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4973
|
+
onClick: toggleSidebar,
|
|
4974
|
+
title: _t({
|
|
4975
|
+
id: "VmtOUn",
|
|
4976
|
+
message: "Gallery settings"
|
|
4977
|
+
}),
|
|
4978
|
+
"aria-label": _t({
|
|
4979
|
+
id: "VmtOUn",
|
|
4980
|
+
message: "Gallery settings"
|
|
4981
|
+
}),
|
|
4982
|
+
children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4" })
|
|
4983
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
4984
|
+
type: "button",
|
|
4985
|
+
variant: "destructive",
|
|
4986
|
+
shape: "square",
|
|
4987
|
+
className: "h-8 w-8",
|
|
4988
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4989
|
+
onClick: () => deleteNode(),
|
|
4990
|
+
title: _t({
|
|
4991
|
+
id: "HjItFk",
|
|
4992
|
+
message: "Delete gallery"
|
|
4993
|
+
}),
|
|
4994
|
+
"aria-label": _t({
|
|
4995
|
+
id: "HjItFk",
|
|
4996
|
+
message: "Delete gallery"
|
|
4997
|
+
}),
|
|
4998
|
+
children: /* @__PURE__ */ jsx(Trash, { className: "h-4 w-4" })
|
|
4999
|
+
})]
|
|
5000
|
+
})]
|
|
5001
|
+
});
|
|
5002
|
+
}
|
|
5003
|
+
const GalleryExtension = Node$1.create({
|
|
5004
|
+
name: "gallery",
|
|
5005
|
+
group: "block",
|
|
5006
|
+
atom: true,
|
|
5007
|
+
draggable: true,
|
|
5008
|
+
addStorage() {
|
|
5009
|
+
return {
|
|
5010
|
+
onOpenBlockSidebar: null,
|
|
5011
|
+
onCloseBlockSidebar: null
|
|
5012
|
+
};
|
|
5013
|
+
},
|
|
5014
|
+
addAttributes() {
|
|
5015
|
+
return {
|
|
5016
|
+
images: { default: [] },
|
|
5017
|
+
columns: { default: null }
|
|
5018
|
+
};
|
|
5019
|
+
},
|
|
5020
|
+
parseHTML() {
|
|
5021
|
+
return [{ tag: "div[data-type=\"gallery\"]" }];
|
|
5022
|
+
},
|
|
5023
|
+
renderHTML() {
|
|
5024
|
+
return ["div", { "data-type": "gallery" }];
|
|
5025
|
+
},
|
|
5026
|
+
addNodeView() {
|
|
5027
|
+
return ReactNodeViewRenderer(GalleryNodeView);
|
|
5028
|
+
},
|
|
5029
|
+
addCommands() {
|
|
5030
|
+
return { setGallery: (options) => ({ commands }) => {
|
|
5031
|
+
return commands.insertContent({
|
|
5032
|
+
type: this.name,
|
|
5033
|
+
attrs: options
|
|
5034
|
+
});
|
|
5035
|
+
} };
|
|
5036
|
+
}
|
|
5037
|
+
});
|
|
5038
|
+
|
|
5039
|
+
//#endregion
|
|
5040
|
+
//#region src/components/editor/GalleryDetailPanel.tsx
|
|
5041
|
+
/**
|
|
5042
|
+
* Gallery Detail Panel for Editor
|
|
5043
|
+
*
|
|
5044
|
+
* Sidebar panel for editing a gallery block: add images (multi-select media
|
|
5045
|
+
* picker), remove, drag-and-drop reorder, per-image alt/caption, and column
|
|
5046
|
+
* count. Changes apply immediately via onUpdate (reordering is inherently
|
|
5047
|
+
* live, so the whole panel follows suit instead of a save-button form).
|
|
5048
|
+
*/
|
|
5049
|
+
function generateKey$1() {
|
|
5050
|
+
return Math.random().toString(36).substring(2, 11);
|
|
5051
|
+
}
|
|
5052
|
+
/** Map a picked MediaItem to the gallery's Portable Text image shape. */
|
|
5053
|
+
function mediaItemToGalleryImage(item) {
|
|
5054
|
+
return {
|
|
5055
|
+
_type: "image",
|
|
5056
|
+
_key: generateKey$1(),
|
|
5057
|
+
asset: {
|
|
5058
|
+
_type: "reference",
|
|
5059
|
+
_ref: item.id,
|
|
5060
|
+
url: item.url,
|
|
5061
|
+
provider: item.provider && item.provider !== "local" ? item.provider : void 0
|
|
5062
|
+
},
|
|
5063
|
+
alt: item.alt || "",
|
|
5064
|
+
width: item.width,
|
|
5065
|
+
height: item.height,
|
|
5066
|
+
blurhash: item.blurhash ?? metaString(item.meta, "blurhash"),
|
|
5067
|
+
dominantColor: item.dominantColor ?? metaString(item.meta, "dominantColor")
|
|
5068
|
+
};
|
|
5069
|
+
}
|
|
5070
|
+
function GalleryDetailPanel({ attributes, onUpdate, onDelete, onClose, inline = false }) {
|
|
5071
|
+
const { _: _t } = useLingui();
|
|
5072
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));
|
|
5073
|
+
const [showMediaPicker, setShowMediaPicker] = React$1.useState(false);
|
|
5074
|
+
const selectedImageKey = attributes.selectedImageKey;
|
|
5075
|
+
const nodeKey = attributes.nodeKey;
|
|
5076
|
+
const [selectedKey, setSelectedKey] = React$1.useState(selectedImageKey ?? null);
|
|
5077
|
+
React$1.useEffect(() => {
|
|
5078
|
+
if (selectedImageKey != null) setSelectedKey(selectedImageKey);
|
|
5079
|
+
}, [selectedImageKey]);
|
|
5080
|
+
const [gallery, setGallery] = React$1.useState({
|
|
5081
|
+
images: attributes.images ?? [],
|
|
5082
|
+
columns: attributes.columns
|
|
5083
|
+
});
|
|
5084
|
+
React$1.useEffect(() => {
|
|
5085
|
+
setGallery({
|
|
5086
|
+
images: attributes.images ?? [],
|
|
5087
|
+
columns: attributes.columns
|
|
5088
|
+
});
|
|
5089
|
+
}, [nodeKey]);
|
|
5090
|
+
const images = gallery.images;
|
|
5091
|
+
const columns = gallery.columns ?? 3;
|
|
5092
|
+
const selectedImage = selectedKey ? images.find((image) => image._key === selectedKey) ?? null : null;
|
|
5093
|
+
const apply = (patch) => {
|
|
5094
|
+
setGallery((prev) => ({
|
|
5095
|
+
...prev,
|
|
5096
|
+
...patch
|
|
5097
|
+
}));
|
|
5098
|
+
onUpdate(patch);
|
|
5099
|
+
};
|
|
5100
|
+
const handleAdd = (items) => {
|
|
5101
|
+
apply({ images: [...images, ...items.map(mediaItemToGalleryImage)] });
|
|
5102
|
+
};
|
|
5103
|
+
const handleRemove = (key) => {
|
|
5104
|
+
apply({ images: images.filter((image) => image._key !== key) });
|
|
5105
|
+
setSelectedKey((prev) => prev === key ? null : prev);
|
|
5106
|
+
};
|
|
5107
|
+
const handleImageChange = (key, patch) => {
|
|
5108
|
+
apply({ images: images.map((image) => image._key === key ? {
|
|
5109
|
+
...image,
|
|
5110
|
+
...patch
|
|
5111
|
+
} : image) });
|
|
5112
|
+
};
|
|
5113
|
+
const handleReplace = (key, item) => {
|
|
5114
|
+
apply({ images: images.map((image) => image._key === key ? {
|
|
5115
|
+
...image,
|
|
5116
|
+
asset: {
|
|
5117
|
+
_type: "reference",
|
|
5118
|
+
_ref: item.id,
|
|
5119
|
+
url: item.url,
|
|
5120
|
+
provider: item.provider && item.provider !== "local" ? item.provider : void 0
|
|
5121
|
+
},
|
|
5122
|
+
alt: item.alt || "",
|
|
5123
|
+
width: item.width,
|
|
5124
|
+
height: item.height,
|
|
5125
|
+
blurhash: item.blurhash ?? metaString(item.meta, "blurhash"),
|
|
5126
|
+
dominantColor: item.dominantColor ?? metaString(item.meta, "dominantColor")
|
|
5127
|
+
} : image) });
|
|
5128
|
+
};
|
|
5129
|
+
const handleDragEnd = (event) => {
|
|
5130
|
+
const { active, over } = event;
|
|
5131
|
+
if (!over || active.id === over.id) return;
|
|
5132
|
+
const oldIndex = images.findIndex((image) => image._key === active.id);
|
|
5133
|
+
const newIndex = images.findIndex((image) => image._key === over.id);
|
|
5134
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
5135
|
+
apply({ images: arrayMove(images, oldIndex, newIndex) });
|
|
5136
|
+
};
|
|
5137
|
+
const body = /* @__PURE__ */ jsxs("div", {
|
|
5138
|
+
className: "space-y-4",
|
|
5139
|
+
children: [
|
|
5140
|
+
/* @__PURE__ */ jsxs("div", {
|
|
5141
|
+
className: "flex items-center justify-between",
|
|
5142
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
5143
|
+
className: "text-sm font-semibold",
|
|
5144
|
+
children: _t({
|
|
5145
|
+
id: "U+kFad",
|
|
5146
|
+
message: "Gallery"
|
|
5147
|
+
})
|
|
5148
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
5149
|
+
type: "button",
|
|
5150
|
+
variant: "ghost",
|
|
5151
|
+
shape: "square",
|
|
5152
|
+
className: "h-8 w-8",
|
|
5153
|
+
onClick: onClose,
|
|
5154
|
+
"aria-label": _t({
|
|
5155
|
+
id: "A6xK0W",
|
|
5156
|
+
message: "Close gallery settings"
|
|
5157
|
+
}),
|
|
5158
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
5159
|
+
})]
|
|
5160
|
+
}),
|
|
5161
|
+
/* @__PURE__ */ jsx(Select, {
|
|
5162
|
+
label: _t({
|
|
5163
|
+
id: "jEu4bB",
|
|
5164
|
+
message: "Columns"
|
|
5165
|
+
}),
|
|
5166
|
+
value: String(columns),
|
|
5167
|
+
onValueChange: (v) => apply({ columns: v ? parseInt(v, 10) : void 0 }),
|
|
5168
|
+
items: {
|
|
5169
|
+
"1": "1",
|
|
5170
|
+
"2": "2",
|
|
5171
|
+
"3": "3",
|
|
5172
|
+
"4": "4",
|
|
5173
|
+
"5": "5",
|
|
5174
|
+
"6": "6"
|
|
5175
|
+
}
|
|
5176
|
+
}),
|
|
5177
|
+
/* @__PURE__ */ jsxs("div", {
|
|
5178
|
+
className: "flex items-center justify-between",
|
|
5179
|
+
children: [/* @__PURE__ */ jsx(Label, { children: _t({
|
|
5180
|
+
id: "an5hVd",
|
|
5181
|
+
message: "Images"
|
|
5182
|
+
}) }), /* @__PURE__ */ jsx(Button, {
|
|
5183
|
+
type: "button",
|
|
5184
|
+
variant: "outline",
|
|
5185
|
+
size: "sm",
|
|
5186
|
+
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
5187
|
+
onClick: () => setShowMediaPicker(true),
|
|
5188
|
+
children: _t({
|
|
5189
|
+
id: "9Pd+JF",
|
|
5190
|
+
message: "Add Images"
|
|
5191
|
+
})
|
|
5192
|
+
})]
|
|
5193
|
+
}),
|
|
5194
|
+
images.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
5195
|
+
className: "text-sm text-kumo-subtle text-center py-4",
|
|
5196
|
+
children: _t({
|
|
5197
|
+
id: "aETJnp",
|
|
5198
|
+
message: "No images in this gallery yet."
|
|
5199
|
+
})
|
|
5200
|
+
}) : /* @__PURE__ */ jsx(DndContext, {
|
|
5201
|
+
sensors,
|
|
5202
|
+
collisionDetection: closestCenter,
|
|
5203
|
+
onDragEnd: handleDragEnd,
|
|
5204
|
+
children: /* @__PURE__ */ jsx(SortableContext, {
|
|
5205
|
+
items: images.map((image) => image._key),
|
|
5206
|
+
strategy: rectSortingStrategy,
|
|
5207
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
5208
|
+
className: "grid grid-cols-3 gap-2",
|
|
5209
|
+
children: images.map((image, index) => /* @__PURE__ */ jsx(SortableGalleryThumb, {
|
|
5210
|
+
image,
|
|
5211
|
+
index,
|
|
5212
|
+
selected: selectedKey === image._key,
|
|
5213
|
+
onSelect: () => setSelectedKey((prev) => prev === image._key ? null : image._key),
|
|
5214
|
+
onRemove: () => handleRemove(image._key)
|
|
5215
|
+
}, image._key))
|
|
5216
|
+
})
|
|
5217
|
+
})
|
|
5218
|
+
}),
|
|
5219
|
+
selectedImage && /* @__PURE__ */ jsx(GalleryImageSettings, {
|
|
5220
|
+
image: selectedImage,
|
|
5221
|
+
onChange: (patch) => handleImageChange(selectedImage._key, patch),
|
|
5222
|
+
onReplace: (item) => handleReplace(selectedImage._key, item)
|
|
5223
|
+
}, selectedImage._key),
|
|
5224
|
+
/* @__PURE__ */ jsx(Button, {
|
|
5225
|
+
type: "button",
|
|
5226
|
+
variant: "destructive",
|
|
5227
|
+
className: "w-full",
|
|
5228
|
+
onClick: onDelete,
|
|
5229
|
+
children: _t({
|
|
5230
|
+
id: "HjItFk",
|
|
5231
|
+
message: "Delete gallery"
|
|
5232
|
+
})
|
|
5233
|
+
}),
|
|
5234
|
+
/* @__PURE__ */ jsx(MediaPickerModal, {
|
|
5235
|
+
open: showMediaPicker,
|
|
5236
|
+
onOpenChange: setShowMediaPicker,
|
|
5237
|
+
multiple: true,
|
|
5238
|
+
onSelect: () => {},
|
|
5239
|
+
onSelectMany: handleAdd,
|
|
5240
|
+
mimeTypeFilters: ["image/"],
|
|
5241
|
+
title: _t({
|
|
5242
|
+
id: "yHTMc+",
|
|
5243
|
+
message: "Add images to gallery"
|
|
5244
|
+
})
|
|
5245
|
+
})
|
|
5246
|
+
]
|
|
5247
|
+
});
|
|
5248
|
+
if (inline) return body;
|
|
5249
|
+
return /* @__PURE__ */ jsx("div", {
|
|
5250
|
+
className: "fixed inset-y-0 end-0 w-96 max-w-full bg-kumo-base border-s shadow-lg z-50 overflow-y-auto p-4",
|
|
5251
|
+
children: body
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
function SortableGalleryThumb({ image, index, selected, onSelect, onRemove }) {
|
|
5255
|
+
const { _: _t2 } = useLingui();
|
|
5256
|
+
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: image._key });
|
|
5257
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
5258
|
+
ref: setNodeRef,
|
|
5259
|
+
style: {
|
|
5260
|
+
transform: CSS.Transform.toString(transform),
|
|
5261
|
+
transition
|
|
5262
|
+
},
|
|
5263
|
+
className: "relative group",
|
|
5264
|
+
children: [
|
|
5265
|
+
/* @__PURE__ */ jsx(Button, {
|
|
5266
|
+
type: "button",
|
|
5267
|
+
variant: "ghost",
|
|
5268
|
+
shape: "square",
|
|
5269
|
+
"aria-label": image.alt || _t2({
|
|
5270
|
+
id: "4lIvAN",
|
|
5271
|
+
message: "Image {0}",
|
|
5272
|
+
values: { 0: index + 1 }
|
|
5273
|
+
}),
|
|
5274
|
+
className: cn("aspect-square h-full w-full rounded-md border overflow-hidden", selected && "ring-2 ring-kumo-brand"),
|
|
5275
|
+
onClick: onSelect,
|
|
5276
|
+
...attributes,
|
|
5277
|
+
...listeners,
|
|
5278
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
5279
|
+
src: galleryImageUrl(image),
|
|
5280
|
+
alt: image.alt || "",
|
|
5281
|
+
className: "object-cover w-full h-full",
|
|
5282
|
+
draggable: false
|
|
5283
|
+
})
|
|
5284
|
+
}),
|
|
5285
|
+
/* @__PURE__ */ jsx(Button, {
|
|
5286
|
+
type: "button",
|
|
5287
|
+
variant: "destructive",
|
|
5288
|
+
shape: "square",
|
|
5289
|
+
className: "absolute top-1 end-1 h-6 w-6 opacity-0 group-hover:opacity-100 focus:opacity-100",
|
|
5290
|
+
onClick: (e) => {
|
|
5291
|
+
e.stopPropagation();
|
|
5292
|
+
onRemove();
|
|
5293
|
+
},
|
|
5294
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
5295
|
+
"aria-label": _t2({
|
|
5296
|
+
id: "YMIArw",
|
|
5297
|
+
message: "Remove image {0}",
|
|
5298
|
+
values: { 0: index + 1 }
|
|
5299
|
+
}),
|
|
5300
|
+
children: /* @__PURE__ */ jsx(Trash, { className: "h-3 w-3" })
|
|
5301
|
+
}),
|
|
5302
|
+
/* @__PURE__ */ jsx("span", {
|
|
5303
|
+
className: "absolute bottom-1 start-1 text-[10px] bg-black/60 text-white rounded px-1",
|
|
5304
|
+
"aria-hidden": true,
|
|
5305
|
+
children: index + 1
|
|
5306
|
+
})
|
|
5307
|
+
]
|
|
5308
|
+
});
|
|
5309
|
+
}
|
|
5310
|
+
function GalleryImageSettings({ image, onChange, onReplace }) {
|
|
5311
|
+
const { _: _t3 } = useLingui();
|
|
5312
|
+
const [showReplacePicker, setShowReplacePicker] = React$1.useState(false);
|
|
5313
|
+
const hasOriginalSize = typeof image.width === "number" && typeof image.height === "number";
|
|
5314
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
5315
|
+
className: "border rounded-lg p-3 space-y-3",
|
|
5316
|
+
children: [
|
|
5317
|
+
/* @__PURE__ */ jsxs("div", {
|
|
5318
|
+
className: "aspect-video bg-kumo-tint rounded-lg overflow-hidden flex items-center justify-center relative group",
|
|
5319
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
5320
|
+
src: galleryImageUrl(image),
|
|
5321
|
+
alt: image.alt || "",
|
|
5322
|
+
className: "max-h-full max-w-full object-contain",
|
|
5323
|
+
draggable: false
|
|
5324
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
5325
|
+
className: "absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center",
|
|
5326
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
5327
|
+
type: "button",
|
|
5328
|
+
variant: "outline",
|
|
5329
|
+
size: "sm",
|
|
5330
|
+
icon: /* @__PURE__ */ jsx(ImageSquare, {}),
|
|
5331
|
+
onClick: () => setShowReplacePicker(true),
|
|
5332
|
+
children: _t3({
|
|
5333
|
+
id: "YOzD/a",
|
|
5334
|
+
message: "Replace image"
|
|
5335
|
+
})
|
|
5336
|
+
})
|
|
5337
|
+
})]
|
|
5338
|
+
}),
|
|
5339
|
+
hasOriginalSize && /* @__PURE__ */ jsxs("div", {
|
|
5340
|
+
className: "flex items-center gap-2 text-sm",
|
|
5341
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
5342
|
+
className: "text-kumo-subtle",
|
|
5343
|
+
children: _t3({
|
|
5344
|
+
id: "9DNTTa",
|
|
5345
|
+
message: "Original:"
|
|
5346
|
+
})
|
|
5347
|
+
}), /* @__PURE__ */ jsxs("span", { children: [
|
|
5348
|
+
image.width,
|
|
5349
|
+
" × ",
|
|
5350
|
+
image.height
|
|
5351
|
+
] })]
|
|
5352
|
+
}),
|
|
5353
|
+
/* @__PURE__ */ jsx(Input, {
|
|
5354
|
+
label: _t3({
|
|
5355
|
+
id: "u/DP73",
|
|
5356
|
+
message: "Alt text"
|
|
5357
|
+
}),
|
|
5358
|
+
value: image.alt ?? "",
|
|
5359
|
+
onChange: (e) => onChange({ alt: e.target.value }),
|
|
5360
|
+
placeholder: _t3({
|
|
5361
|
+
id: "BwNww/",
|
|
5362
|
+
message: "Describe the image..."
|
|
5363
|
+
})
|
|
5364
|
+
}),
|
|
5365
|
+
/* @__PURE__ */ jsx(Input, {
|
|
5366
|
+
label: _t3({
|
|
5367
|
+
id: "3Z1aAQ",
|
|
5368
|
+
message: "Caption"
|
|
5369
|
+
}),
|
|
5370
|
+
value: image.caption ?? "",
|
|
5371
|
+
onChange: (e) => onChange({ caption: e.target.value || void 0 }),
|
|
5372
|
+
placeholder: _t3({
|
|
5373
|
+
id: "0IiIv1",
|
|
5374
|
+
message: "Optional caption"
|
|
5375
|
+
})
|
|
5376
|
+
}),
|
|
5377
|
+
/* @__PURE__ */ jsx(MediaPickerModal, {
|
|
5378
|
+
open: showReplacePicker,
|
|
5379
|
+
onOpenChange: setShowReplacePicker,
|
|
5380
|
+
onSelect: (item) => {
|
|
5381
|
+
onReplace(item);
|
|
5382
|
+
setShowReplacePicker(false);
|
|
5383
|
+
},
|
|
5384
|
+
mimeTypeFilters: ["image/"],
|
|
5385
|
+
title: _t3({
|
|
5386
|
+
id: "YOzD/a",
|
|
5387
|
+
message: "Replace image"
|
|
5388
|
+
})
|
|
5389
|
+
})
|
|
5390
|
+
]
|
|
5391
|
+
});
|
|
5392
|
+
}
|
|
5393
|
+
|
|
4818
5394
|
//#endregion
|
|
4819
5395
|
//#region src/components/editor/ImageDetailPanel.tsx
|
|
4820
5396
|
/**
|
|
@@ -5611,7 +6187,7 @@ function formatFullDate(dateString) {
|
|
|
5611
6187
|
* RevisionHistory component - displays revision history for a content item
|
|
5612
6188
|
* with ability to restore previous versions.
|
|
5613
6189
|
*/
|
|
5614
|
-
function RevisionHistory({ collection, entryId, onRestored }) {
|
|
6190
|
+
function RevisionHistory({ collection, entryId, onRestored, reserveHeaderEnd = false }) {
|
|
5615
6191
|
const { _: _t } = useLingui();
|
|
5616
6192
|
const [isExpanded, setIsExpanded] = React$1.useState(false);
|
|
5617
6193
|
const [selectedRevision, setSelectedRevision] = React$1.useState(null);
|
|
@@ -5679,7 +6255,7 @@ function RevisionHistory({ collection, entryId, onRestored }) {
|
|
|
5679
6255
|
variant: "ghost",
|
|
5680
6256
|
className: "relative justify-between",
|
|
5681
6257
|
style: {
|
|
5682
|
-
width: "calc(100% + 1.5rem)",
|
|
6258
|
+
width: reserveHeaderEnd ? "calc(100% - 1.5rem)" : "calc(100% + 1.5rem)",
|
|
5683
6259
|
insetInlineStart: "-0.75rem"
|
|
5684
6260
|
}
|
|
5685
6261
|
}),
|
|
@@ -6483,6 +7059,207 @@ function SeoPanel({ contentKey, seo, onChange }) {
|
|
|
6483
7059
|
});
|
|
6484
7060
|
}
|
|
6485
7061
|
|
|
7062
|
+
//#endregion
|
|
7063
|
+
//#region src/lib/content-settings-layout.ts
|
|
7064
|
+
const CONTENT_SETTINGS_LAYOUT_VERSION = 1;
|
|
7065
|
+
const DEFAULT_CONTENT_SETTINGS_SECTION_ORDER = [
|
|
7066
|
+
"publish",
|
|
7067
|
+
"ownership",
|
|
7068
|
+
"bylines",
|
|
7069
|
+
"translations",
|
|
7070
|
+
"taxonomies",
|
|
7071
|
+
"seo",
|
|
7072
|
+
"outline",
|
|
7073
|
+
"revisions"
|
|
7074
|
+
];
|
|
7075
|
+
const KNOWN_SECTION_IDS = new Set(DEFAULT_CONTENT_SETTINGS_SECTION_ORDER);
|
|
7076
|
+
function isRecord(value) {
|
|
7077
|
+
return typeof value === "object" && value !== null;
|
|
7078
|
+
}
|
|
7079
|
+
function isKnownSectionId(value) {
|
|
7080
|
+
return typeof value === "string" && KNOWN_SECTION_IDS.has(value);
|
|
7081
|
+
}
|
|
7082
|
+
/** Parse a browser preference without allowing malformed state to break the editor. */
|
|
7083
|
+
function parseContentSettingsLayout(raw) {
|
|
7084
|
+
if (!raw) return null;
|
|
7085
|
+
try {
|
|
7086
|
+
const value = JSON.parse(raw);
|
|
7087
|
+
if (!isRecord(value) || value.version !== CONTENT_SETTINGS_LAYOUT_VERSION || !Array.isArray(value.order)) return null;
|
|
7088
|
+
return {
|
|
7089
|
+
version: CONTENT_SETTINGS_LAYOUT_VERSION,
|
|
7090
|
+
order: value.order.filter(isKnownSectionId)
|
|
7091
|
+
};
|
|
7092
|
+
} catch {
|
|
7093
|
+
return null;
|
|
7094
|
+
}
|
|
7095
|
+
}
|
|
7096
|
+
/**
|
|
7097
|
+
* Reconcile saved order with the current defaults. Duplicate and unknown ids
|
|
7098
|
+
* disappear, while sections introduced by a later EmDash version append.
|
|
7099
|
+
*/
|
|
7100
|
+
function resolveContentSettingsLayout(stored) {
|
|
7101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7102
|
+
const order = (stored?.order ?? []).filter((id) => {
|
|
7103
|
+
if (seen.has(id)) return false;
|
|
7104
|
+
seen.add(id);
|
|
7105
|
+
return true;
|
|
7106
|
+
});
|
|
7107
|
+
for (const id of DEFAULT_CONTENT_SETTINGS_SECTION_ORDER) {
|
|
7108
|
+
if (seen.has(id)) continue;
|
|
7109
|
+
order.push(id);
|
|
7110
|
+
seen.add(id);
|
|
7111
|
+
}
|
|
7112
|
+
return {
|
|
7113
|
+
version: CONTENT_SETTINGS_LAYOUT_VERSION,
|
|
7114
|
+
order
|
|
7115
|
+
};
|
|
7116
|
+
}
|
|
7117
|
+
function reorderContentSettingsLayout(layout, activeId, overId) {
|
|
7118
|
+
if (activeId === overId) return layout;
|
|
7119
|
+
const from = layout.order.indexOf(activeId);
|
|
7120
|
+
const to = layout.order.indexOf(overId);
|
|
7121
|
+
if (from < 0 || to < 0) return layout;
|
|
7122
|
+
const order = [...layout.order];
|
|
7123
|
+
const [moved] = order.splice(from, 1);
|
|
7124
|
+
if (!moved) return layout;
|
|
7125
|
+
order.splice(to, 0, moved);
|
|
7126
|
+
return {
|
|
7127
|
+
...layout,
|
|
7128
|
+
order
|
|
7129
|
+
};
|
|
7130
|
+
}
|
|
7131
|
+
|
|
7132
|
+
//#endregion
|
|
7133
|
+
//#region src/components/SortableContentSettingsSections.tsx
|
|
7134
|
+
const STORAGE_PREFIX = "emdash:content-settings-layout:v1";
|
|
7135
|
+
const restrictToVerticalAxis = ({ transform }) => ({
|
|
7136
|
+
...transform,
|
|
7137
|
+
x: 0
|
|
7138
|
+
});
|
|
7139
|
+
function readStoredLayout(storageKey) {
|
|
7140
|
+
if (!storageKey || typeof window === "undefined") return null;
|
|
7141
|
+
try {
|
|
7142
|
+
return parseContentSettingsLayout(window.localStorage.getItem(storageKey));
|
|
7143
|
+
} catch {
|
|
7144
|
+
return null;
|
|
7145
|
+
}
|
|
7146
|
+
}
|
|
7147
|
+
function writeStoredLayout(storageKey, layout) {
|
|
7148
|
+
if (!storageKey || typeof window === "undefined") return;
|
|
7149
|
+
try {
|
|
7150
|
+
window.localStorage.setItem(storageKey, JSON.stringify(layout));
|
|
7151
|
+
} catch {}
|
|
7152
|
+
}
|
|
7153
|
+
function SortableContentSettingsSections({ collection, userId, onSortingChange, children }) {
|
|
7154
|
+
const storageKey = userId ? `${STORAGE_PREFIX}:${encodeURIComponent(userId)}:${encodeURIComponent(collection)}` : null;
|
|
7155
|
+
const [storedLayout, setStoredLayout] = React$1.useState(null);
|
|
7156
|
+
const [activeId, setActiveId] = React$1.useState(null);
|
|
7157
|
+
React$1.useEffect(() => {
|
|
7158
|
+
setStoredLayout(readStoredLayout(storageKey));
|
|
7159
|
+
}, [storageKey]);
|
|
7160
|
+
const layout = React$1.useMemo(() => resolveContentSettingsLayout(storedLayout), [storedLayout]);
|
|
7161
|
+
const sectionsById = React$1.useMemo(() => {
|
|
7162
|
+
const sections = React$1.Children.toArray(children).filter((child) => React$1.isValidElement(child));
|
|
7163
|
+
return new Map(sections.map((section) => [section.props.id, section]));
|
|
7164
|
+
}, [children]);
|
|
7165
|
+
const visibleIds = React$1.useMemo(() => layout.order.filter((id) => sectionsById.has(id)), [layout.order, sectionsById]);
|
|
7166
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
7167
|
+
const handleDragStart = React$1.useCallback((event) => {
|
|
7168
|
+
setActiveId(String(event.active.id));
|
|
7169
|
+
onSortingChange?.(true);
|
|
7170
|
+
}, [onSortingChange]);
|
|
7171
|
+
const handleDragCancel = React$1.useCallback(() => {
|
|
7172
|
+
setActiveId(null);
|
|
7173
|
+
onSortingChange?.(false);
|
|
7174
|
+
}, [onSortingChange]);
|
|
7175
|
+
const handleDragEnd = React$1.useCallback((event) => {
|
|
7176
|
+
setActiveId(null);
|
|
7177
|
+
onSortingChange?.(false);
|
|
7178
|
+
if (event.over && event.active.id !== event.over.id) {
|
|
7179
|
+
const movedId = String(event.active.id);
|
|
7180
|
+
const overId = String(event.over.id);
|
|
7181
|
+
setStoredLayout((current) => {
|
|
7182
|
+
const next = reorderContentSettingsLayout(resolveContentSettingsLayout(current), movedId, overId);
|
|
7183
|
+
writeStoredLayout(storageKey, next);
|
|
7184
|
+
return next;
|
|
7185
|
+
});
|
|
7186
|
+
}
|
|
7187
|
+
}, [onSortingChange, storageKey]);
|
|
7188
|
+
return /* @__PURE__ */ jsx(DndContext, {
|
|
7189
|
+
sensors,
|
|
7190
|
+
collisionDetection: closestCenter,
|
|
7191
|
+
modifiers: [restrictToVerticalAxis],
|
|
7192
|
+
measuring: { droppable: { strategy: MeasuringStrategy.Always } },
|
|
7193
|
+
onDragStart: handleDragStart,
|
|
7194
|
+
onDragCancel: handleDragCancel,
|
|
7195
|
+
onDragEnd: handleDragEnd,
|
|
7196
|
+
children: /* @__PURE__ */ jsx(SortableContext, {
|
|
7197
|
+
items: visibleIds,
|
|
7198
|
+
strategy: verticalListSortingStrategy,
|
|
7199
|
+
children: visibleIds.map((id) => {
|
|
7200
|
+
const section = sectionsById.get(id);
|
|
7201
|
+
return section ? React$1.cloneElement(section, {
|
|
7202
|
+
key: id,
|
|
7203
|
+
isSorting: activeId !== null
|
|
7204
|
+
}) : null;
|
|
7205
|
+
})
|
|
7206
|
+
})
|
|
7207
|
+
});
|
|
7208
|
+
}
|
|
7209
|
+
function SortableContentSettingsSection({ id, label, disclosure = false, children, isSorting = false }) {
|
|
7210
|
+
const { _: _t } = useLingui();
|
|
7211
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });
|
|
7212
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
7213
|
+
ref: setNodeRef,
|
|
7214
|
+
style: {
|
|
7215
|
+
transform: transform ? CSS.Transform.toString({
|
|
7216
|
+
...transform,
|
|
7217
|
+
x: 0
|
|
7218
|
+
}) : void 0,
|
|
7219
|
+
transition,
|
|
7220
|
+
zIndex: isDragging ? 10 : void 0,
|
|
7221
|
+
inlineSize: "100%"
|
|
7222
|
+
},
|
|
7223
|
+
"data-sorting": isSorting ? "true" : "false",
|
|
7224
|
+
"data-disclosure": disclosure ? "true" : "false",
|
|
7225
|
+
className: cn("relative min-w-0 border-t bg-kumo-base first:border-t-0", isSorting && "[&>*:not([data-sortable-heading]):not([data-sortable-handle])]:hidden", isDragging && "bg-kumo-tint opacity-60"),
|
|
7226
|
+
children: [
|
|
7227
|
+
isSorting && /* @__PURE__ */ jsx("div", {
|
|
7228
|
+
"data-sortable-heading": true,
|
|
7229
|
+
className: "flex items-center px-4 pe-12",
|
|
7230
|
+
style: { minHeight: 48 },
|
|
7231
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
7232
|
+
className: "text-[15px] font-semibold",
|
|
7233
|
+
children: label
|
|
7234
|
+
})
|
|
7235
|
+
}),
|
|
7236
|
+
children,
|
|
7237
|
+
/* @__PURE__ */ jsx("button", {
|
|
7238
|
+
type: "button",
|
|
7239
|
+
"data-sortable-handle": true,
|
|
7240
|
+
"data-sorting": isSorting ? "true" : "false",
|
|
7241
|
+
...attributes,
|
|
7242
|
+
...listeners,
|
|
7243
|
+
className: cn("absolute z-10 grid size-7 touch-none cursor-grab place-items-center rounded-md text-kumo-subtle hover:bg-kumo-tint hover:text-kumo-default focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-kumo-accent active:cursor-grabbing", isSorting ? "end-3 top-1/2 -translate-y-1/2" : "top-3", !isSorting && "end-3"),
|
|
7244
|
+
"aria-label": _t({
|
|
7245
|
+
id: "LGF0vE",
|
|
7246
|
+
message: "Drag to reorder {label}",
|
|
7247
|
+
values: { label }
|
|
7248
|
+
}),
|
|
7249
|
+
title: _t({
|
|
7250
|
+
id: "LGF0vE",
|
|
7251
|
+
message: "Drag to reorder {label}",
|
|
7252
|
+
values: { label }
|
|
7253
|
+
}),
|
|
7254
|
+
children: /* @__PURE__ */ jsx(DotsSixVertical, {
|
|
7255
|
+
size: 16,
|
|
7256
|
+
"aria-hidden": "true"
|
|
7257
|
+
})
|
|
7258
|
+
})
|
|
7259
|
+
]
|
|
7260
|
+
});
|
|
7261
|
+
}
|
|
7262
|
+
|
|
6486
7263
|
//#endregion
|
|
6487
7264
|
//#region src/lib/taxonomy-match.ts
|
|
6488
7265
|
/**
|
|
@@ -6558,6 +7335,17 @@ const EMPTY_TERMS = [];
|
|
|
6558
7335
|
async function fetchTaxonomyDefs$1() {
|
|
6559
7336
|
return (await parseApiResponse(await apiFetch(`/_emdash/api/taxonomies`), "Failed to fetch taxonomies")).taxonomies;
|
|
6560
7337
|
}
|
|
7338
|
+
function useApplicableTaxonomies(collection) {
|
|
7339
|
+
const { data: taxonomies = [] } = useQuery({
|
|
7340
|
+
queryKey: ["taxonomy-defs"],
|
|
7341
|
+
queryFn: fetchTaxonomyDefs$1
|
|
7342
|
+
});
|
|
7343
|
+
return taxonomies.filter((taxonomy) => taxonomy.collections.includes(collection));
|
|
7344
|
+
}
|
|
7345
|
+
/** Whether the editor should include a taxonomy settings section. */
|
|
7346
|
+
function useHasApplicableTaxonomies(collection) {
|
|
7347
|
+
return useApplicableTaxonomies(collection).length > 0;
|
|
7348
|
+
}
|
|
6561
7349
|
/**
|
|
6562
7350
|
* Fetch terms for a taxonomy, scoped to the entry's locale so only the matching
|
|
6563
7351
|
* translation variants are offered.
|
|
@@ -6927,11 +7715,7 @@ function TaxonomySection({ taxonomy, collection, entryId, entryLocale, onChange
|
|
|
6927
7715
|
*/
|
|
6928
7716
|
function TaxonomySidebar({ collection, entryId, entryLocale, onChange, className }) {
|
|
6929
7717
|
const { _: _t3 } = useLingui();
|
|
6930
|
-
const
|
|
6931
|
-
queryKey: ["taxonomy-defs"],
|
|
6932
|
-
queryFn: fetchTaxonomyDefs$1
|
|
6933
|
-
});
|
|
6934
|
-
const applicableTaxonomies = taxonomies.filter((tax) => tax.collections.includes(collection));
|
|
7718
|
+
const applicableTaxonomies = useApplicableTaxonomies(collection);
|
|
6935
7719
|
if (applicableTaxonomies.length === 0) return null;
|
|
6936
7720
|
return /* @__PURE__ */ jsx("div", {
|
|
6937
7721
|
className: cn(className),
|
|
@@ -7228,7 +8012,9 @@ const ContentSettingsPanel = React$1.memo(function ContentSettingsPanel({ collec
|
|
|
7228
8012
|
const navigate = useNavigate$1();
|
|
7229
8013
|
const [scheduleDate, setScheduleDate] = React$1.useState("");
|
|
7230
8014
|
const [showScheduler, setShowScheduler] = React$1.useState(false);
|
|
8015
|
+
const [isReorderingSections, setIsReorderingSections] = React$1.useState(false);
|
|
7231
8016
|
const showDiscard = !isNew && supportsDrafts && hasPendingChanges && !!onDiscardDraft;
|
|
8017
|
+
const hasApplicableTaxonomies = useHasApplicableTaxonomies(collection);
|
|
7232
8018
|
const handleScheduleSubmit = () => {
|
|
7233
8019
|
if (scheduleDate && onSchedule) {
|
|
7234
8020
|
onSchedule(new Date(scheduleDate).toISOString());
|
|
@@ -7246,318 +8032,395 @@ const ContentSettingsPanel = React$1.memo(function ContentSettingsPanel({ collec
|
|
|
7246
8032
|
onClose: onBlockSidebarClose,
|
|
7247
8033
|
inline: true
|
|
7248
8034
|
})
|
|
8035
|
+
}) : blockSidebarPanel.type === "gallery" ? /* @__PURE__ */ jsx("div", {
|
|
8036
|
+
className: "p-4",
|
|
8037
|
+
children: /* @__PURE__ */ jsx(GalleryDetailPanel, {
|
|
8038
|
+
attributes: blockSidebarPanel.attrs,
|
|
8039
|
+
onUpdate: (attrs) => blockSidebarPanel.onUpdate(attrs),
|
|
8040
|
+
onDelete: onBlockSidebarDelete,
|
|
8041
|
+
onClose: onBlockSidebarClose,
|
|
8042
|
+
inline: true
|
|
8043
|
+
})
|
|
7249
8044
|
}) : null;
|
|
7250
8045
|
return /* @__PURE__ */ jsxs("div", {
|
|
7251
8046
|
className: "flex flex-col whitespace-normal",
|
|
7252
|
-
children: [
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
message: "Publish"
|
|
7263
|
-
})
|
|
8047
|
+
children: [/* @__PURE__ */ jsxs(SortableContentSettingsSections, {
|
|
8048
|
+
collection,
|
|
8049
|
+
userId: currentUser?.id,
|
|
8050
|
+
onSortingChange: setIsReorderingSections,
|
|
8051
|
+
children: [
|
|
8052
|
+
/* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8053
|
+
id: "publish",
|
|
8054
|
+
label: _t5({
|
|
8055
|
+
id: "EEYbdt",
|
|
8056
|
+
message: "Publish"
|
|
7264
8057
|
}),
|
|
7265
|
-
/* @__PURE__ */ jsxs("div", {
|
|
7266
|
-
className: "
|
|
8058
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8059
|
+
className: "p-4",
|
|
7267
8060
|
children: [
|
|
7268
|
-
/* @__PURE__ */ jsx(
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
placeholder: "my-post-slug"
|
|
7276
|
-
}),
|
|
7277
|
-
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
7278
|
-
className: "flex flex-wrap items-center gap-x-3 gap-y-1.5",
|
|
7279
|
-
children: [/* @__PURE__ */ jsx(Label, { children: _t5({
|
|
7280
|
-
id: "uAQUqI",
|
|
7281
|
-
message: "Status"
|
|
7282
|
-
}) }), supportsDrafts ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7283
|
-
isLive && /* @__PURE__ */ jsx(Badge, {
|
|
7284
|
-
variant: "success",
|
|
7285
|
-
children: _t5({
|
|
7286
|
-
id: "u3wRF+",
|
|
7287
|
-
message: "Published"
|
|
7288
|
-
})
|
|
7289
|
-
}),
|
|
7290
|
-
hasPendingChanges && /* @__PURE__ */ jsx(Badge, {
|
|
7291
|
-
variant: "secondary",
|
|
7292
|
-
children: _t5({
|
|
7293
|
-
id: "fkUmSB",
|
|
7294
|
-
message: "Pending changes"
|
|
7295
|
-
})
|
|
7296
|
-
}),
|
|
7297
|
-
!isLive && !hasSchedule && /* @__PURE__ */ jsx(Badge, {
|
|
7298
|
-
variant: "secondary",
|
|
7299
|
-
children: _t5({
|
|
7300
|
-
id: "eneWvv",
|
|
7301
|
-
message: "Draft"
|
|
7302
|
-
})
|
|
7303
|
-
}),
|
|
7304
|
-
hasSchedule && /* @__PURE__ */ jsx(Badge, {
|
|
7305
|
-
variant: "outline",
|
|
7306
|
-
children: _t5({
|
|
7307
|
-
id: "4ba0NE",
|
|
7308
|
-
message: "Scheduled"
|
|
7309
|
-
})
|
|
7310
|
-
})
|
|
7311
|
-
] }) : /* @__PURE__ */ jsx(Badge, {
|
|
7312
|
-
variant: "secondary",
|
|
7313
|
-
children: status.charAt(0).toUpperCase() + status.slice(1)
|
|
7314
|
-
})]
|
|
7315
|
-
}), showDiscard && /* @__PURE__ */ jsx("div", {
|
|
7316
|
-
className: "mt-2",
|
|
7317
|
-
children: /* @__PURE__ */ jsx(DiscardDraftDialog, {
|
|
7318
|
-
onDiscard: onDiscardDraft,
|
|
7319
|
-
triggerVariant: "outline",
|
|
7320
|
-
triggerSize: "sm"
|
|
8061
|
+
/* @__PURE__ */ jsx(Text, {
|
|
8062
|
+
bold: true,
|
|
8063
|
+
as: "h3",
|
|
8064
|
+
DANGEROUS_className: "mb-4",
|
|
8065
|
+
children: _t5({
|
|
8066
|
+
id: "EEYbdt",
|
|
8067
|
+
message: "Publish"
|
|
7321
8068
|
})
|
|
7322
|
-
})] }),
|
|
7323
|
-
item?.scheduledAt && /* @__PURE__ */ jsxs("div", {
|
|
7324
|
-
className: "flex items-center justify-between gap-2 rounded-lg border px-3 py-2",
|
|
7325
|
-
children: [/* @__PURE__ */ jsx("p", {
|
|
7326
|
-
className: "text-xs text-kumo-subtle",
|
|
7327
|
-
children: _t5({
|
|
7328
|
-
id: "MjRZEl",
|
|
7329
|
-
message: "Scheduled for: {0}",
|
|
7330
|
-
values: { 0: formatScheduledDate(item.scheduledAt) }
|
|
7331
|
-
})
|
|
7332
|
-
}), /* @__PURE__ */ jsx(Button, {
|
|
7333
|
-
type: "button",
|
|
7334
|
-
variant: "outline",
|
|
7335
|
-
size: "sm",
|
|
7336
|
-
onClick: onUnschedule,
|
|
7337
|
-
children: _t5({
|
|
7338
|
-
id: "ssbNAt",
|
|
7339
|
-
message: "Unschedule"
|
|
7340
|
-
})
|
|
7341
|
-
})]
|
|
7342
8069
|
}),
|
|
7343
|
-
|
|
7344
|
-
className: "
|
|
7345
|
-
children:
|
|
7346
|
-
|
|
7347
|
-
children: [/* @__PURE__ */ jsx(Input, {
|
|
8070
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8071
|
+
className: "space-y-4",
|
|
8072
|
+
children: [
|
|
8073
|
+
/* @__PURE__ */ jsx(Input, {
|
|
7348
8074
|
label: _t5({
|
|
7349
|
-
id: "
|
|
7350
|
-
message: "
|
|
8075
|
+
id: "L85WcV",
|
|
8076
|
+
message: "Slug"
|
|
7351
8077
|
}),
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
className: "flex gap-
|
|
7358
|
-
children: [/* @__PURE__ */ jsx(
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
8078
|
+
value: slug,
|
|
8079
|
+
onChange: (e) => onSlugChange(e.target.value),
|
|
8080
|
+
placeholder: "my-post-slug"
|
|
8081
|
+
}),
|
|
8082
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
8083
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1.5",
|
|
8084
|
+
children: [/* @__PURE__ */ jsx(Label, { children: _t5({
|
|
8085
|
+
id: "uAQUqI",
|
|
8086
|
+
message: "Status"
|
|
8087
|
+
}) }), supportsDrafts ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8088
|
+
isLive && /* @__PURE__ */ jsx(Badge, {
|
|
8089
|
+
variant: "success",
|
|
8090
|
+
children: _t5({
|
|
8091
|
+
id: "u3wRF+",
|
|
8092
|
+
message: "Published"
|
|
8093
|
+
})
|
|
8094
|
+
}),
|
|
8095
|
+
hasPendingChanges && /* @__PURE__ */ jsx(Badge, {
|
|
8096
|
+
variant: "secondary",
|
|
8097
|
+
children: _t5({
|
|
8098
|
+
id: "fkUmSB",
|
|
8099
|
+
message: "Pending changes"
|
|
8100
|
+
})
|
|
8101
|
+
}),
|
|
8102
|
+
!isLive && !hasSchedule && /* @__PURE__ */ jsx(Badge, {
|
|
8103
|
+
variant: "secondary",
|
|
8104
|
+
children: _t5({
|
|
8105
|
+
id: "eneWvv",
|
|
8106
|
+
message: "Draft"
|
|
8107
|
+
})
|
|
8108
|
+
}),
|
|
8109
|
+
hasSchedule && /* @__PURE__ */ jsx(Badge, {
|
|
8110
|
+
variant: "outline",
|
|
8111
|
+
children: _t5({
|
|
8112
|
+
id: "4ba0NE",
|
|
8113
|
+
message: "Scheduled"
|
|
8114
|
+
})
|
|
8115
|
+
})
|
|
8116
|
+
] }) : /* @__PURE__ */ jsx(Badge, {
|
|
8117
|
+
variant: "secondary",
|
|
8118
|
+
children: status.charAt(0).toUpperCase() + status.slice(1)
|
|
8119
|
+
})]
|
|
8120
|
+
}), showDiscard && /* @__PURE__ */ jsx("div", {
|
|
8121
|
+
className: "mt-2",
|
|
8122
|
+
children: /* @__PURE__ */ jsx(DiscardDraftDialog, {
|
|
8123
|
+
onDiscard: onDiscardDraft,
|
|
8124
|
+
triggerVariant: "outline",
|
|
8125
|
+
triggerSize: "sm"
|
|
8126
|
+
})
|
|
8127
|
+
})] }),
|
|
8128
|
+
item?.scheduledAt && /* @__PURE__ */ jsxs("div", {
|
|
8129
|
+
className: "flex items-center justify-between gap-2 rounded-lg border px-3 py-2",
|
|
8130
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
8131
|
+
className: "text-xs text-kumo-subtle",
|
|
7364
8132
|
children: _t5({
|
|
7365
|
-
id: "
|
|
7366
|
-
message: "
|
|
8133
|
+
id: "MjRZEl",
|
|
8134
|
+
message: "Scheduled for: {0}",
|
|
8135
|
+
values: { 0: formatScheduledDate(item.scheduledAt) }
|
|
7367
8136
|
})
|
|
7368
8137
|
}), /* @__PURE__ */ jsx(Button, {
|
|
7369
8138
|
type: "button",
|
|
7370
8139
|
variant: "outline",
|
|
7371
8140
|
size: "sm",
|
|
7372
|
-
onClick:
|
|
7373
|
-
setShowScheduler(false);
|
|
7374
|
-
setScheduleDate("");
|
|
7375
|
-
},
|
|
8141
|
+
onClick: onUnschedule,
|
|
7376
8142
|
children: _t5({
|
|
7377
|
-
id: "
|
|
7378
|
-
message: "
|
|
8143
|
+
id: "ssbNAt",
|
|
8144
|
+
message: "Unschedule"
|
|
7379
8145
|
})
|
|
7380
8146
|
})]
|
|
7381
|
-
})
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
8147
|
+
}),
|
|
8148
|
+
canSchedule && /* @__PURE__ */ jsx("div", {
|
|
8149
|
+
className: "pt-2",
|
|
8150
|
+
children: showScheduler ? /* @__PURE__ */ jsxs("div", {
|
|
8151
|
+
className: "space-y-2",
|
|
8152
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
8153
|
+
label: _t5({
|
|
8154
|
+
id: "x6lWtJ",
|
|
8155
|
+
message: "Schedule for"
|
|
8156
|
+
}),
|
|
8157
|
+
type: "datetime-local",
|
|
8158
|
+
value: scheduleDate,
|
|
8159
|
+
onChange: (e) => setScheduleDate(e.target.value),
|
|
8160
|
+
min: (/* @__PURE__ */ new Date()).toISOString().slice(0, 16)
|
|
8161
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
8162
|
+
className: "flex gap-2",
|
|
8163
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
8164
|
+
type: "button",
|
|
8165
|
+
size: "sm",
|
|
8166
|
+
onClick: handleScheduleSubmit,
|
|
8167
|
+
disabled: !scheduleDate || isScheduling,
|
|
8168
|
+
icon: isScheduling ? /* @__PURE__ */ jsx(Loader, { size: "sm" }) : void 0,
|
|
8169
|
+
children: _t5({
|
|
8170
|
+
id: "gmB6oO",
|
|
8171
|
+
message: "Schedule"
|
|
8172
|
+
})
|
|
8173
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
8174
|
+
type: "button",
|
|
8175
|
+
variant: "outline",
|
|
8176
|
+
size: "sm",
|
|
8177
|
+
onClick: () => {
|
|
8178
|
+
setShowScheduler(false);
|
|
8179
|
+
setScheduleDate("");
|
|
8180
|
+
},
|
|
8181
|
+
children: _t5({
|
|
8182
|
+
id: "dEgA5A",
|
|
8183
|
+
message: "Cancel"
|
|
8184
|
+
})
|
|
8185
|
+
})]
|
|
8186
|
+
})]
|
|
8187
|
+
}) : /* @__PURE__ */ jsx(Button, {
|
|
8188
|
+
type: "button",
|
|
8189
|
+
variant: "outline",
|
|
8190
|
+
size: "sm",
|
|
8191
|
+
className: "w-full",
|
|
8192
|
+
onClick: () => setShowScheduler(true),
|
|
8193
|
+
children: _t5({
|
|
8194
|
+
id: "QS1Nla",
|
|
8195
|
+
message: "Schedule for later"
|
|
8196
|
+
})
|
|
8197
|
+
})
|
|
7391
8198
|
})
|
|
7392
|
-
|
|
8199
|
+
]
|
|
8200
|
+
}),
|
|
8201
|
+
item && /* @__PURE__ */ jsxs("dl", {
|
|
8202
|
+
"data-testid": "content-timestamps",
|
|
8203
|
+
className: "mt-4 border-t pt-4 space-y-1 text-xs text-kumo-subtle",
|
|
8204
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
8205
|
+
className: "flex items-center justify-between gap-2",
|
|
8206
|
+
children: [/* @__PURE__ */ jsx("dt", { children: _t5({
|
|
8207
|
+
id: "d+F6q9",
|
|
8208
|
+
message: "Created"
|
|
8209
|
+
}) }), /* @__PURE__ */ jsx("dd", { children: new Date(item.createdAt).toLocaleString() })]
|
|
8210
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
8211
|
+
className: "flex items-center justify-between gap-2",
|
|
8212
|
+
children: [/* @__PURE__ */ jsx("dt", { children: _t5({
|
|
8213
|
+
id: "+b7T3G",
|
|
8214
|
+
message: "Updated"
|
|
8215
|
+
}) }), /* @__PURE__ */ jsx("dd", { children: new Date(item.updatedAt).toLocaleString() })]
|
|
8216
|
+
})]
|
|
7393
8217
|
})
|
|
7394
8218
|
]
|
|
7395
|
-
}),
|
|
7396
|
-
item && /* @__PURE__ */ jsxs("dl", {
|
|
7397
|
-
"data-testid": "content-timestamps",
|
|
7398
|
-
className: "mt-4 border-t pt-4 space-y-1 text-xs text-kumo-subtle",
|
|
7399
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
7400
|
-
className: "flex items-center justify-between gap-2",
|
|
7401
|
-
children: [/* @__PURE__ */ jsx("dt", { children: _t5({
|
|
7402
|
-
id: "d+F6q9",
|
|
7403
|
-
message: "Created"
|
|
7404
|
-
}) }), /* @__PURE__ */ jsx("dd", { children: new Date(item.createdAt).toLocaleString() })]
|
|
7405
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
7406
|
-
className: "flex items-center justify-between gap-2",
|
|
7407
|
-
children: [/* @__PURE__ */ jsx("dt", { children: _t5({
|
|
7408
|
-
id: "+b7T3G",
|
|
7409
|
-
message: "Updated"
|
|
7410
|
-
}) }), /* @__PURE__ */ jsx("dd", { children: new Date(item.updatedAt).toLocaleString() })]
|
|
7411
|
-
})]
|
|
7412
8219
|
})
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
children: [/* @__PURE__ */ jsx(Text, {
|
|
7418
|
-
bold: true,
|
|
7419
|
-
as: "h3",
|
|
7420
|
-
DANGEROUS_className: "mb-4",
|
|
7421
|
-
children: _t5({
|
|
8220
|
+
}),
|
|
8221
|
+
currentUser && currentUser.role >= ROLE_EDITOR$3 && users && users.length > 0 && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8222
|
+
id: "ownership",
|
|
8223
|
+
label: _t5({
|
|
7422
8224
|
id: "oDAEQq",
|
|
7423
8225
|
message: "Ownership"
|
|
8226
|
+
}),
|
|
8227
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8228
|
+
className: "p-4",
|
|
8229
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
8230
|
+
bold: true,
|
|
8231
|
+
as: "h3",
|
|
8232
|
+
DANGEROUS_className: "mb-4",
|
|
8233
|
+
children: _t5({
|
|
8234
|
+
id: "oDAEQq",
|
|
8235
|
+
message: "Ownership"
|
|
8236
|
+
})
|
|
8237
|
+
}), /* @__PURE__ */ jsx(AuthorSelector, {
|
|
8238
|
+
authorId: item?.authorId || null,
|
|
8239
|
+
users,
|
|
8240
|
+
onChange: onAuthorChange
|
|
8241
|
+
})]
|
|
7424
8242
|
})
|
|
7425
|
-
}),
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
})]
|
|
7430
|
-
}),
|
|
7431
|
-
currentUser && currentUser.role >= ROLE_EDITOR$3 && /* @__PURE__ */ jsxs("div", {
|
|
7432
|
-
className: "p-4 border-t",
|
|
7433
|
-
children: [/* @__PURE__ */ jsx(Text, {
|
|
7434
|
-
bold: true,
|
|
7435
|
-
as: "h3",
|
|
7436
|
-
DANGEROUS_className: "mb-4",
|
|
7437
|
-
children: _t5({
|
|
8243
|
+
}),
|
|
8244
|
+
currentUser && currentUser.role >= ROLE_EDITOR$3 && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8245
|
+
id: "bylines",
|
|
8246
|
+
label: _t5({
|
|
7438
8247
|
id: "xLGa7J",
|
|
7439
8248
|
message: "Bylines"
|
|
8249
|
+
}),
|
|
8250
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8251
|
+
className: "p-4",
|
|
8252
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
8253
|
+
bold: true,
|
|
8254
|
+
as: "h3",
|
|
8255
|
+
DANGEROUS_className: "mb-4",
|
|
8256
|
+
children: _t5({
|
|
8257
|
+
id: "xLGa7J",
|
|
8258
|
+
message: "Bylines"
|
|
8259
|
+
})
|
|
8260
|
+
}), /* @__PURE__ */ jsx(BylineCreditsEditor, {
|
|
8261
|
+
credits: activeBylines,
|
|
8262
|
+
bylines: availableBylines ?? [],
|
|
8263
|
+
selectedBylineDetails: item?.bylines?.map((entry) => entry.byline),
|
|
8264
|
+
bylinesLoaded: availableBylinesLoaded,
|
|
8265
|
+
onChange: onBylinesChange,
|
|
8266
|
+
onQuickCreate: onQuickCreateByline,
|
|
8267
|
+
onQuickEdit: onQuickEditByline,
|
|
8268
|
+
entryLocale: item?.locale ?? entryLocale,
|
|
8269
|
+
i18n
|
|
8270
|
+
})]
|
|
7440
8271
|
})
|
|
7441
|
-
}),
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
onQuickCreate: onQuickCreateByline,
|
|
7448
|
-
onQuickEdit: onQuickEditByline,
|
|
7449
|
-
entryLocale: item?.locale ?? entryLocale,
|
|
7450
|
-
i18n
|
|
7451
|
-
})]
|
|
7452
|
-
}),
|
|
7453
|
-
i18n && item && !isNew && /* @__PURE__ */ jsx("div", {
|
|
7454
|
-
className: "p-4 border-t",
|
|
7455
|
-
children: /* @__PURE__ */ jsx(TranslationsPanel, {
|
|
7456
|
-
locales: i18n.locales,
|
|
7457
|
-
defaultLocale: i18n.defaultLocale,
|
|
7458
|
-
currentLocale: item.locale ?? void 0,
|
|
7459
|
-
translations: translations ?? [],
|
|
7460
|
-
onOpen: (tr) => navigate({
|
|
7461
|
-
to: "/content/$collection/$id",
|
|
7462
|
-
params: {
|
|
7463
|
-
collection,
|
|
7464
|
-
id: tr.id
|
|
7465
|
-
},
|
|
7466
|
-
search: { locale: tr.locale }
|
|
8272
|
+
}),
|
|
8273
|
+
i18n && item && !isNew && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8274
|
+
id: "translations",
|
|
8275
|
+
label: _t5({
|
|
8276
|
+
id: "kAy5R9",
|
|
8277
|
+
message: "Translations"
|
|
7467
8278
|
}),
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
8279
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
8280
|
+
className: "p-4",
|
|
8281
|
+
children: /* @__PURE__ */ jsx(TranslationsPanel, {
|
|
8282
|
+
locales: i18n.locales,
|
|
8283
|
+
defaultLocale: i18n.defaultLocale,
|
|
8284
|
+
currentLocale: item.locale ?? void 0,
|
|
8285
|
+
translations: translations ?? [],
|
|
8286
|
+
onOpen: (tr) => navigate({
|
|
8287
|
+
to: "/content/$collection/$id",
|
|
8288
|
+
params: {
|
|
8289
|
+
collection,
|
|
8290
|
+
id: tr.id
|
|
8291
|
+
},
|
|
8292
|
+
search: { locale: tr.locale }
|
|
8293
|
+
}),
|
|
8294
|
+
onCreate: onTranslate
|
|
8295
|
+
})
|
|
8296
|
+
})
|
|
8297
|
+
}),
|
|
8298
|
+
item && hasApplicableTaxonomies && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8299
|
+
id: "taxonomies",
|
|
8300
|
+
label: _t5({
|
|
8301
|
+
id: "sMNeA/",
|
|
8302
|
+
message: "Taxonomies"
|
|
8303
|
+
}),
|
|
8304
|
+
children: /* @__PURE__ */ jsx(TaxonomySidebar, {
|
|
8305
|
+
className: "p-4",
|
|
8306
|
+
collection,
|
|
8307
|
+
entryId: item.id,
|
|
8308
|
+
entryLocale: item.locale ?? entryLocale
|
|
8309
|
+
})
|
|
8310
|
+
}),
|
|
8311
|
+
hasSeo && !isNew && onSeoChange && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8312
|
+
id: "seo",
|
|
8313
|
+
label: _t5({
|
|
7484
8314
|
id: "4Ml90q",
|
|
7485
8315
|
message: "SEO"
|
|
8316
|
+
}),
|
|
8317
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8318
|
+
className: "p-4",
|
|
8319
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
8320
|
+
bold: true,
|
|
8321
|
+
as: "h3",
|
|
8322
|
+
DANGEROUS_className: "mb-4",
|
|
8323
|
+
children: _t5({
|
|
8324
|
+
id: "4Ml90q",
|
|
8325
|
+
message: "SEO"
|
|
8326
|
+
})
|
|
8327
|
+
}), /* @__PURE__ */ jsx(SeoPanel, {
|
|
8328
|
+
contentKey: item?.id ?? `new:${collection}`,
|
|
8329
|
+
seo: item?.seo,
|
|
8330
|
+
onChange: onSeoChange
|
|
8331
|
+
})]
|
|
7486
8332
|
})
|
|
7487
|
-
}),
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
collection,
|
|
7501
|
-
entryId: item.id
|
|
7502
|
-
})
|
|
7503
|
-
}),
|
|
7504
|
-
!isNew && onDelete && /* @__PURE__ */ jsx("div", {
|
|
7505
|
-
className: "border-t p-4",
|
|
7506
|
-
children: /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
7507
|
-
disablePointerDismissal: true,
|
|
7508
|
-
children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
7509
|
-
...p,
|
|
7510
|
-
type: "button",
|
|
7511
|
-
variant: "outline",
|
|
7512
|
-
className: "w-full text-kumo-danger hover:text-kumo-danger",
|
|
7513
|
-
disabled: isDeleting,
|
|
7514
|
-
icon: isDeleting ? /* @__PURE__ */ jsx(Loader, { size: "sm" }) : /* @__PURE__ */ jsx(Trash, {}),
|
|
7515
|
-
children: _t5({
|
|
7516
|
-
id: "q3TWG7",
|
|
7517
|
-
message: "Move to Trash"
|
|
8333
|
+
}),
|
|
8334
|
+
portableTextEditor && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8335
|
+
id: "outline",
|
|
8336
|
+
label: _t5({
|
|
8337
|
+
id: "dD7NPy",
|
|
8338
|
+
message: "Outline"
|
|
8339
|
+
}),
|
|
8340
|
+
disclosure: true,
|
|
8341
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
8342
|
+
className: "p-4",
|
|
8343
|
+
children: /* @__PURE__ */ jsx(DocumentOutline, {
|
|
8344
|
+
editor: portableTextEditor,
|
|
8345
|
+
reserveHeaderEnd: true
|
|
7518
8346
|
})
|
|
7519
|
-
})
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
8347
|
+
})
|
|
8348
|
+
}),
|
|
8349
|
+
!isNew && item && supportsRevisions && /* @__PURE__ */ jsx(SortableContentSettingsSection, {
|
|
8350
|
+
id: "revisions",
|
|
8351
|
+
label: _t5({
|
|
8352
|
+
id: "ZdWn/b",
|
|
8353
|
+
message: "Revisions"
|
|
8354
|
+
}),
|
|
8355
|
+
disclosure: true,
|
|
8356
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
8357
|
+
className: "p-4",
|
|
8358
|
+
children: /* @__PURE__ */ jsx(RevisionHistory, {
|
|
8359
|
+
collection,
|
|
8360
|
+
entryId: item.id,
|
|
8361
|
+
reserveHeaderEnd: true
|
|
8362
|
+
})
|
|
8363
|
+
})
|
|
8364
|
+
})
|
|
8365
|
+
]
|
|
8366
|
+
}), !isNew && onDelete && /* @__PURE__ */ jsx("div", {
|
|
8367
|
+
"data-testid": "content-trash-actions",
|
|
8368
|
+
"aria-hidden": isReorderingSections || void 0,
|
|
8369
|
+
className: cn("border-t p-4", isReorderingSections && "invisible pointer-events-none"),
|
|
8370
|
+
children: /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
8371
|
+
disablePointerDismissal: true,
|
|
8372
|
+
children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8373
|
+
...p,
|
|
8374
|
+
type: "button",
|
|
8375
|
+
variant: "outline",
|
|
8376
|
+
className: "w-full text-kumo-danger hover:text-kumo-danger",
|
|
8377
|
+
disabled: isDeleting,
|
|
8378
|
+
icon: isDeleting ? /* @__PURE__ */ jsx(Loader, { size: "sm" }) : /* @__PURE__ */ jsx(Trash, {}),
|
|
8379
|
+
children: _t5({
|
|
8380
|
+
id: "q3TWG7",
|
|
8381
|
+
message: "Move to Trash"
|
|
8382
|
+
})
|
|
8383
|
+
}) }), /* @__PURE__ */ jsxs(Dialog, {
|
|
8384
|
+
className: "p-6",
|
|
8385
|
+
size: "sm",
|
|
8386
|
+
children: [
|
|
8387
|
+
/* @__PURE__ */ jsx(Dialog.Title, {
|
|
8388
|
+
className: "text-lg font-semibold",
|
|
8389
|
+
children: _t5({
|
|
8390
|
+
id: "eAnjuA",
|
|
8391
|
+
message: "Move to Trash?"
|
|
8392
|
+
})
|
|
8393
|
+
}),
|
|
8394
|
+
/* @__PURE__ */ jsx(Dialog.Description, {
|
|
8395
|
+
className: "text-kumo-subtle",
|
|
8396
|
+
children: _t5({
|
|
8397
|
+
id: "cXBP3V",
|
|
8398
|
+
message: "This will move the item to trash. You can restore it later from the trash."
|
|
8399
|
+
})
|
|
8400
|
+
}),
|
|
8401
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8402
|
+
className: "mt-6 flex justify-end gap-2",
|
|
8403
|
+
children: [/* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8404
|
+
...p,
|
|
8405
|
+
variant: "secondary",
|
|
7525
8406
|
children: _t5({
|
|
7526
|
-
id: "
|
|
7527
|
-
message: "
|
|
8407
|
+
id: "dEgA5A",
|
|
8408
|
+
message: "Cancel"
|
|
7528
8409
|
})
|
|
7529
|
-
}),
|
|
7530
|
-
|
|
7531
|
-
|
|
8410
|
+
}) }), /* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8411
|
+
...p,
|
|
8412
|
+
variant: "destructive",
|
|
8413
|
+
onClick: onDelete,
|
|
7532
8414
|
children: _t5({
|
|
7533
|
-
id: "
|
|
7534
|
-
message: "
|
|
8415
|
+
id: "q3TWG7",
|
|
8416
|
+
message: "Move to Trash"
|
|
7535
8417
|
})
|
|
7536
|
-
})
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
...p,
|
|
7541
|
-
variant: "secondary",
|
|
7542
|
-
children: _t5({
|
|
7543
|
-
id: "dEgA5A",
|
|
7544
|
-
message: "Cancel"
|
|
7545
|
-
})
|
|
7546
|
-
}) }), /* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
7547
|
-
...p,
|
|
7548
|
-
variant: "destructive",
|
|
7549
|
-
onClick: onDelete,
|
|
7550
|
-
children: _t5({
|
|
7551
|
-
id: "q3TWG7",
|
|
7552
|
-
message: "Move to Trash"
|
|
7553
|
-
})
|
|
7554
|
-
}) })]
|
|
7555
|
-
})
|
|
7556
|
-
]
|
|
7557
|
-
})]
|
|
7558
|
-
})
|
|
8418
|
+
}) })]
|
|
8419
|
+
})
|
|
8420
|
+
]
|
|
8421
|
+
})]
|
|
7559
8422
|
})
|
|
7560
|
-
]
|
|
8423
|
+
})]
|
|
7561
8424
|
});
|
|
7562
8425
|
});
|
|
7563
8426
|
function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange, onQuickCreate, onQuickEdit, entryLocale, i18n, bylinesLoaded = true }) {
|
|
@@ -9961,7 +10824,7 @@ function HtmlBlockNodeView({ node, updateAttributes, selected, deleteNode }) {
|
|
|
9961
10824
|
* An atom node that stores raw HTML in a `html` attribute. Round-trips
|
|
9962
10825
|
* through Portable Text as `{ _type: "htmlBlock", _key, html }`.
|
|
9963
10826
|
*/
|
|
9964
|
-
const HtmlBlockExtension = Node$
|
|
10827
|
+
const HtmlBlockExtension = Node$2.create({
|
|
9965
10828
|
name: "htmlBlock",
|
|
9966
10829
|
group: "block",
|
|
9967
10830
|
atom: true,
|
|
@@ -9982,7 +10845,7 @@ const HtmlBlockExtension = Node$1.create({
|
|
|
9982
10845
|
return [{ tag: "div[data-html-block]" }];
|
|
9983
10846
|
},
|
|
9984
10847
|
renderHTML({ HTMLAttributes }) {
|
|
9985
|
-
return ["div", mergeAttributes(HTMLAttributes, { "data-html-block": "" })];
|
|
10848
|
+
return ["div", mergeAttributes$1(HTMLAttributes, { "data-html-block": "" })];
|
|
9986
10849
|
},
|
|
9987
10850
|
addNodeView() {
|
|
9988
10851
|
return ReactNodeViewRenderer(HtmlBlockNodeView);
|
|
@@ -10241,7 +11104,7 @@ function ImageNodeView({ node, updateAttributes, selected, deleteNode, editor })
|
|
|
10241
11104
|
})
|
|
10242
11105
|
});
|
|
10243
11106
|
}
|
|
10244
|
-
const ImageExtension = Node$
|
|
11107
|
+
const ImageExtension = Node$1.create({
|
|
10245
11108
|
name: "image",
|
|
10246
11109
|
addOptions() {
|
|
10247
11110
|
return {
|
|
@@ -10284,7 +11147,7 @@ const ImageExtension = Node$2.create({
|
|
|
10284
11147
|
return [{ tag: "img[src]" }];
|
|
10285
11148
|
},
|
|
10286
11149
|
renderHTML({ HTMLAttributes }) {
|
|
10287
|
-
return ["img", mergeAttributes
|
|
11150
|
+
return ["img", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
|
10288
11151
|
},
|
|
10289
11152
|
addNodeView() {
|
|
10290
11153
|
return ReactNodeViewRenderer(ImageNodeView);
|
|
@@ -10666,7 +11529,7 @@ function PluginBlockNodeView({ node, updateAttributes, selected, deleteNode, edi
|
|
|
10666
11529
|
/**
|
|
10667
11530
|
* TipTap Node extension for plugin blocks (embeds)
|
|
10668
11531
|
*/
|
|
10669
|
-
const PluginBlockExtension = Node$
|
|
11532
|
+
const PluginBlockExtension = Node$2.create({
|
|
10670
11533
|
name: "pluginBlock",
|
|
10671
11534
|
group: "block",
|
|
10672
11535
|
atom: true,
|
|
@@ -10693,7 +11556,7 @@ const PluginBlockExtension = Node$1.create({
|
|
|
10693
11556
|
return [{ tag: "div[data-plugin-block]" }];
|
|
10694
11557
|
},
|
|
10695
11558
|
renderHTML({ HTMLAttributes }) {
|
|
10696
|
-
return ["div", mergeAttributes(HTMLAttributes, { "data-plugin-block": "" })];
|
|
11559
|
+
return ["div", mergeAttributes$1(HTMLAttributes, { "data-plugin-block": "" })];
|
|
10697
11560
|
},
|
|
10698
11561
|
addNodeView() {
|
|
10699
11562
|
return ReactNodeViewRenderer(PluginBlockNodeView);
|
|
@@ -10912,6 +11775,40 @@ const TABLE_BUBBLE_MENU_KEY = "emdashTableBubbleMenu";
|
|
|
10912
11775
|
function generateKey() {
|
|
10913
11776
|
return Math.random().toString(36).substring(2, 11);
|
|
10914
11777
|
}
|
|
11778
|
+
/**
|
|
11779
|
+
* Normalize an untrusted gallery `images` value into well-formed entries.
|
|
11780
|
+
* Mirrors `sanitizeGalleryImages` in core's content/converters (duplicated
|
|
11781
|
+
* like the converters themselves — see note above).
|
|
11782
|
+
*/
|
|
11783
|
+
function sanitizeGalleryImages(value, withKeys = false) {
|
|
11784
|
+
if (!Array.isArray(value)) return [];
|
|
11785
|
+
const images = [];
|
|
11786
|
+
for (const entry of value) {
|
|
11787
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
11788
|
+
const record = entry;
|
|
11789
|
+
const asset = record.asset;
|
|
11790
|
+
if (typeof asset !== "object" || asset === null) continue;
|
|
11791
|
+
const assetRecord = asset;
|
|
11792
|
+
const image = {
|
|
11793
|
+
_type: "image",
|
|
11794
|
+
_key: attrStr(record._key) ?? (withKeys ? generateKey() : ""),
|
|
11795
|
+
asset: {
|
|
11796
|
+
_type: "reference",
|
|
11797
|
+
_ref: typeof assetRecord._ref === "string" ? assetRecord._ref : "",
|
|
11798
|
+
...attrStr(assetRecord.url) ? { url: attrStr(assetRecord.url) } : {},
|
|
11799
|
+
...attrStr(assetRecord.provider) ? { provider: attrStr(assetRecord.provider) } : {}
|
|
11800
|
+
}
|
|
11801
|
+
};
|
|
11802
|
+
if (attrStr(record.alt)) image.alt = attrStr(record.alt);
|
|
11803
|
+
if (attrStr(record.caption)) image.caption = attrStr(record.caption);
|
|
11804
|
+
if (typeof record.width === "number") image.width = record.width;
|
|
11805
|
+
if (typeof record.height === "number") image.height = record.height;
|
|
11806
|
+
if (attrStr(record.blurhash)) image.blurhash = attrStr(record.blurhash);
|
|
11807
|
+
if (attrStr(record.dominantColor)) image.dominantColor = attrStr(record.dominantColor);
|
|
11808
|
+
images.push(image);
|
|
11809
|
+
}
|
|
11810
|
+
return images;
|
|
11811
|
+
}
|
|
10915
11812
|
const attrStr = (v) => typeof v === "string" && v ? v : void 0;
|
|
10916
11813
|
const attrNum = (v) => typeof v === "number" && v ? v : void 0;
|
|
10917
11814
|
function prosemirrorToPortableText(doc) {
|
|
@@ -11022,6 +11919,15 @@ function convertPMNode(node) {
|
|
|
11022
11919
|
_key: generateKey(),
|
|
11023
11920
|
style: "lineBreak"
|
|
11024
11921
|
};
|
|
11922
|
+
case "gallery": {
|
|
11923
|
+
const columns = node.attrs?.columns;
|
|
11924
|
+
return {
|
|
11925
|
+
_type: "gallery",
|
|
11926
|
+
_key: generateKey(),
|
|
11927
|
+
images: sanitizeGalleryImages(node.attrs?.images, true),
|
|
11928
|
+
...typeof columns === "number" ? { columns } : {}
|
|
11929
|
+
};
|
|
11930
|
+
}
|
|
11025
11931
|
case "table": {
|
|
11026
11932
|
const tableKey = generateKey();
|
|
11027
11933
|
const rows = (node.content || []).filter((row) => row.type === "tableRow").map((row, rowIndex) => {
|
|
@@ -11268,6 +12174,24 @@ function convertPTBlock(block) {
|
|
|
11268
12174
|
};
|
|
11269
12175
|
}
|
|
11270
12176
|
case "break": return { type: "horizontalRule" };
|
|
12177
|
+
case "gallery": {
|
|
12178
|
+
const galleryBlock = block;
|
|
12179
|
+
if (!Array.isArray(galleryBlock.images)) return {
|
|
12180
|
+
type: "paragraph",
|
|
12181
|
+
content: [{
|
|
12182
|
+
type: "text",
|
|
12183
|
+
text: `[Unknown block type: ${block._type}]`,
|
|
12184
|
+
marks: [{ type: "code" }]
|
|
12185
|
+
}]
|
|
12186
|
+
};
|
|
12187
|
+
return {
|
|
12188
|
+
type: "gallery",
|
|
12189
|
+
attrs: {
|
|
12190
|
+
images: sanitizeGalleryImages(galleryBlock.images),
|
|
12191
|
+
columns: typeof galleryBlock.columns === "number" ? galleryBlock.columns : void 0
|
|
12192
|
+
}
|
|
12193
|
+
};
|
|
12194
|
+
}
|
|
11271
12195
|
case "htmlBlock": return {
|
|
11272
12196
|
type: "htmlBlock",
|
|
11273
12197
|
attrs: { html: block.html || "" }
|
|
@@ -12433,6 +13357,7 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12433
13357
|
else setInternalFocusMode(mode);
|
|
12434
13358
|
};
|
|
12435
13359
|
const [mediaPickerOpen, setMediaPickerOpen] = React$1.useState(false);
|
|
13360
|
+
const [galleryPickerOpen, setGalleryPickerOpen] = React$1.useState(false);
|
|
12436
13361
|
const [pluginBlockModal, setPluginBlockModal] = React$1.useState(null);
|
|
12437
13362
|
const [pluginBlockInitialValues, setPluginBlockInitialValues] = React$1.useState(void 0);
|
|
12438
13363
|
/** When editing an existing block, store the node position for updateAttributes */
|
|
@@ -12484,6 +13409,32 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12484
13409
|
setMediaPickerOpen(true);
|
|
12485
13410
|
}
|
|
12486
13411
|
});
|
|
13412
|
+
cmds.push({
|
|
13413
|
+
id: "gallery",
|
|
13414
|
+
title: {
|
|
13415
|
+
id: "U+kFad",
|
|
13416
|
+
message: "Gallery"
|
|
13417
|
+
},
|
|
13418
|
+
description: {
|
|
13419
|
+
id: "ojLvJk",
|
|
13420
|
+
message: "Insert an image gallery"
|
|
13421
|
+
},
|
|
13422
|
+
icon: Images,
|
|
13423
|
+
aliases: [
|
|
13424
|
+
"gal",
|
|
13425
|
+
"photos",
|
|
13426
|
+
"grid"
|
|
13427
|
+
],
|
|
13428
|
+
category: {
|
|
13429
|
+
id: "xYilR2",
|
|
13430
|
+
message: "Media"
|
|
13431
|
+
},
|
|
13432
|
+
deferInsertion: true,
|
|
13433
|
+
command: ({ editor, range }) => {
|
|
13434
|
+
editor.chain().focus().deleteRange(range).run();
|
|
13435
|
+
setGalleryPickerOpen(true);
|
|
13436
|
+
}
|
|
13437
|
+
});
|
|
12487
13438
|
cmds.push({
|
|
12488
13439
|
id: "section",
|
|
12489
13440
|
title: {
|
|
@@ -12569,6 +13520,7 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12569
13520
|
}),
|
|
12570
13521
|
CodeBlockExtension,
|
|
12571
13522
|
HtmlBlockExtension,
|
|
13523
|
+
GalleryExtension,
|
|
12572
13524
|
ImageExtension,
|
|
12573
13525
|
MarkdownLinkExtension,
|
|
12574
13526
|
PluginBlockExtension,
|
|
@@ -12797,17 +13749,21 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12797
13749
|
onBlockSidebarCloseRef.current = onBlockSidebarClose;
|
|
12798
13750
|
React$1.useEffect(() => {
|
|
12799
13751
|
if (!editor) return;
|
|
12800
|
-
const
|
|
12801
|
-
|
|
12802
|
-
storage
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
13752
|
+
const editorStorage = editor.storage;
|
|
13753
|
+
const storages = [editorStorage.image, editorStorage.gallery].filter((storage) => storage !== void 0);
|
|
13754
|
+
for (const storage of storages) {
|
|
13755
|
+
storage.onOpenBlockSidebar = (panel) => {
|
|
13756
|
+
onBlockSidebarOpenRef.current?.(panel);
|
|
13757
|
+
};
|
|
13758
|
+
storage.onCloseBlockSidebar = () => {
|
|
13759
|
+
onBlockSidebarCloseRef.current?.();
|
|
13760
|
+
};
|
|
13761
|
+
}
|
|
12808
13762
|
return () => {
|
|
12809
|
-
storage
|
|
12810
|
-
|
|
13763
|
+
for (const storage of storages) {
|
|
13764
|
+
storage.onOpenBlockSidebar = null;
|
|
13765
|
+
storage.onCloseBlockSidebar = null;
|
|
13766
|
+
}
|
|
12811
13767
|
};
|
|
12812
13768
|
}, [editor]);
|
|
12813
13769
|
const handleImageSelect = React$1.useCallback((item) => {
|
|
@@ -12833,6 +13789,23 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12833
13789
|
pendingBlockInsertPosRef.current = null;
|
|
12834
13790
|
setMediaPickerOpen(false);
|
|
12835
13791
|
}, [editor]);
|
|
13792
|
+
const handleGallerySelect = React$1.useCallback((items) => {
|
|
13793
|
+
if (editor && items.length > 0) {
|
|
13794
|
+
const attrs = {
|
|
13795
|
+
images: items.map(mediaItemToGalleryImage),
|
|
13796
|
+
columns: 3
|
|
13797
|
+
};
|
|
13798
|
+
const insertPos = pendingBlockInsertPosRef.current;
|
|
13799
|
+
const chain = editor.chain().focus();
|
|
13800
|
+
if (insertPos === null) chain.setGallery(attrs).run();
|
|
13801
|
+
else chain.insertContentAt(insertPos, {
|
|
13802
|
+
type: "gallery",
|
|
13803
|
+
attrs
|
|
13804
|
+
}).run();
|
|
13805
|
+
}
|
|
13806
|
+
pendingBlockInsertPosRef.current = null;
|
|
13807
|
+
setGalleryPickerOpen(false);
|
|
13808
|
+
}, [editor]);
|
|
12836
13809
|
const handlePluginBlockInsert = React$1.useCallback((values) => {
|
|
12837
13810
|
if (!editor || !pluginBlockModal) return;
|
|
12838
13811
|
const { id, ...data } = values;
|
|
@@ -12948,6 +13921,21 @@ function PortableTextEditor({ value, onChange, placeholder, className, editable
|
|
|
12948
13921
|
message: "Select Image"
|
|
12949
13922
|
})
|
|
12950
13923
|
}),
|
|
13924
|
+
/* @__PURE__ */ jsx(MediaPickerModal, {
|
|
13925
|
+
open: galleryPickerOpen,
|
|
13926
|
+
onOpenChange: (open) => {
|
|
13927
|
+
setGalleryPickerOpen(open);
|
|
13928
|
+
if (!open) pendingBlockInsertPosRef.current = null;
|
|
13929
|
+
},
|
|
13930
|
+
multiple: true,
|
|
13931
|
+
onSelect: () => {},
|
|
13932
|
+
onSelectMany: handleGallerySelect,
|
|
13933
|
+
mimeTypeFilter: "image/",
|
|
13934
|
+
title: _t6({
|
|
13935
|
+
id: "qgANyN",
|
|
13936
|
+
message: "Select Gallery Images"
|
|
13937
|
+
})
|
|
13938
|
+
}),
|
|
12951
13939
|
/* @__PURE__ */ jsx(PluginBlockModal, {
|
|
12952
13940
|
block: pluginBlockModal,
|
|
12953
13941
|
initialValues: pluginBlockInitialValues,
|
|
@@ -14366,6 +15354,7 @@ function MobileSidebarPortalGuard() {
|
|
|
14366
15354
|
if (!isMobile || !openMobile) return;
|
|
14367
15355
|
const nestedOverlaySelector = "[role=\"dialog\"], [role=\"listbox\"], [role=\"menu\"], .kumo-tooltip-popup";
|
|
14368
15356
|
const keepSheetOpen = () => queueMicrotask(() => setOpenMobile(true));
|
|
15357
|
+
const reopenSheetAfterDismiss = () => setTimeout(setOpenMobile, 0, true);
|
|
14369
15358
|
const promotePortal = (element) => {
|
|
14370
15359
|
const portal = (element.closest(nestedOverlaySelector) ?? element.querySelector(nestedOverlaySelector))?.closest("[data-base-ui-portal]");
|
|
14371
15360
|
if (!portal) return;
|
|
@@ -14375,7 +15364,13 @@ function MobileSidebarPortalGuard() {
|
|
|
14375
15364
|
const handleFocusOut = (event) => {
|
|
14376
15365
|
const source = event.target;
|
|
14377
15366
|
const destination = event.relatedTarget;
|
|
14378
|
-
if (!(source instanceof Element)
|
|
15367
|
+
if (!(source instanceof Element)) return;
|
|
15368
|
+
if (source.closest("[data-sortable-handle]") && destination === null) {
|
|
15369
|
+
event.stopPropagation();
|
|
15370
|
+
keepSheetOpen();
|
|
15371
|
+
return;
|
|
15372
|
+
}
|
|
15373
|
+
if (!(destination instanceof Element)) return;
|
|
14379
15374
|
const sheet = source.closest("nav[data-sidebar=\"sidebar\"][data-mobile=\"true\"]");
|
|
14380
15375
|
if (!sheet || sheet.contains(destination)) return;
|
|
14381
15376
|
if (!destination.closest(nestedOverlaySelector)) return;
|
|
@@ -14385,7 +15380,12 @@ function MobileSidebarPortalGuard() {
|
|
|
14385
15380
|
const handleKeyDown = (event) => {
|
|
14386
15381
|
if (event.key !== "Escape") return;
|
|
14387
15382
|
const target = event.target;
|
|
14388
|
-
if (!(target instanceof Element)
|
|
15383
|
+
if (!(target instanceof Element)) return;
|
|
15384
|
+
if (target.closest("[data-sortable-handle][data-sorting=\"true\"]")) {
|
|
15385
|
+
reopenSheetAfterDismiss();
|
|
15386
|
+
return;
|
|
15387
|
+
}
|
|
15388
|
+
if (!target.closest(nestedOverlaySelector)) return;
|
|
14389
15389
|
keepSheetOpen();
|
|
14390
15390
|
};
|
|
14391
15391
|
document.addEventListener("focusout", handleFocusOut, true);
|
|
@@ -28220,6 +29220,15 @@ function SectionEditorForm({ section, isSaving, onSave }) {
|
|
|
28220
29220
|
},
|
|
28221
29221
|
onClose: handleBlockSidebarClose,
|
|
28222
29222
|
inline: true
|
|
29223
|
+
}) : blockSidebarPanel?.type === "gallery" ? /* @__PURE__ */ jsx(GalleryDetailPanel, {
|
|
29224
|
+
attributes: blockSidebarPanel.attrs,
|
|
29225
|
+
onUpdate: (attrs) => blockSidebarPanel.onUpdate(attrs),
|
|
29226
|
+
onDelete: () => {
|
|
29227
|
+
blockSidebarPanel.onDelete();
|
|
29228
|
+
setBlockSidebarPanel(null);
|
|
29229
|
+
},
|
|
29230
|
+
onClose: handleBlockSidebarClose,
|
|
29231
|
+
inline: true
|
|
28223
29232
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
28224
29233
|
className: "rounded-lg border bg-kumo-base p-6 space-y-4",
|
|
28225
29234
|
children: [
|
|
@@ -36570,7 +37579,7 @@ function Widgets() {
|
|
|
36570
37579
|
})
|
|
36571
37580
|
})
|
|
36572
37581
|
});
|
|
36573
|
-
return /* @__PURE__ */ jsxs(DndContext, {
|
|
37582
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(DndContext, {
|
|
36574
37583
|
sensors,
|
|
36575
37584
|
collisionDetection,
|
|
36576
37585
|
onDragStart: handleDragStart,
|
|
@@ -36817,7 +37826,15 @@ function Widgets() {
|
|
|
36817
37826
|
onClose: handleBlockSidebarClose
|
|
36818
37827
|
})
|
|
36819
37828
|
]
|
|
36820
|
-
})
|
|
37829
|
+
}), blockSidebarPanel?.type === "gallery" && /* @__PURE__ */ jsx(GalleryDetailPanel, {
|
|
37830
|
+
attributes: blockSidebarPanel.attrs,
|
|
37831
|
+
onUpdate: (attrs) => blockSidebarPanel.onUpdate(attrs),
|
|
37832
|
+
onDelete: () => {
|
|
37833
|
+
blockSidebarPanel.onDelete();
|
|
37834
|
+
setBlockSidebarPanel(null);
|
|
37835
|
+
},
|
|
37836
|
+
onClose: handleBlockSidebarClose
|
|
37837
|
+
})] });
|
|
36821
37838
|
}
|
|
36822
37839
|
/** A draggable item in the available widgets palette */
|
|
36823
37840
|
function DraggablePaletteItem({ id, label, description, widgetInput }) {
|