tinacms 3.6.3 → 3.7.1
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/index.js +1218 -119
- package/dist/lib/posthog/posthog.d.ts +6 -0
- package/dist/rich-text/index.d.ts +4 -0
- package/dist/rich-text/index.js +14 -0
- package/dist/toolkit/components/dashboard/dashboard-ui.d.ts +16 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/index.d.ts +6 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/media-lightbox.d.ts +6 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/media-usage-scanner.d.ts +21 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/media-usage-table.d.ts +7 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/media-usage-thumbnails.d.ts +5 -0
- package/dist/toolkit/components/dashboard/media-usage-dashboard/useMediaUsageScanner.d.ts +8 -0
- package/dist/toolkit/components/ui/dialog.d.ts +16 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/icons.d.ts +1 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/mark-toolbar-button.d.ts +1 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/editor-plugins.d.ts +3 -3
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/ui/components.d.ts +2 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/toolbar/toolbar-overrides.d.ts +1 -1
- package/dist/toolkit/form-builder/create-branch-modal.d.ts +3 -1
- package/dist/toolkit/plugin-screens/media-usage-dashboard-screen.d.ts +1 -0
- package/dist/toolkit/react-screens/screen-plugin.d.ts +2 -2
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -16,13 +16,14 @@ import { HEADING_KEYS as HEADING_KEYS$1, HEADING_LEVELS as HEADING_LEVELS$1 } fr
|
|
|
16
16
|
import { isHotkey } from "is-hotkey";
|
|
17
17
|
import { Slot } from "@radix-ui/react-slot";
|
|
18
18
|
import { isLangSupported, formatCodeBlock, insertEmptyCodeBlock, unwrapCodeBlock, isCodeBlockEmpty, isSelectionAtCodeBlockStart } from "@udecode/plate-code-block";
|
|
19
|
-
import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Plus, AlignCenter as AlignCenter$1, AlignJustify, AlignLeft as AlignLeft$1, AlignRight as AlignRight$1, PaintBucket, Quote, ChevronRight, ChevronsUpDown, FileCode, Baseline, RectangleVertical, Combine, Ungroup, MessageSquare, MessageSquarePlus, Trash, GripVertical, Edit2, Smile, ExternalLink, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Indent, Keyboard, WrapText, Minus, MoreHorizontal, Outdent, Pilcrow, RotateCcw, RectangleHorizontal, Settings, Strikethrough, Subscript, Superscript, Table as Table$1, Text as Text$2, Underline, Link2Off, Eye, SeparatorHorizontal, Moon, SunMedium, Twitter, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, ChevronDownIcon as ChevronDownIcon$1, ChevronUp, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, ArrowUpDown, LoaderCircle, TriangleAlert, FileStack, History, GitBranchIcon, List as List$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink } from "lucide-react";
|
|
19
|
+
import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Plus, AlignCenter as AlignCenter$1, AlignJustify, AlignLeft as AlignLeft$1, AlignRight as AlignRight$1, PaintBucket, Quote, ChevronRight, ChevronsUpDown, FileCode, Baseline, RectangleVertical, Combine, Ungroup, MessageSquare, MessageSquarePlus, Trash, GripVertical, Edit2, Smile, ExternalLink, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Indent, Keyboard, WrapText, Minus, MoreHorizontal, Outdent, Pilcrow, RotateCcw, RectangleHorizontal, Settings, Highlighter, Strikethrough, Subscript, Superscript, Table as Table$1, Text as Text$2, Underline, Link2Off, Eye, SeparatorHorizontal, Moon, SunMedium, Twitter, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, ChevronDownIcon as ChevronDownIcon$1, ChevronUp, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, ArrowUpDown, AlertCircle, Image, RefreshCw, Database, CheckCircle2, ImageOff, LoaderCircle, TriangleAlert, FileStack, History, GitBranchIcon, List as List$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink } from "lucide-react";
|
|
20
20
|
import mermaid from "mermaid";
|
|
21
21
|
import { cva } from "class-variance-authority";
|
|
22
22
|
import { Command as Command$2 } from "cmdk";
|
|
23
23
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
24
24
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
25
25
|
import { PopoverAnchor } from "@radix-ui/react-popover";
|
|
26
|
+
import posthog from "posthog-js";
|
|
26
27
|
import { createSlatePlugin as createSlatePlugin$1, someHtmlElement, findHtmlParentElement, createTSlatePlugin as createTSlatePlugin$1, RangeApi as RangeApi$1, TextApi as TextApi$1, HtmlPlugin as HtmlPlugin$1, NodeApi as NodeApi$1, ElementApi as ElementApi$1, Hotkeys, isHotkey as isHotkey$1, isUrl as isUrl$1, getEditorPlugin as getEditorPlugin$1, bindFirst as bindFirst$1, sanitizeUrl, PathApi as PathApi$1, isDefined as isDefined$1, PointApi as PointApi$1, BaseParagraphPlugin as BaseParagraphPlugin$1, match as match$2, deleteMerge, getPluginTypes, queryNode as queryNode$1, isType, getInjectMatch as getInjectMatch$1, traverseHtmlElements, isHtmlBlockElement as isHtmlBlockElement$1, postCleanHtml, mergeProps } from "@udecode/plate";
|
|
27
28
|
import { useComboboxContext, Combobox as Combobox$1, useComboboxStore, ComboboxProvider, Portal, ComboboxPopover, ComboboxItem } from "@ariakit/react";
|
|
28
29
|
import { withTriggerCombobox, filterWords } from "@udecode/plate-combobox";
|
|
@@ -35,6 +36,7 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
|
35
36
|
import * as ToolbarPrimitive from "@radix-ui/react-toolbar";
|
|
36
37
|
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
37
38
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
39
|
+
import colorString, { get as get$6, to as to$1 } from "color-string";
|
|
38
40
|
import { createForm, FORM_ERROR, getIn } from "final-form";
|
|
39
41
|
import arrayMutators from "final-form-arrays";
|
|
40
42
|
import setFieldData from "final-form-set-field-data";
|
|
@@ -45,8 +47,6 @@ import { sortableKeyboardCoordinates, useSortable, SortableContext, verticalList
|
|
|
45
47
|
import { CSS } from "@dnd-kit/utilities";
|
|
46
48
|
import { buildSchema, print, getIntrospectionQuery, buildClientSchema, parse as parse$4 } from "graphql";
|
|
47
49
|
import { diff as diff$1 } from "@graphql-inspector/core";
|
|
48
|
-
import posthog from "posthog-js";
|
|
49
|
-
import { get as get$6, to as to$1 } from "color-string";
|
|
50
50
|
import { HexColorPicker } from "react-colorful";
|
|
51
51
|
import * as dropzone from "react-dropzone";
|
|
52
52
|
import { Command as Command$3 } from "@udecode/cmdk";
|
|
@@ -63,7 +63,7 @@ import "moment-timezone";
|
|
|
63
63
|
import { DayPicker } from "react-day-picker";
|
|
64
64
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
65
65
|
import { formatDistanceToNow } from "date-fns";
|
|
66
|
-
import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender } from "@tanstack/react-table";
|
|
66
|
+
import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender, getFilteredRowModel, getExpandedRowModel } from "@tanstack/react-table";
|
|
67
67
|
import { TinaSchema, addNamespaceToSchema, parseURL, resolveForm, normalizePath, canonicalPath, validateSchema } from "@tinacms/schema-tools";
|
|
68
68
|
import { NAMER, resolveField } from "@tinacms/schema-tools";
|
|
69
69
|
import gql from "graphql-tag";
|
|
@@ -27490,6 +27490,35 @@ var CodeBlockPlugin = toPlatePlugin(BaseCodeBlockPlugin, {
|
|
|
27490
27490
|
}
|
|
27491
27491
|
}
|
|
27492
27492
|
}));
|
|
27493
|
+
var BaseHighlightPlugin = createSlatePlugin$1({
|
|
27494
|
+
key: "highlight",
|
|
27495
|
+
node: { isLeaf: true },
|
|
27496
|
+
parsers: {
|
|
27497
|
+
html: {
|
|
27498
|
+
deserializer: {
|
|
27499
|
+
rules: [
|
|
27500
|
+
{
|
|
27501
|
+
validNodeName: ["MARK"]
|
|
27502
|
+
}
|
|
27503
|
+
]
|
|
27504
|
+
}
|
|
27505
|
+
}
|
|
27506
|
+
}
|
|
27507
|
+
});
|
|
27508
|
+
var HighlightPlugin = toPlatePlugin(
|
|
27509
|
+
BaseHighlightPlugin,
|
|
27510
|
+
({ editor, type: type2 }) => ({
|
|
27511
|
+
shortcuts: {
|
|
27512
|
+
toggleHighlight: {
|
|
27513
|
+
keys: [[Key2.Mod, Key2.Shift, "h"]],
|
|
27514
|
+
preventDefault: true,
|
|
27515
|
+
handler: () => {
|
|
27516
|
+
editor.tf.toggleMark(type2);
|
|
27517
|
+
}
|
|
27518
|
+
}
|
|
27519
|
+
}
|
|
27520
|
+
})
|
|
27521
|
+
);
|
|
27493
27522
|
var BaseHorizontalRulePlugin = createSlatePlugin$1({
|
|
27494
27523
|
key: "hr",
|
|
27495
27524
|
node: { isElement: true, isVoid: true },
|
|
@@ -33620,13 +33649,13 @@ const Button$3 = withRef$1(({ asChild = false, className, isMenu, size: size2, v
|
|
|
33620
33649
|
}
|
|
33621
33650
|
);
|
|
33622
33651
|
});
|
|
33623
|
-
const DialogPortal = DialogPrimitive.Portal;
|
|
33624
|
-
const DialogOverlay = withCn(
|
|
33652
|
+
const DialogPortal$1 = DialogPrimitive.Portal;
|
|
33653
|
+
const DialogOverlay$1 = withCn(
|
|
33625
33654
|
DialogPrimitive.Overlay,
|
|
33626
33655
|
"fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0"
|
|
33627
33656
|
);
|
|
33628
33657
|
withRef$1(
|
|
33629
|
-
({ children, className, ...props }, ref) => /* @__PURE__ */ React.createElement(DialogPortal, null, /* @__PURE__ */ React.createElement(DialogOverlay, null), /* @__PURE__ */ React.createElement(
|
|
33658
|
+
({ children, className, ...props }, ref) => /* @__PURE__ */ React.createElement(DialogPortal$1, null, /* @__PURE__ */ React.createElement(DialogOverlay$1, null), /* @__PURE__ */ React.createElement(
|
|
33630
33659
|
DialogPrimitive.Content,
|
|
33631
33660
|
{
|
|
33632
33661
|
ref,
|
|
@@ -34458,6 +34487,7 @@ const Icons = {
|
|
|
34458
34487
|
row: RectangleHorizontal,
|
|
34459
34488
|
search: Search,
|
|
34460
34489
|
settings: Settings,
|
|
34490
|
+
highlight: Highlighter,
|
|
34461
34491
|
strikethrough: Strikethrough,
|
|
34462
34492
|
subscript: Subscript,
|
|
34463
34493
|
superscript: Superscript,
|
|
@@ -34724,6 +34754,101 @@ function ItalicIcon(props) {
|
|
|
34724
34754
|
))
|
|
34725
34755
|
);
|
|
34726
34756
|
}
|
|
34757
|
+
const BranchSwitchedEvent = "branch-switched";
|
|
34758
|
+
const BranchSwitcherOpenedEvent = "branch-switcher-opened";
|
|
34759
|
+
const BranchSwitcherSearchEvent = "branch-switcher-search";
|
|
34760
|
+
const BranchSwitcherDropDownEvent = "branch-switcher-dropdown";
|
|
34761
|
+
const BranchSwitcherPRClickedEvent = "branch-switcher-pr-clicked";
|
|
34762
|
+
const SavedContentEvent = "saved-content";
|
|
34763
|
+
const SaveContentErrorEvent = "save-content-error";
|
|
34764
|
+
const FormResetEvent = "form-reset";
|
|
34765
|
+
const MediaManagerContentUploadedEvent = "media-manager-content-uploaded";
|
|
34766
|
+
const MediaManagerContentDeletedEvent = "media-manager-content-deleted";
|
|
34767
|
+
const RichTextEditorSwitchedEvent = "rich-text-editor-switched";
|
|
34768
|
+
const EventLogPageViewedEvent = "event-log-page-viewed";
|
|
34769
|
+
const TinaCMSStartedEvent = "tina-cms-started";
|
|
34770
|
+
const CollectionListPageItemClickedEvent = "collection-list-page-item-clicked";
|
|
34771
|
+
const CollectionListPageSortEvent = "collection-list-page-sort";
|
|
34772
|
+
const CollectionListPageSearchEvent = "collection-list-page-search";
|
|
34773
|
+
const CloudConfigNavComponentClickedEvent = "cloud-config-nav-component-clicked";
|
|
34774
|
+
const SlashCommandOpenedEvent = "slash-command-opened";
|
|
34775
|
+
const SlashCommandUsedEvent = "slash-command-used";
|
|
34776
|
+
let posthogClient = null;
|
|
34777
|
+
let isInitialized = false;
|
|
34778
|
+
let initializationPromise = null;
|
|
34779
|
+
const POSTHOG_CONFIG_ENDPOINT = "https://identity-v2.tinajs.io/v2/posthog-token";
|
|
34780
|
+
async function fetchPostHogConfig() {
|
|
34781
|
+
try {
|
|
34782
|
+
const response = await fetch(POSTHOG_CONFIG_ENDPOINT, {
|
|
34783
|
+
method: "GET",
|
|
34784
|
+
headers: {
|
|
34785
|
+
"Content-Type": "application/json"
|
|
34786
|
+
}
|
|
34787
|
+
});
|
|
34788
|
+
if (!response.ok) {
|
|
34789
|
+
console.warn(`Failed to fetch PostHog config: ${response.statusText}`);
|
|
34790
|
+
return {};
|
|
34791
|
+
}
|
|
34792
|
+
return await response.json();
|
|
34793
|
+
} catch (error2) {
|
|
34794
|
+
console.warn(
|
|
34795
|
+
"Failed to fetch PostHog config:",
|
|
34796
|
+
error2 instanceof Error ? error2.message : "Unknown error"
|
|
34797
|
+
);
|
|
34798
|
+
return {};
|
|
34799
|
+
}
|
|
34800
|
+
}
|
|
34801
|
+
async function initializePostHog(mode = "anonymous") {
|
|
34802
|
+
if (isInitialized) {
|
|
34803
|
+
return posthogClient;
|
|
34804
|
+
}
|
|
34805
|
+
if (initializationPromise) {
|
|
34806
|
+
return initializationPromise;
|
|
34807
|
+
}
|
|
34808
|
+
if (mode === "disabled") {
|
|
34809
|
+
isInitialized = true;
|
|
34810
|
+
return null;
|
|
34811
|
+
}
|
|
34812
|
+
if (process.env.TINA_DEV === "true") {
|
|
34813
|
+
isInitialized = true;
|
|
34814
|
+
return null;
|
|
34815
|
+
}
|
|
34816
|
+
initializationPromise = (async () => {
|
|
34817
|
+
const config = await fetchPostHogConfig();
|
|
34818
|
+
if (!config.api_key) {
|
|
34819
|
+
console.warn(
|
|
34820
|
+
"PostHog API key not found. PostHog tracking will be disabled."
|
|
34821
|
+
);
|
|
34822
|
+
isInitialized = true;
|
|
34823
|
+
return null;
|
|
34824
|
+
}
|
|
34825
|
+
posthog.init(config.api_key, {
|
|
34826
|
+
api_host: config.host || "https://us.i.posthog.com",
|
|
34827
|
+
persistence: "localStorage",
|
|
34828
|
+
autocapture: false,
|
|
34829
|
+
capture_pageview: false,
|
|
34830
|
+
disable_session_recording: true,
|
|
34831
|
+
disable_compression: true
|
|
34832
|
+
});
|
|
34833
|
+
posthogClient = posthog;
|
|
34834
|
+
isInitialized = true;
|
|
34835
|
+
return posthogClient;
|
|
34836
|
+
})();
|
|
34837
|
+
return initializationPromise;
|
|
34838
|
+
}
|
|
34839
|
+
function captureEvent(event, properties2) {
|
|
34840
|
+
if (!posthogClient) {
|
|
34841
|
+
return;
|
|
34842
|
+
}
|
|
34843
|
+
try {
|
|
34844
|
+
posthogClient.capture(event, {
|
|
34845
|
+
...properties2,
|
|
34846
|
+
system: "tinacms/tinacms"
|
|
34847
|
+
});
|
|
34848
|
+
} catch (error2) {
|
|
34849
|
+
console.error("Error capturing PostHog event:", error2);
|
|
34850
|
+
}
|
|
34851
|
+
}
|
|
34727
34852
|
var useComboboxInput = ({
|
|
34728
34853
|
autoFocus = true,
|
|
34729
34854
|
cancelInputOnArrowLeftRight = true,
|
|
@@ -34873,7 +34998,7 @@ const InlineCombobox = ({
|
|
|
34873
34998
|
},
|
|
34874
34999
|
[setValueProp, hasValueProp]
|
|
34875
35000
|
);
|
|
34876
|
-
const
|
|
35001
|
+
const insertPoint = React__default.useRef(null);
|
|
34877
35002
|
useEffect(() => {
|
|
34878
35003
|
const path3 = editor.api.findPath(element);
|
|
34879
35004
|
if (!path3)
|
|
@@ -34882,7 +35007,7 @@ const InlineCombobox = ({
|
|
|
34882
35007
|
if (!point3)
|
|
34883
35008
|
return;
|
|
34884
35009
|
const pointRef3 = editor.api.pointRef(point3);
|
|
34885
|
-
|
|
35010
|
+
insertPoint.current = pointRef3.current;
|
|
34886
35011
|
return () => {
|
|
34887
35012
|
pointRef3.unref();
|
|
34888
35013
|
};
|
|
@@ -34896,12 +35021,6 @@ const InlineCombobox = ({
|
|
|
34896
35021
|
at: (insertPoint == null ? void 0 : insertPoint.current) ?? void 0
|
|
34897
35022
|
});
|
|
34898
35023
|
}
|
|
34899
|
-
if (cause === "arrowLeft" || cause === "arrowRight") {
|
|
34900
|
-
editor.tf.move({
|
|
34901
|
-
distance: 1,
|
|
34902
|
-
reverse: cause === "arrowLeft"
|
|
34903
|
-
});
|
|
34904
|
-
}
|
|
34905
35024
|
},
|
|
34906
35025
|
ref: inputRef
|
|
34907
35026
|
});
|
|
@@ -35099,6 +35218,9 @@ const rules = [
|
|
|
35099
35218
|
const SlashInputElement = withRef$1(
|
|
35100
35219
|
({ className, ...props }, ref) => {
|
|
35101
35220
|
const { children, editor, element } = props;
|
|
35221
|
+
useEffect(() => {
|
|
35222
|
+
captureEvent(SlashCommandOpenedEvent);
|
|
35223
|
+
}, []);
|
|
35102
35224
|
return /* @__PURE__ */ React__default.createElement(
|
|
35103
35225
|
PlateElement,
|
|
35104
35226
|
{
|
|
@@ -35112,7 +35234,12 @@ const SlashInputElement = withRef$1(
|
|
|
35112
35234
|
{
|
|
35113
35235
|
key: value,
|
|
35114
35236
|
keywords: keywords2,
|
|
35115
|
-
onClick: () =>
|
|
35237
|
+
onClick: () => {
|
|
35238
|
+
onSelect(editor);
|
|
35239
|
+
captureEvent(SlashCommandUsedEvent, {
|
|
35240
|
+
command: value
|
|
35241
|
+
});
|
|
35242
|
+
},
|
|
35116
35243
|
value
|
|
35117
35244
|
},
|
|
35118
35245
|
/* @__PURE__ */ React__default.createElement(Icon, { "aria-hidden": true, className: "mr-2 size-4" }),
|
|
@@ -37561,6 +37688,30 @@ const uuid = () => {
|
|
|
37561
37688
|
};
|
|
37562
37689
|
const blockClasses = "mt-0.5";
|
|
37563
37690
|
const headerClasses = "font-normal";
|
|
37691
|
+
function getContrastColor(color) {
|
|
37692
|
+
const parsed = colorString.get.rgb(color);
|
|
37693
|
+
if (!parsed)
|
|
37694
|
+
return "#000000";
|
|
37695
|
+
const [r2, g, b] = parsed;
|
|
37696
|
+
const luminance = (0.299 * r2 + 0.587 * g + 0.114 * b) / 255;
|
|
37697
|
+
return luminance > 0.5 ? "#000000" : "#ffffff";
|
|
37698
|
+
}
|
|
37699
|
+
const HighlightLeaf = ({
|
|
37700
|
+
leaf: leaf3,
|
|
37701
|
+
...props
|
|
37702
|
+
}) => {
|
|
37703
|
+
const backgroundColor = leaf3.highlightColor || "#FEF08A";
|
|
37704
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
37705
|
+
PlateLeaf,
|
|
37706
|
+
{
|
|
37707
|
+
as: "mark",
|
|
37708
|
+
className: "rounded-sm",
|
|
37709
|
+
style: { backgroundColor, color: getContrastColor(backgroundColor) },
|
|
37710
|
+
leaf: leaf3,
|
|
37711
|
+
...props
|
|
37712
|
+
}
|
|
37713
|
+
);
|
|
37714
|
+
};
|
|
37564
37715
|
const Components = () => {
|
|
37565
37716
|
return {
|
|
37566
37717
|
[SlashInputPlugin.key]: SlashInputElement,
|
|
@@ -37719,6 +37870,7 @@ const Components = () => {
|
|
|
37719
37870
|
[ListItemPlugin.key]: withProps(PlateElement, { as: "li" }),
|
|
37720
37871
|
[LinkPlugin.key]: LinkElement,
|
|
37721
37872
|
[CodePlugin.key]: CodeLeaf,
|
|
37873
|
+
[HighlightPlugin.key]: HighlightLeaf,
|
|
37722
37874
|
[UnderlinePlugin.key]: withProps(PlateLeaf, { as: "u" }),
|
|
37723
37875
|
[StrikethroughPlugin.key]: withProps(PlateLeaf, { as: "s" }),
|
|
37724
37876
|
[ItalicPlugin.key]: withProps(PlateLeaf, { as: "em" }),
|
|
@@ -39939,6 +40091,9 @@ function MdAccessTime(props) {
|
|
|
39939
40091
|
function MdKeyboardArrowDown(props) {
|
|
39940
40092
|
return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0V0z" }, "child": [] }, { "tag": "path", "attr": { "d": "M7.41 8.59 12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" }, "child": [] }] })(props);
|
|
39941
40093
|
}
|
|
40094
|
+
function MdImage(props) {
|
|
40095
|
+
return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0z" }, "child": [] }, { "tag": "path", "attr": { "d": "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }, "child": [] }] })(props);
|
|
40096
|
+
}
|
|
39942
40097
|
function MdArrowForward(props) {
|
|
39943
40098
|
return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0z" }, "child": [] }, { "tag": "path", "attr": { "d": "m12 4-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" }, "child": [] }] })(props);
|
|
39944
40099
|
}
|
|
@@ -41458,7 +41613,15 @@ const Blocks = ({
|
|
|
41458
41613
|
meta,
|
|
41459
41614
|
index
|
|
41460
41615
|
}) => {
|
|
41461
|
-
const
|
|
41616
|
+
const [newObjects, setNewObjects] = useState(/* @__PURE__ */ new Set());
|
|
41617
|
+
const prevPristine = useRef(meta.pristine);
|
|
41618
|
+
useEffect(() => {
|
|
41619
|
+
if (!prevPristine.current && meta.pristine) {
|
|
41620
|
+
setNewObjects(/* @__PURE__ */ new Set());
|
|
41621
|
+
}
|
|
41622
|
+
prevPristine.current = meta.pristine;
|
|
41623
|
+
}, [meta.pristine]);
|
|
41624
|
+
const addItem = useCallback(
|
|
41462
41625
|
(name2, template) => {
|
|
41463
41626
|
let obj = {};
|
|
41464
41627
|
if (typeof template.defaultItem === "function") {
|
|
@@ -41467,6 +41630,7 @@ const Blocks = ({
|
|
|
41467
41630
|
obj = template.defaultItem || {};
|
|
41468
41631
|
}
|
|
41469
41632
|
obj._template = name2;
|
|
41633
|
+
setNewObjects((prev) => new Set(prev).add(obj));
|
|
41470
41634
|
form.mutators.push(field.name, obj);
|
|
41471
41635
|
},
|
|
41472
41636
|
[field.name, form.mutators]
|
|
@@ -41529,6 +41693,7 @@ const Blocks = ({
|
|
|
41529
41693
|
tinaForm,
|
|
41530
41694
|
isMin,
|
|
41531
41695
|
fixedLength,
|
|
41696
|
+
isNew: newObjects.has(block2),
|
|
41532
41697
|
...itemProps(block2)
|
|
41533
41698
|
}
|
|
41534
41699
|
);
|
|
@@ -41543,7 +41708,8 @@ const BlockListItem = ({
|
|
|
41543
41708
|
index,
|
|
41544
41709
|
template,
|
|
41545
41710
|
isMin,
|
|
41546
|
-
fixedLength
|
|
41711
|
+
fixedLength,
|
|
41712
|
+
isNew
|
|
41547
41713
|
}) => {
|
|
41548
41714
|
const cms = useCMS$1();
|
|
41549
41715
|
const removeItem = React.useCallback(() => {
|
|
@@ -41587,6 +41753,7 @@ const BlockListItem = ({
|
|
|
41587
41753
|
onMouseOut: () => setHoveredField({ id: null, fieldName: null })
|
|
41588
41754
|
},
|
|
41589
41755
|
/* @__PURE__ */ React.createElement(GroupLabel, null, label || template.label),
|
|
41756
|
+
isNew && /* @__PURE__ */ React.createElement("span", { className: "mr-1.5 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] border-[0.5px] border-tina-orange/50 font-semibold bg-tina-orange/10 text-tina-orange leading-none" }, "NEW"),
|
|
41590
41757
|
/* @__PURE__ */ React.createElement(BiPencil, { className: "h-5 w-auto fill-current text-gray-200 group-hover:text-inherit transition-colors duration-150 ease-out" })
|
|
41591
41758
|
), (!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React.createElement(ItemDeleteButton, { disabled: isMin, onClick: removeItem }))));
|
|
41592
41759
|
};
|
|
@@ -43958,99 +44125,6 @@ const TableCaption = React.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
43958
44125
|
}
|
|
43959
44126
|
));
|
|
43960
44127
|
TableCaption.displayName = "TableCaption";
|
|
43961
|
-
let posthogClient = null;
|
|
43962
|
-
let isInitialized = false;
|
|
43963
|
-
let initializationPromise = null;
|
|
43964
|
-
const POSTHOG_CONFIG_ENDPOINT = "https://identity-v2.tinajs.io/v2/posthog-token";
|
|
43965
|
-
async function fetchPostHogConfig() {
|
|
43966
|
-
try {
|
|
43967
|
-
const response = await fetch(POSTHOG_CONFIG_ENDPOINT, {
|
|
43968
|
-
method: "GET",
|
|
43969
|
-
headers: {
|
|
43970
|
-
"Content-Type": "application/json"
|
|
43971
|
-
}
|
|
43972
|
-
});
|
|
43973
|
-
if (!response.ok) {
|
|
43974
|
-
console.warn(`Failed to fetch PostHog config: ${response.statusText}`);
|
|
43975
|
-
return {};
|
|
43976
|
-
}
|
|
43977
|
-
return await response.json();
|
|
43978
|
-
} catch (error2) {
|
|
43979
|
-
console.warn(
|
|
43980
|
-
"Failed to fetch PostHog config:",
|
|
43981
|
-
error2 instanceof Error ? error2.message : "Unknown error"
|
|
43982
|
-
);
|
|
43983
|
-
return {};
|
|
43984
|
-
}
|
|
43985
|
-
}
|
|
43986
|
-
async function initializePostHog(mode = "anonymous") {
|
|
43987
|
-
if (isInitialized) {
|
|
43988
|
-
return posthogClient;
|
|
43989
|
-
}
|
|
43990
|
-
if (initializationPromise) {
|
|
43991
|
-
return initializationPromise;
|
|
43992
|
-
}
|
|
43993
|
-
if (mode === "disabled") {
|
|
43994
|
-
isInitialized = true;
|
|
43995
|
-
return null;
|
|
43996
|
-
}
|
|
43997
|
-
if (process.env.TINA_DEV === "true") {
|
|
43998
|
-
isInitialized = true;
|
|
43999
|
-
return null;
|
|
44000
|
-
}
|
|
44001
|
-
initializationPromise = (async () => {
|
|
44002
|
-
const config = await fetchPostHogConfig();
|
|
44003
|
-
if (!config.api_key) {
|
|
44004
|
-
console.warn(
|
|
44005
|
-
"PostHog API key not found. PostHog tracking will be disabled."
|
|
44006
|
-
);
|
|
44007
|
-
isInitialized = true;
|
|
44008
|
-
return null;
|
|
44009
|
-
}
|
|
44010
|
-
posthog.init(config.api_key, {
|
|
44011
|
-
api_host: config.host || "https://us.i.posthog.com",
|
|
44012
|
-
persistence: "localStorage",
|
|
44013
|
-
autocapture: false,
|
|
44014
|
-
capture_pageview: false,
|
|
44015
|
-
disable_session_recording: true,
|
|
44016
|
-
disable_compression: true
|
|
44017
|
-
});
|
|
44018
|
-
posthogClient = posthog;
|
|
44019
|
-
isInitialized = true;
|
|
44020
|
-
return posthogClient;
|
|
44021
|
-
})();
|
|
44022
|
-
return initializationPromise;
|
|
44023
|
-
}
|
|
44024
|
-
function captureEvent(event, properties2) {
|
|
44025
|
-
if (!posthogClient) {
|
|
44026
|
-
return;
|
|
44027
|
-
}
|
|
44028
|
-
try {
|
|
44029
|
-
posthogClient.capture(event, {
|
|
44030
|
-
...properties2,
|
|
44031
|
-
system: "tinacms/tinacms"
|
|
44032
|
-
});
|
|
44033
|
-
} catch (error2) {
|
|
44034
|
-
console.error("Error capturing PostHog event:", error2);
|
|
44035
|
-
}
|
|
44036
|
-
}
|
|
44037
|
-
const BranchSwitchedEvent = "branch-switched";
|
|
44038
|
-
const BranchSwitcherOpenedEvent = "branch-switcher-opened";
|
|
44039
|
-
const BranchSwitcherSearchEvent = "branch-switcher-search";
|
|
44040
|
-
const BranchSwitcherDropDownEvent = "branch-switcher-dropdown";
|
|
44041
|
-
const BranchSwitcherPRClickedEvent = "branch-switcher-pr-clicked";
|
|
44042
|
-
const SavedContentEvent = "saved-content";
|
|
44043
|
-
const SaveContentErrorEvent = "save-content-error";
|
|
44044
|
-
const FormResetEvent = "form-reset";
|
|
44045
|
-
const MediaManagerContentUploadedEvent = "media-manager-content-uploaded";
|
|
44046
|
-
const MediaManagerContentDeletedEvent = "media-manager-content-deleted";
|
|
44047
|
-
const RichTextEditorSwitchedEvent = "rich-text-editor-switched";
|
|
44048
|
-
const EventLogPageViewedEvent = "event-log-page-viewed";
|
|
44049
|
-
const TinaCMSStartedEvent = "tina-cms-started";
|
|
44050
|
-
const CollectionListPageItemClickedEvent = "collection-list-page-item-clicked";
|
|
44051
|
-
const CollectionListPageSortEvent = "collection-list-page-sort";
|
|
44052
|
-
const CollectionListPageSearchEvent = "collection-list-page-search";
|
|
44053
|
-
const CloudConfigNavComponentClickedEvent = "cloud-config-nav-component-clicked";
|
|
44054
44128
|
const IndexStatus$1 = ({ indexingStatus }) => {
|
|
44055
44129
|
const styles = {
|
|
44056
44130
|
complete: {
|
|
@@ -46796,6 +46870,882 @@ const PasswordScreenPlugin = createScreen({
|
|
|
46796
46870
|
layout: "fullscreen",
|
|
46797
46871
|
navCategory: "Account"
|
|
46798
46872
|
});
|
|
46873
|
+
const DashboardLoadingState = ({
|
|
46874
|
+
message,
|
|
46875
|
+
progress
|
|
46876
|
+
}) => /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center justify-center p-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-gray-500" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg font-semibold text-gray-700 animate-pulse" }, "Loading Dashboard"), /* @__PURE__ */ React__default.createElement("p", { className: "mt-2 text-sm" }, message), progress ? /* @__PURE__ */ React__default.createElement("div", { className: "mt-4 w-72 max-w-full mx-auto" }, /* @__PURE__ */ React__default.createElement("div", { className: "h-2 rounded-full bg-gray-200 overflow-hidden" }, /* @__PURE__ */ React__default.createElement(
|
|
46877
|
+
"div",
|
|
46878
|
+
{
|
|
46879
|
+
className: "h-full bg-tina-orange transition-[width] duration-300 ease-out",
|
|
46880
|
+
style: {
|
|
46881
|
+
width: `${Math.max(0, Math.min(100, progress.value))}%`
|
|
46882
|
+
}
|
|
46883
|
+
}
|
|
46884
|
+
)), /* @__PURE__ */ React__default.createElement("div", { className: "mt-2 flex items-center justify-between text-xs text-gray-500" }, /* @__PURE__ */ React__default.createElement("span", null, progress.label || "In progress"), /* @__PURE__ */ React__default.createElement("span", null, Math.round(progress.value), "%"))) : /* @__PURE__ */ React__default.createElement("div", { className: "mt-4 flex justify-center" }, /* @__PURE__ */ React__default.createElement(LoadingDots, { color: "var(--tina-color-primary)" }))));
|
|
46885
|
+
const DashboardErrorState = ({ message }) => /* @__PURE__ */ React__default.createElement("div", { className: "p-8 text-red-500 bg-red-50 rounded-lg m-8" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg font-bold mb-2 flex items-center gap-2" }, /* @__PURE__ */ React__default.createElement(AlertCircle, { className: "text-xl" }), " Dashboard Error"), /* @__PURE__ */ React__default.createElement("p", null, message));
|
|
46886
|
+
const DashboardTitleBar = ({
|
|
46887
|
+
title,
|
|
46888
|
+
icon,
|
|
46889
|
+
controls
|
|
46890
|
+
}) => /* @__PURE__ */ React__default.createElement("div", { className: "mb-6 flex items-center justify-between gap-4" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-3xl text-tina-orange" }, icon), /* @__PURE__ */ React__default.createElement("h2", { className: "text-2xl font-bold text-gray-800" }, title)), controls);
|
|
46891
|
+
const MEDIA_USAGE_THUMBNAIL_SIZE = { w: 75, h: 75 };
|
|
46892
|
+
const MEDIA_USAGE_THUMBNAIL_KEY = `${MEDIA_USAGE_THUMBNAIL_SIZE.w}x${MEDIA_USAGE_THUMBNAIL_SIZE.h}`;
|
|
46893
|
+
const getDocumentEditUrl = async (cms, document2) => {
|
|
46894
|
+
var _a2;
|
|
46895
|
+
const collectionName = document2._sys.collection.name;
|
|
46896
|
+
const breadcrumbsDerivedPath = document2._sys.breadcrumbs.join("/");
|
|
46897
|
+
let editUrl = `#/collections/edit/${collectionName}/~/${breadcrumbsDerivedPath}`;
|
|
46898
|
+
try {
|
|
46899
|
+
const collection = cms.api.tina.schema.getCollection(collectionName);
|
|
46900
|
+
if ((_a2 = collection == null ? void 0 : collection.ui) == null ? void 0 : _a2.router) {
|
|
46901
|
+
let customPath = await collection.ui.router({
|
|
46902
|
+
document: document2,
|
|
46903
|
+
collection
|
|
46904
|
+
});
|
|
46905
|
+
if (customPath) {
|
|
46906
|
+
customPath = customPath.startsWith("/") ? customPath.slice(1) : customPath;
|
|
46907
|
+
const tinaBasePath = cms.flags.get("tina-basepath");
|
|
46908
|
+
const tinaPreviewIsSet = cms.flags.get("tina-preview");
|
|
46909
|
+
if (tinaPreviewIsSet) {
|
|
46910
|
+
if (tinaBasePath) {
|
|
46911
|
+
editUrl = `#/~/${tinaBasePath}/${customPath}`;
|
|
46912
|
+
} else {
|
|
46913
|
+
editUrl = `#/~/${customPath}`;
|
|
46914
|
+
}
|
|
46915
|
+
}
|
|
46916
|
+
}
|
|
46917
|
+
}
|
|
46918
|
+
} catch (e3) {
|
|
46919
|
+
console.error(
|
|
46920
|
+
"Unable to determine custom edit URL for document. Falling back to default edit URL.",
|
|
46921
|
+
e3
|
|
46922
|
+
);
|
|
46923
|
+
}
|
|
46924
|
+
return editUrl;
|
|
46925
|
+
};
|
|
46926
|
+
const scanDocumentForMedia = (documentContent, mediaUsages) => {
|
|
46927
|
+
const matchedSrcs = /* @__PURE__ */ new Set();
|
|
46928
|
+
for (const mediaUsage of mediaUsages) {
|
|
46929
|
+
const src = JSON.stringify(mediaUsage.media.src).slice(1, -1);
|
|
46930
|
+
let index = documentContent.indexOf(src);
|
|
46931
|
+
while (index !== -1) {
|
|
46932
|
+
const prevChar = documentContent[index - 1];
|
|
46933
|
+
const nextChar = documentContent[index + src.length];
|
|
46934
|
+
const isPrevValid = !prevChar || !/[a-zA-Z0-9_.%~+-]/.test(prevChar);
|
|
46935
|
+
const isNextValid = !nextChar || !/[a-zA-Z0-9_.%~+-]/.test(nextChar);
|
|
46936
|
+
if (isPrevValid && isNextValid) {
|
|
46937
|
+
matchedSrcs.add(mediaUsage.media.src);
|
|
46938
|
+
break;
|
|
46939
|
+
}
|
|
46940
|
+
index = documentContent.indexOf(src, index + 1);
|
|
46941
|
+
}
|
|
46942
|
+
}
|
|
46943
|
+
return matchedSrcs;
|
|
46944
|
+
};
|
|
46945
|
+
const THUMBNAIL_SIZES = [MEDIA_USAGE_THUMBNAIL_SIZE];
|
|
46946
|
+
const BATCH_SIZE = 100;
|
|
46947
|
+
const UI_YIELD_INTERVAL = 50;
|
|
46948
|
+
const collectAllMedia = async (cms, mediaSrcToUsageMap, currentDirectory) => {
|
|
46949
|
+
const subDirectories = [];
|
|
46950
|
+
let currentOffset = void 0;
|
|
46951
|
+
let moreOffsetsAvailable = true;
|
|
46952
|
+
while (moreOffsetsAvailable) {
|
|
46953
|
+
const list = await cms.media.list({
|
|
46954
|
+
directory: currentDirectory,
|
|
46955
|
+
offset: currentOffset,
|
|
46956
|
+
thumbnailSizes: THUMBNAIL_SIZES
|
|
46957
|
+
});
|
|
46958
|
+
for (const item of list.items) {
|
|
46959
|
+
if (item.type === "file") {
|
|
46960
|
+
if (item.src) {
|
|
46961
|
+
const isImg = isImage(item.filename);
|
|
46962
|
+
const isVid = isVideo(item.filename);
|
|
46963
|
+
const type2 = isImg ? "image" : isVid ? "video" : "other";
|
|
46964
|
+
mediaSrcToUsageMap[item.src] = {
|
|
46965
|
+
media: item,
|
|
46966
|
+
type: type2,
|
|
46967
|
+
usedIn: []
|
|
46968
|
+
};
|
|
46969
|
+
}
|
|
46970
|
+
} else if (item.type === "dir") {
|
|
46971
|
+
const directorySegment = item.filename.replace(/^\/+|\/+$/g, "");
|
|
46972
|
+
subDirectories.push(
|
|
46973
|
+
currentDirectory ? `${currentDirectory}/${directorySegment}` : directorySegment
|
|
46974
|
+
);
|
|
46975
|
+
}
|
|
46976
|
+
}
|
|
46977
|
+
currentOffset = list.nextOffset;
|
|
46978
|
+
if (!currentOffset) {
|
|
46979
|
+
moreOffsetsAvailable = false;
|
|
46980
|
+
}
|
|
46981
|
+
}
|
|
46982
|
+
if (subDirectories.length > 0) {
|
|
46983
|
+
await Promise.all(
|
|
46984
|
+
subDirectories.map((dir) => collectAllMedia(cms, mediaSrcToUsageMap, dir))
|
|
46985
|
+
);
|
|
46986
|
+
}
|
|
46987
|
+
};
|
|
46988
|
+
const scanCollectionForMediaUsage = async (cms, collectionMeta, mediaSrcToUsageMap) => {
|
|
46989
|
+
var _a2, _b;
|
|
46990
|
+
let hasNextPage = true;
|
|
46991
|
+
let after3 = void 0;
|
|
46992
|
+
const mediaUsages = Object.values(mediaSrcToUsageMap);
|
|
46993
|
+
const listQuery = `
|
|
46994
|
+
query($after: String, $first: Float) {
|
|
46995
|
+
collectionConnection: ${collectionMeta.name}Connection(first: $first, after: $after) {
|
|
46996
|
+
pageInfo { hasNextPage, endCursor }
|
|
46997
|
+
edges {
|
|
46998
|
+
node {
|
|
46999
|
+
... on Document {
|
|
47000
|
+
_sys {
|
|
47001
|
+
relativePath
|
|
47002
|
+
filename
|
|
47003
|
+
basename
|
|
47004
|
+
path
|
|
47005
|
+
breadcrumbs
|
|
47006
|
+
extension
|
|
47007
|
+
template
|
|
47008
|
+
title
|
|
47009
|
+
hasReferences
|
|
47010
|
+
collection {
|
|
47011
|
+
name
|
|
47012
|
+
label
|
|
47013
|
+
path
|
|
47014
|
+
format
|
|
47015
|
+
}
|
|
47016
|
+
}
|
|
47017
|
+
_values
|
|
47018
|
+
}
|
|
47019
|
+
}
|
|
47020
|
+
}
|
|
47021
|
+
}
|
|
47022
|
+
}
|
|
47023
|
+
`;
|
|
47024
|
+
while (hasNextPage) {
|
|
47025
|
+
try {
|
|
47026
|
+
const res = await cms.api.tina.request(listQuery, {
|
|
47027
|
+
variables: { after: after3, first: BATCH_SIZE }
|
|
47028
|
+
});
|
|
47029
|
+
const connection = res.collectionConnection;
|
|
47030
|
+
const edges2 = (connection == null ? void 0 : connection.edges) || [];
|
|
47031
|
+
hasNextPage = ((_a2 = connection == null ? void 0 : connection.pageInfo) == null ? void 0 : _a2.hasNextPage) || false;
|
|
47032
|
+
after3 = (_b = connection == null ? void 0 : connection.pageInfo) == null ? void 0 : _b.endCursor;
|
|
47033
|
+
for (let i2 = 0; i2 < edges2.length; i2++) {
|
|
47034
|
+
if (i2 > 0 && i2 % UI_YIELD_INTERVAL === 0) {
|
|
47035
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
47036
|
+
}
|
|
47037
|
+
const edge = edges2[i2];
|
|
47038
|
+
const matchedSrcs = scanDocumentForMedia(
|
|
47039
|
+
JSON.stringify(edge.node._values),
|
|
47040
|
+
mediaUsages
|
|
47041
|
+
);
|
|
47042
|
+
if (matchedSrcs.size === 0)
|
|
47043
|
+
continue;
|
|
47044
|
+
const editUrl = await getDocumentEditUrl(cms, edge.node);
|
|
47045
|
+
matchedSrcs.forEach((mediaSrc) => {
|
|
47046
|
+
const usage = mediaSrcToUsageMap[mediaSrc];
|
|
47047
|
+
if (usage) {
|
|
47048
|
+
usage.usedIn.push({
|
|
47049
|
+
collectionName: collectionMeta.name,
|
|
47050
|
+
breadcrumbs: edge.node._sys.breadcrumbs,
|
|
47051
|
+
collectionLabel: collectionMeta.label || collectionMeta.name,
|
|
47052
|
+
// label is optional in the schema
|
|
47053
|
+
editUrl
|
|
47054
|
+
});
|
|
47055
|
+
}
|
|
47056
|
+
});
|
|
47057
|
+
}
|
|
47058
|
+
} catch (e3) {
|
|
47059
|
+
console.error(`Error processing collection ${collectionMeta.name}:`, e3);
|
|
47060
|
+
throw e3;
|
|
47061
|
+
}
|
|
47062
|
+
}
|
|
47063
|
+
};
|
|
47064
|
+
const scanAllMedia = async (cms, onProgress) => {
|
|
47065
|
+
const mediaSrcToUsageMap = {};
|
|
47066
|
+
await collectAllMedia(cms, mediaSrcToUsageMap, "");
|
|
47067
|
+
const collectionMetas = cms.api.tina.schema.getCollections();
|
|
47068
|
+
for (let i2 = 0; i2 < collectionMetas.length; i2++) {
|
|
47069
|
+
await scanCollectionForMediaUsage(
|
|
47070
|
+
cms,
|
|
47071
|
+
collectionMetas[i2],
|
|
47072
|
+
mediaSrcToUsageMap
|
|
47073
|
+
);
|
|
47074
|
+
onProgress == null ? void 0 : onProgress((i2 + 1) / collectionMetas.length * 100);
|
|
47075
|
+
}
|
|
47076
|
+
return Object.values(mediaSrcToUsageMap);
|
|
47077
|
+
};
|
|
47078
|
+
const useMediaUsageScanner = () => {
|
|
47079
|
+
const cms = useCMS$1();
|
|
47080
|
+
const [mediaItems, setMediaItems] = useState([]);
|
|
47081
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
47082
|
+
const [errorOccurred, setErrorOccurred] = useState(false);
|
|
47083
|
+
const [progress, setProgress] = useState(0);
|
|
47084
|
+
const activeRef = useRef(true);
|
|
47085
|
+
const scanMedia = useCallback(async () => {
|
|
47086
|
+
setIsLoading(true);
|
|
47087
|
+
setErrorOccurred(false);
|
|
47088
|
+
setProgress(0);
|
|
47089
|
+
try {
|
|
47090
|
+
const updatedMediaItems = await scanAllMedia(cms, setProgress);
|
|
47091
|
+
if (activeRef.current)
|
|
47092
|
+
setMediaItems(updatedMediaItems);
|
|
47093
|
+
} catch (e3) {
|
|
47094
|
+
console.error("Error scanning media usage:", e3);
|
|
47095
|
+
if (activeRef.current)
|
|
47096
|
+
setErrorOccurred(true);
|
|
47097
|
+
} finally {
|
|
47098
|
+
if (activeRef.current)
|
|
47099
|
+
setIsLoading(false);
|
|
47100
|
+
}
|
|
47101
|
+
}, [cms]);
|
|
47102
|
+
useEffect(() => {
|
|
47103
|
+
activeRef.current = true;
|
|
47104
|
+
scanMedia().catch((e3) => {
|
|
47105
|
+
console.error("Unhandled rejection from scanMedia:", e3);
|
|
47106
|
+
});
|
|
47107
|
+
return () => {
|
|
47108
|
+
activeRef.current = false;
|
|
47109
|
+
};
|
|
47110
|
+
}, [scanMedia]);
|
|
47111
|
+
return {
|
|
47112
|
+
mediaItems,
|
|
47113
|
+
isLoading,
|
|
47114
|
+
errorOccurred,
|
|
47115
|
+
progress,
|
|
47116
|
+
refresh: scanMedia
|
|
47117
|
+
};
|
|
47118
|
+
};
|
|
47119
|
+
function Dialog({
|
|
47120
|
+
...props
|
|
47121
|
+
}) {
|
|
47122
|
+
return /* @__PURE__ */ React.createElement(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
47123
|
+
}
|
|
47124
|
+
function DialogPortal({
|
|
47125
|
+
...props
|
|
47126
|
+
}) {
|
|
47127
|
+
return /* @__PURE__ */ React.createElement(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
47128
|
+
}
|
|
47129
|
+
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
47130
|
+
DialogPrimitive.Overlay,
|
|
47131
|
+
{
|
|
47132
|
+
ref,
|
|
47133
|
+
"data-slot": "dialog-overlay",
|
|
47134
|
+
className: cn(
|
|
47135
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-[100000]",
|
|
47136
|
+
className
|
|
47137
|
+
),
|
|
47138
|
+
...props
|
|
47139
|
+
}
|
|
47140
|
+
));
|
|
47141
|
+
function DialogContent({
|
|
47142
|
+
className,
|
|
47143
|
+
children,
|
|
47144
|
+
showCloseButton = true,
|
|
47145
|
+
...props
|
|
47146
|
+
}) {
|
|
47147
|
+
return /* @__PURE__ */ React.createElement(DialogPortal, null, /* @__PURE__ */ React.createElement(DialogOverlay, null), /* @__PURE__ */ React.createElement(
|
|
47148
|
+
DialogPrimitive.Content,
|
|
47149
|
+
{
|
|
47150
|
+
"data-slot": "dialog-content",
|
|
47151
|
+
className: cn(
|
|
47152
|
+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-[100000] w-full -translate-x-1/2 -translate-y-1/2 outline-none",
|
|
47153
|
+
className
|
|
47154
|
+
),
|
|
47155
|
+
...props
|
|
47156
|
+
},
|
|
47157
|
+
children,
|
|
47158
|
+
showCloseButton && /* @__PURE__ */ React.createElement(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true }, /* @__PURE__ */ React.createElement(
|
|
47159
|
+
Button,
|
|
47160
|
+
{
|
|
47161
|
+
variant: "ghost",
|
|
47162
|
+
size: "icon",
|
|
47163
|
+
className: "absolute top-2 right-2 h-8 w-8"
|
|
47164
|
+
},
|
|
47165
|
+
/* @__PURE__ */ React.createElement(XIcon, null),
|
|
47166
|
+
/* @__PURE__ */ React.createElement("span", { className: "sr-only" }, "Close")
|
|
47167
|
+
))
|
|
47168
|
+
));
|
|
47169
|
+
}
|
|
47170
|
+
function DialogTitle({
|
|
47171
|
+
className,
|
|
47172
|
+
...props
|
|
47173
|
+
}) {
|
|
47174
|
+
return /* @__PURE__ */ React.createElement(
|
|
47175
|
+
DialogPrimitive.Title,
|
|
47176
|
+
{
|
|
47177
|
+
"data-slot": "dialog-title",
|
|
47178
|
+
className: cn("text-base leading-none font-medium", className),
|
|
47179
|
+
...props
|
|
47180
|
+
}
|
|
47181
|
+
);
|
|
47182
|
+
}
|
|
47183
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
47184
|
+
function DialogDescription({
|
|
47185
|
+
className,
|
|
47186
|
+
...props
|
|
47187
|
+
}) {
|
|
47188
|
+
return /* @__PURE__ */ React.createElement(
|
|
47189
|
+
DialogPrimitive.Description,
|
|
47190
|
+
{
|
|
47191
|
+
"data-slot": "dialog-description",
|
|
47192
|
+
className: cn(
|
|
47193
|
+
"text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3",
|
|
47194
|
+
className
|
|
47195
|
+
),
|
|
47196
|
+
...props
|
|
47197
|
+
}
|
|
47198
|
+
);
|
|
47199
|
+
}
|
|
47200
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
47201
|
+
const MediaLightbox = ({
|
|
47202
|
+
item,
|
|
47203
|
+
onClose
|
|
47204
|
+
}) => {
|
|
47205
|
+
if (!item)
|
|
47206
|
+
return null;
|
|
47207
|
+
const usageCount = item.usedIn.length;
|
|
47208
|
+
const mediaSrc = item.media.src;
|
|
47209
|
+
const directory = item.media.directory || "/";
|
|
47210
|
+
return /* @__PURE__ */ React__default.createElement(Dialog, { open: true, onOpenChange: (isOpen) => !isOpen && onClose() }, /* @__PURE__ */ React__default.createElement(DialogContent, { className: "w-auto max-w-[95vw] border border-gray-200 bg-white px-4 pt-12 pb-4 shadow-xl sm:max-w-fit" }, /* @__PURE__ */ React__default.createElement(DialogTitle, { className: "sr-only" }, "Preview: ", item.media.filename), /* @__PURE__ */ React__default.createElement(DialogDescription, { className: "sr-only" }, usageCount > 0 ? `Used in ${usageCount} ${usageCount === 1 ? "document" : "documents"}` : "Unused media file"), /* @__PURE__ */ React__default.createElement("div", { className: "mx-auto w-fit max-w-full rounded-lg border border-gray-200 bg-gray-50 p-2 sm:p-3" }, item.type === "video" ? /* @__PURE__ */ React__default.createElement(
|
|
47211
|
+
VideoLightboxContent,
|
|
47212
|
+
{
|
|
47213
|
+
src: mediaSrc,
|
|
47214
|
+
filename: item.media.filename
|
|
47215
|
+
}
|
|
47216
|
+
) : /* @__PURE__ */ React__default.createElement(
|
|
47217
|
+
ImageLightboxContent,
|
|
47218
|
+
{
|
|
47219
|
+
src: mediaSrc,
|
|
47220
|
+
filename: item.media.filename
|
|
47221
|
+
}
|
|
47222
|
+
)), /* @__PURE__ */ React__default.createElement("div", { className: "mt-3 space-y-1 text-center" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-sm font-medium text-gray-700" }, /* @__PURE__ */ React__default.createElement("span", { className: "break-all" }, item.media.filename)), /* @__PURE__ */ React__default.createElement("div", { className: "text-xs text-gray-500" }, "Directory:", " ", /* @__PURE__ */ React__default.createElement("span", { className: "break-all font-medium" }, directory)), /* @__PURE__ */ React__default.createElement("div", { className: "text-sm font-medium text-gray-700" }, usageCount > 0 ? /* @__PURE__ */ React__default.createElement("span", { className: "text-tina-orange font-semibold" }, "Used in ", usageCount, " ", usageCount === 1 ? "doc" : "docs") : /* @__PURE__ */ React__default.createElement("span", { className: "font-semibold text-gray-500" }, "Unused")))));
|
|
47223
|
+
};
|
|
47224
|
+
const ImageLightboxContent = ({
|
|
47225
|
+
src,
|
|
47226
|
+
filename
|
|
47227
|
+
}) => /* @__PURE__ */ React__default.createElement(
|
|
47228
|
+
"img",
|
|
47229
|
+
{
|
|
47230
|
+
src,
|
|
47231
|
+
alt: filename,
|
|
47232
|
+
className: "mx-auto block max-w-full max-h-[75vh] object-contain rounded-md shadow-sm"
|
|
47233
|
+
}
|
|
47234
|
+
);
|
|
47235
|
+
const VideoLightboxContent = ({
|
|
47236
|
+
src,
|
|
47237
|
+
filename
|
|
47238
|
+
}) => {
|
|
47239
|
+
const [playbackFailed, setPlaybackFailed] = React__default.useState(false);
|
|
47240
|
+
React__default.useEffect(() => {
|
|
47241
|
+
setPlaybackFailed(false);
|
|
47242
|
+
return () => {
|
|
47243
|
+
setPlaybackFailed(false);
|
|
47244
|
+
};
|
|
47245
|
+
}, [src]);
|
|
47246
|
+
if (playbackFailed) {
|
|
47247
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: "flex min-h-[12rem] min-w-[16rem] flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-300 bg-white px-6 py-8 text-center" }, /* @__PURE__ */ React__default.createElement(BiMovie, { className: "h-10 w-10 text-gray-400" }), /* @__PURE__ */ React__default.createElement("div", { className: "text-sm font-medium text-gray-700" }, filename), /* @__PURE__ */ React__default.createElement("div", { className: "max-w-sm text-sm text-gray-500" }, "This video format is recognized, but this browser could not preview it."));
|
|
47248
|
+
}
|
|
47249
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47250
|
+
"video",
|
|
47251
|
+
{
|
|
47252
|
+
src,
|
|
47253
|
+
controls: true,
|
|
47254
|
+
playsInline: true,
|
|
47255
|
+
preload: "metadata",
|
|
47256
|
+
className: "mx-auto block h-auto w-[min(80vw,720px)] max-w-full max-h-[75vh] rounded-md bg-black shadow-sm",
|
|
47257
|
+
onError: () => setPlaybackFailed(true)
|
|
47258
|
+
}
|
|
47259
|
+
);
|
|
47260
|
+
};
|
|
47261
|
+
const INFINITE_SCROLL_PAGE_SIZE = 10;
|
|
47262
|
+
const DEFAULT_COLUMN_FILTERS = [
|
|
47263
|
+
{ id: "type", value: "all" },
|
|
47264
|
+
{ id: "usage", value: "all" }
|
|
47265
|
+
];
|
|
47266
|
+
const getUsageCount = (item) => item.usedIn.length;
|
|
47267
|
+
const SortIcon = ({ sorted }) => {
|
|
47268
|
+
if (sorted === "asc")
|
|
47269
|
+
return /* @__PURE__ */ React__default.createElement(ArrowUp, { className: "ml-2 h-4 w-4" });
|
|
47270
|
+
if (sorted === "desc")
|
|
47271
|
+
return /* @__PURE__ */ React__default.createElement(ArrowDown, { className: "ml-2 h-4 w-4" });
|
|
47272
|
+
return /* @__PURE__ */ React__default.createElement(ArrowUpDown, { className: "ml-2 h-4 w-4" });
|
|
47273
|
+
};
|
|
47274
|
+
const mediaTypeFilterFn = (row, _columnId, filterValue) => {
|
|
47275
|
+
if (filterValue === "all")
|
|
47276
|
+
return true;
|
|
47277
|
+
return row.original.type === filterValue;
|
|
47278
|
+
};
|
|
47279
|
+
const usageFilterFn = (row, _columnId, filterValue) => {
|
|
47280
|
+
if (filterValue === "all")
|
|
47281
|
+
return true;
|
|
47282
|
+
const count = getUsageCount(row.original);
|
|
47283
|
+
if (filterValue === "used")
|
|
47284
|
+
return count > 0;
|
|
47285
|
+
if (filterValue === "unused")
|
|
47286
|
+
return count === 0;
|
|
47287
|
+
return true;
|
|
47288
|
+
};
|
|
47289
|
+
const getMediaColumns = (onPreview) => [
|
|
47290
|
+
{
|
|
47291
|
+
// Hidden behavior-only column so TanStack can filter by media type.
|
|
47292
|
+
id: "type",
|
|
47293
|
+
accessorFn: (row) => row.type,
|
|
47294
|
+
filterFn: mediaTypeFilterFn,
|
|
47295
|
+
enableSorting: false,
|
|
47296
|
+
header: () => null,
|
|
47297
|
+
cell: () => null
|
|
47298
|
+
},
|
|
47299
|
+
{
|
|
47300
|
+
id: "preview",
|
|
47301
|
+
header: () => /* @__PURE__ */ React__default.createElement("span", { className: "font-medium text-muted-foreground" }, "Preview"),
|
|
47302
|
+
cell: ({ row }) => {
|
|
47303
|
+
var _a2;
|
|
47304
|
+
const media = row.original.media;
|
|
47305
|
+
const type2 = row.original.type;
|
|
47306
|
+
const usageCount = getUsageCount(row.original);
|
|
47307
|
+
const isExpanded = row.getIsExpanded();
|
|
47308
|
+
const thumbnailSrc = (_a2 = media.thumbnails) == null ? void 0 : _a2[MEDIA_USAGE_THUMBNAIL_KEY];
|
|
47309
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-2" }, usageCount > 0 ? /* @__PURE__ */ React__default.createElement(
|
|
47310
|
+
"button",
|
|
47311
|
+
{
|
|
47312
|
+
type: "button",
|
|
47313
|
+
onClick: (event) => {
|
|
47314
|
+
event.stopPropagation();
|
|
47315
|
+
row.toggleExpanded();
|
|
47316
|
+
},
|
|
47317
|
+
className: `flex h-5 w-5 shrink-0 items-center justify-center rounded-full border transition-colors ${isExpanded ? "border-tina-orange bg-white text-tina-orange" : "border-tina-orange bg-tina-orange text-white"}`,
|
|
47318
|
+
title: "View where this file is used",
|
|
47319
|
+
"aria-label": `Toggle usage references for ${row.original.media.filename}`
|
|
47320
|
+
},
|
|
47321
|
+
/* @__PURE__ */ React__default.createElement(
|
|
47322
|
+
ChevronDown,
|
|
47323
|
+
{
|
|
47324
|
+
className: `h-3.5 w-3.5 transition-transform ${isExpanded ? "rotate-180" : ""}`
|
|
47325
|
+
}
|
|
47326
|
+
)
|
|
47327
|
+
) : /* @__PURE__ */ React__default.createElement("span", { className: "block h-5 w-5 shrink-0", "aria-hidden": "true" }), /* @__PURE__ */ React__default.createElement("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded border border-gray-200 bg-gray-100 text-gray-400" }, type2 === "image" && thumbnailSrc ? /* @__PURE__ */ React__default.createElement(
|
|
47328
|
+
"img",
|
|
47329
|
+
{
|
|
47330
|
+
src: thumbnailSrc,
|
|
47331
|
+
alt: media.filename,
|
|
47332
|
+
loading: "lazy",
|
|
47333
|
+
decoding: "async",
|
|
47334
|
+
className: "h-full w-full cursor-pointer object-cover transition-opacity hover:opacity-80",
|
|
47335
|
+
onClick: (event) => {
|
|
47336
|
+
event.stopPropagation();
|
|
47337
|
+
onPreview == null ? void 0 : onPreview(row.original);
|
|
47338
|
+
}
|
|
47339
|
+
}
|
|
47340
|
+
) : type2 === "video" ? /* @__PURE__ */ React__default.createElement(
|
|
47341
|
+
"button",
|
|
47342
|
+
{
|
|
47343
|
+
type: "button",
|
|
47344
|
+
title: "Preview video",
|
|
47345
|
+
className: "flex h-full w-full cursor-pointer items-center justify-center text-gray-400 transition-opacity hover:opacity-80",
|
|
47346
|
+
onClick: (event) => {
|
|
47347
|
+
event.stopPropagation();
|
|
47348
|
+
onPreview == null ? void 0 : onPreview(row.original);
|
|
47349
|
+
}
|
|
47350
|
+
},
|
|
47351
|
+
/* @__PURE__ */ React__default.createElement(BiMovie, { className: "text-3xl" })
|
|
47352
|
+
) : /* @__PURE__ */ React__default.createElement(BiFile, { className: "text-3xl" })));
|
|
47353
|
+
},
|
|
47354
|
+
enableSorting: false
|
|
47355
|
+
},
|
|
47356
|
+
{
|
|
47357
|
+
id: "filename",
|
|
47358
|
+
accessorFn: (row) => row.media.filename,
|
|
47359
|
+
header: ({ column }) => {
|
|
47360
|
+
const sorted = column.getIsSorted();
|
|
47361
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47362
|
+
"button",
|
|
47363
|
+
{
|
|
47364
|
+
type: "button",
|
|
47365
|
+
className: "font-medium text-muted-foreground flex items-center gap-1",
|
|
47366
|
+
onClick: column.getToggleSortingHandler()
|
|
47367
|
+
},
|
|
47368
|
+
"Filename",
|
|
47369
|
+
/* @__PURE__ */ React__default.createElement(SortIcon, { sorted })
|
|
47370
|
+
);
|
|
47371
|
+
},
|
|
47372
|
+
cell: ({ row }) => /* @__PURE__ */ React__default.createElement(TooltipProvider$1, null, /* @__PURE__ */ React__default.createElement(Tooltip$1, { delayDuration: 300 }, /* @__PURE__ */ React__default.createElement(TooltipTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement("span", { className: "block w-full truncate font-medium text-gray-800" }, row.original.media.filename)), /* @__PURE__ */ React__default.createElement(TooltipPortal, null, /* @__PURE__ */ React__default.createElement(TooltipContent$1, { side: "top", className: "max-w-sm break-all shadow-md" }, row.original.media.filename))))
|
|
47373
|
+
},
|
|
47374
|
+
{
|
|
47375
|
+
id: "directory",
|
|
47376
|
+
accessorFn: (row) => row.media.directory || "/",
|
|
47377
|
+
header: ({ column }) => {
|
|
47378
|
+
const sorted = column.getIsSorted();
|
|
47379
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47380
|
+
"button",
|
|
47381
|
+
{
|
|
47382
|
+
type: "button",
|
|
47383
|
+
className: "font-medium text-muted-foreground flex items-center gap-1",
|
|
47384
|
+
onClick: column.getToggleSortingHandler()
|
|
47385
|
+
},
|
|
47386
|
+
"Directory",
|
|
47387
|
+
/* @__PURE__ */ React__default.createElement(SortIcon, { sorted })
|
|
47388
|
+
);
|
|
47389
|
+
},
|
|
47390
|
+
cell: ({ getValue: getValue2 }) => {
|
|
47391
|
+
const directory = getValue2();
|
|
47392
|
+
return /* @__PURE__ */ React__default.createElement(TooltipProvider$1, null, /* @__PURE__ */ React__default.createElement(Tooltip$1, { delayDuration: 300 }, /* @__PURE__ */ React__default.createElement(TooltipTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement("span", { className: "block w-full truncate text-sm text-gray-500" }, directory)), /* @__PURE__ */ React__default.createElement(TooltipPortal, null, /* @__PURE__ */ React__default.createElement(
|
|
47393
|
+
TooltipContent$1,
|
|
47394
|
+
{
|
|
47395
|
+
side: "top",
|
|
47396
|
+
className: "max-w-sm break-all shadow-md"
|
|
47397
|
+
},
|
|
47398
|
+
directory
|
|
47399
|
+
))));
|
|
47400
|
+
}
|
|
47401
|
+
},
|
|
47402
|
+
{
|
|
47403
|
+
id: "usage",
|
|
47404
|
+
accessorFn: getUsageCount,
|
|
47405
|
+
header: ({ column }) => {
|
|
47406
|
+
const sorted = column.getIsSorted();
|
|
47407
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47408
|
+
"button",
|
|
47409
|
+
{
|
|
47410
|
+
type: "button",
|
|
47411
|
+
className: "font-medium text-muted-foreground ml-auto flex items-center gap-1",
|
|
47412
|
+
onClick: column.getToggleSortingHandler()
|
|
47413
|
+
},
|
|
47414
|
+
"Usage",
|
|
47415
|
+
/* @__PURE__ */ React__default.createElement(SortIcon, { sorted })
|
|
47416
|
+
);
|
|
47417
|
+
},
|
|
47418
|
+
cell: ({ row }) => {
|
|
47419
|
+
const count = getUsageCount(row.original);
|
|
47420
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47421
|
+
"span",
|
|
47422
|
+
{
|
|
47423
|
+
className: `inline-block min-w-[3rem] text-right ${count > 0 ? "font-medium text-gray-800" : "text-gray-500"}`
|
|
47424
|
+
},
|
|
47425
|
+
count
|
|
47426
|
+
);
|
|
47427
|
+
},
|
|
47428
|
+
filterFn: usageFilterFn
|
|
47429
|
+
}
|
|
47430
|
+
];
|
|
47431
|
+
const MediaUsageTable = ({
|
|
47432
|
+
mediaItems,
|
|
47433
|
+
onClose,
|
|
47434
|
+
onPreview
|
|
47435
|
+
}) => {
|
|
47436
|
+
var _a2, _b;
|
|
47437
|
+
const [columnFilters, setColumnFilters] = useState(
|
|
47438
|
+
DEFAULT_COLUMN_FILTERS
|
|
47439
|
+
);
|
|
47440
|
+
const [sorting, setSorting] = useState([]);
|
|
47441
|
+
const [expanded, setExpanded] = useState({});
|
|
47442
|
+
const [visibleCount, setVisibleCount] = useState(INFINITE_SCROLL_PAGE_SIZE);
|
|
47443
|
+
const sentinelRef = useRef(null);
|
|
47444
|
+
const scrollContainerRef = useRef(null);
|
|
47445
|
+
const columns = useMemo(() => getMediaColumns(onPreview), [onPreview]);
|
|
47446
|
+
const typeFilter = ((_a2 = columnFilters.find((filter2) => filter2.id === "type")) == null ? void 0 : _a2.value) ?? "all";
|
|
47447
|
+
const usageFilter = ((_b = columnFilters.find((filter2) => filter2.id === "usage")) == null ? void 0 : _b.value) ?? "all";
|
|
47448
|
+
const table = useReactTable({
|
|
47449
|
+
data: mediaItems,
|
|
47450
|
+
columns,
|
|
47451
|
+
getRowId: (row) => row.media.src,
|
|
47452
|
+
initialState: { columnVisibility: { type: false } },
|
|
47453
|
+
state: { sorting, columnFilters, expanded },
|
|
47454
|
+
onColumnFiltersChange: setColumnFilters,
|
|
47455
|
+
onSortingChange: setSorting,
|
|
47456
|
+
onExpandedChange: setExpanded,
|
|
47457
|
+
getCoreRowModel: getCoreRowModel(),
|
|
47458
|
+
getSortedRowModel: getSortedRowModel(),
|
|
47459
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
47460
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
47461
|
+
getRowCanExpand: (row) => getUsageCount(row.original) > 0
|
|
47462
|
+
});
|
|
47463
|
+
const handleTypeFilterChange = (value) => {
|
|
47464
|
+
var _a3;
|
|
47465
|
+
setExpanded({});
|
|
47466
|
+
setVisibleCount(INFINITE_SCROLL_PAGE_SIZE);
|
|
47467
|
+
(_a3 = table.getColumn("type")) == null ? void 0 : _a3.setFilterValue(value);
|
|
47468
|
+
};
|
|
47469
|
+
const handleUsageFilterChange = (value) => {
|
|
47470
|
+
var _a3;
|
|
47471
|
+
setExpanded({});
|
|
47472
|
+
setVisibleCount(INFINITE_SCROLL_PAGE_SIZE);
|
|
47473
|
+
(_a3 = table.getColumn("usage")) == null ? void 0 : _a3.setFilterValue(value);
|
|
47474
|
+
};
|
|
47475
|
+
useEffect(() => {
|
|
47476
|
+
setVisibleCount(INFINITE_SCROLL_PAGE_SIZE);
|
|
47477
|
+
}, [sorting]);
|
|
47478
|
+
const allRows = table.getRowModel().rows;
|
|
47479
|
+
const visibleRows = allRows.slice(0, visibleCount);
|
|
47480
|
+
const hasMore = visibleCount < allRows.length;
|
|
47481
|
+
const loadMore = useCallback(() => {
|
|
47482
|
+
setVisibleCount((prev) => prev + INFINITE_SCROLL_PAGE_SIZE);
|
|
47483
|
+
}, []);
|
|
47484
|
+
useEffect(() => {
|
|
47485
|
+
const sentinel = sentinelRef.current;
|
|
47486
|
+
const scrollContainer = scrollContainerRef.current;
|
|
47487
|
+
if (!sentinel || !scrollContainer)
|
|
47488
|
+
return;
|
|
47489
|
+
const observer = new IntersectionObserver(
|
|
47490
|
+
(entries) => {
|
|
47491
|
+
var _a3;
|
|
47492
|
+
if ((_a3 = entries[0]) == null ? void 0 : _a3.isIntersecting) {
|
|
47493
|
+
loadMore();
|
|
47494
|
+
}
|
|
47495
|
+
},
|
|
47496
|
+
{ root: scrollContainer, rootMargin: "200px" }
|
|
47497
|
+
);
|
|
47498
|
+
observer.observe(sentinel);
|
|
47499
|
+
return () => observer.disconnect();
|
|
47500
|
+
}, [loadMore, hasMore]);
|
|
47501
|
+
const filteredRowCount = table.getFilteredRowModel().rows.length;
|
|
47502
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: "bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-3 border-b border-gray-200 bg-gray-50/50 px-6 py-4" }, /* @__PURE__ */ React__default.createElement("h3", { className: "whitespace-nowrap text-lg font-semibold text-gray-800" }, "Media Inventory"), /* @__PURE__ */ React__default.createElement(
|
|
47503
|
+
MediaFilters,
|
|
47504
|
+
{
|
|
47505
|
+
filteredRowCount,
|
|
47506
|
+
typeFilter,
|
|
47507
|
+
usageFilter,
|
|
47508
|
+
setTypeFilter: handleTypeFilterChange,
|
|
47509
|
+
setUsageFilter: handleUsageFilterChange,
|
|
47510
|
+
className: "ml-auto"
|
|
47511
|
+
}
|
|
47512
|
+
)), /* @__PURE__ */ React__default.createElement("div", { ref: scrollContainerRef, className: "max-h-[45vh] overflow-auto" }, /* @__PURE__ */ React__default.createElement(
|
|
47513
|
+
Table,
|
|
47514
|
+
{
|
|
47515
|
+
className: "border-separate border-spacing-0",
|
|
47516
|
+
wrapperClassName: "overflow-visible"
|
|
47517
|
+
},
|
|
47518
|
+
/* @__PURE__ */ React__default.createElement(TableHeader, null, table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ React__default.createElement(TableRow, { key: headerGroup.id }, headerGroup.headers.map((header) => /* @__PURE__ */ React__default.createElement(
|
|
47519
|
+
TableHead,
|
|
47520
|
+
{
|
|
47521
|
+
key: header.id,
|
|
47522
|
+
className: `sticky top-0 z-20 border-b border-gray-200 bg-white ${header.column.id === "preview" ? "w-[4rem] pl-9" : header.column.id === "filename" ? "w-[20rem]" : header.column.id === "directory" ? "w-[14rem]" : header.column.id === "usage" ? "w-[5.5rem]" : ""}`
|
|
47523
|
+
},
|
|
47524
|
+
header.isPlaceholder ? null : flexRender(
|
|
47525
|
+
header.column.columnDef.header,
|
|
47526
|
+
header.getContext()
|
|
47527
|
+
)
|
|
47528
|
+
))))),
|
|
47529
|
+
/* @__PURE__ */ React__default.createElement(TableBody, null, allRows.length === 0 ? /* @__PURE__ */ React__default.createElement(TableRow, null, /* @__PURE__ */ React__default.createElement(
|
|
47530
|
+
TableCell,
|
|
47531
|
+
{
|
|
47532
|
+
colSpan: columns.length,
|
|
47533
|
+
className: "!py-8 text-center text-gray-500"
|
|
47534
|
+
},
|
|
47535
|
+
mediaItems.length === 0 ? "No media files found." : "No media files match the current filters."
|
|
47536
|
+
)) : visibleRows.map((row) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, { key: row.id }, /* @__PURE__ */ React__default.createElement(
|
|
47537
|
+
TableRow,
|
|
47538
|
+
{
|
|
47539
|
+
style: { contentVisibility: "auto" },
|
|
47540
|
+
onClick: getUsageCount(row.original) > 0 ? row.getToggleExpandedHandler() : void 0,
|
|
47541
|
+
className: getUsageCount(row.original) > 0 ? row.getIsExpanded() ? "cursor-pointer bg-[#FFF8F6] hover:bg-[#FFF8F6]" : "cursor-pointer" : ""
|
|
47542
|
+
},
|
|
47543
|
+
row.getVisibleCells().map((cell) => /* @__PURE__ */ React__default.createElement(
|
|
47544
|
+
TableCell,
|
|
47545
|
+
{
|
|
47546
|
+
key: cell.id,
|
|
47547
|
+
className: cell.column.id === "preview" ? "!px-2 !py-1.5 w-[4rem]" : cell.column.id === "filename" ? "!px-3 !py-1.5 w-[20rem] max-w-0 overflow-hidden" : cell.column.id === "directory" ? "!px-3 !py-1.5 w-[14rem] max-w-0 overflow-hidden" : cell.column.id === "usage" ? "!pl-2 !pr-4 !py-1.5 w-[5.5rem] text-sm font-medium text-right whitespace-nowrap" : "!px-3 !py-1.5"
|
|
47548
|
+
},
|
|
47549
|
+
flexRender(
|
|
47550
|
+
cell.column.columnDef.cell,
|
|
47551
|
+
cell.getContext()
|
|
47552
|
+
)
|
|
47553
|
+
))
|
|
47554
|
+
), row.getIsExpanded() && /* @__PURE__ */ React__default.createElement(TableRow, null, /* @__PURE__ */ React__default.createElement(
|
|
47555
|
+
TableCell,
|
|
47556
|
+
{
|
|
47557
|
+
colSpan: columns.length,
|
|
47558
|
+
className: "border-b border-gray-150 bg-[#FFEBE5]"
|
|
47559
|
+
},
|
|
47560
|
+
/* @__PURE__ */ React__default.createElement(
|
|
47561
|
+
ExpandedRowContent,
|
|
47562
|
+
{
|
|
47563
|
+
usedIn: row.original.usedIn,
|
|
47564
|
+
onClose
|
|
47565
|
+
}
|
|
47566
|
+
)
|
|
47567
|
+
)))))
|
|
47568
|
+
), hasMore && /* @__PURE__ */ React__default.createElement("div", { ref: sentinelRef, className: "h-px", "aria-hidden": "true" })));
|
|
47569
|
+
};
|
|
47570
|
+
const MediaFilters = ({
|
|
47571
|
+
filteredRowCount,
|
|
47572
|
+
typeFilter,
|
|
47573
|
+
usageFilter,
|
|
47574
|
+
setTypeFilter,
|
|
47575
|
+
setUsageFilter,
|
|
47576
|
+
className
|
|
47577
|
+
}) => /* @__PURE__ */ React__default.createElement("div", { className: `flex items-center gap-3 ${className ?? ""}` }, /* @__PURE__ */ React__default.createElement("span", { className: "text-xs text-gray-500 whitespace-nowrap" }, filteredRowCount, " ", filteredRowCount === 1 ? "result" : "results"), /* @__PURE__ */ React__default.createElement(
|
|
47578
|
+
Select,
|
|
47579
|
+
{
|
|
47580
|
+
value: typeFilter,
|
|
47581
|
+
onValueChange: (value) => setTypeFilter(value)
|
|
47582
|
+
},
|
|
47583
|
+
/* @__PURE__ */ React__default.createElement(
|
|
47584
|
+
SelectTrigger,
|
|
47585
|
+
{
|
|
47586
|
+
"aria-label": "Filter by media type",
|
|
47587
|
+
className: "w-[130px] bg-white border-gray-200 text-gray-700 h-9"
|
|
47588
|
+
},
|
|
47589
|
+
/* @__PURE__ */ React__default.createElement(SelectValue, { placeholder: "All Types" })
|
|
47590
|
+
),
|
|
47591
|
+
/* @__PURE__ */ React__default.createElement(SelectContent, null, /* @__PURE__ */ React__default.createElement(SelectItem, { value: "all" }, "All Types"), /* @__PURE__ */ React__default.createElement(SelectItem, { value: "image" }, "Images"), /* @__PURE__ */ React__default.createElement(SelectItem, { value: "video" }, "Videos"), /* @__PURE__ */ React__default.createElement(SelectItem, { value: "other" }, "Other"))
|
|
47592
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
47593
|
+
Select,
|
|
47594
|
+
{
|
|
47595
|
+
value: usageFilter,
|
|
47596
|
+
onValueChange: (value) => setUsageFilter(value)
|
|
47597
|
+
},
|
|
47598
|
+
/* @__PURE__ */ React__default.createElement(
|
|
47599
|
+
SelectTrigger,
|
|
47600
|
+
{
|
|
47601
|
+
"aria-label": "Filter by usage status",
|
|
47602
|
+
className: "w-[130px] bg-white border-gray-200 text-gray-700 h-9"
|
|
47603
|
+
},
|
|
47604
|
+
/* @__PURE__ */ React__default.createElement(SelectValue, { placeholder: "All Usage" })
|
|
47605
|
+
),
|
|
47606
|
+
/* @__PURE__ */ React__default.createElement(SelectContent, null, /* @__PURE__ */ React__default.createElement(SelectItem, { value: "all" }, "All Usage"), /* @__PURE__ */ React__default.createElement(SelectItem, { value: "used" }, "Used"), /* @__PURE__ */ React__default.createElement(SelectItem, { value: "unused" }, "Unused"))
|
|
47607
|
+
));
|
|
47608
|
+
const ExpandedRowContent = ({
|
|
47609
|
+
usedIn,
|
|
47610
|
+
onClose
|
|
47611
|
+
}) => {
|
|
47612
|
+
const documentCount = usedIn.length;
|
|
47613
|
+
const sortedDocs = [...usedIn].sort(
|
|
47614
|
+
(a2, b) => a2.collectionLabel.localeCompare(b.collectionLabel)
|
|
47615
|
+
);
|
|
47616
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("p", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3" }, "Used in ", documentCount, " document", documentCount !== 1 ? "s" : "", ":"), /* @__PURE__ */ React__default.createElement("table", { className: "w-full text-xs border-collapse" }, /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", { className: "text-left text-[10px] font-bold uppercase tracking-tight text-gray-400" }, /* @__PURE__ */ React__default.createElement("th", { className: "pb-1.5 pr-6 w-40" }, "Collection"), /* @__PURE__ */ React__default.createElement("th", { className: "pb-1.5" }, "Document"))), /* @__PURE__ */ React__default.createElement("tbody", null, sortedDocs.map((doc) => {
|
|
47617
|
+
const breadcrumb = doc.breadcrumbs.join("/");
|
|
47618
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47619
|
+
"tr",
|
|
47620
|
+
{
|
|
47621
|
+
key: doc.editUrl || breadcrumb,
|
|
47622
|
+
className: "border-t border-gray-150"
|
|
47623
|
+
},
|
|
47624
|
+
/* @__PURE__ */ React__default.createElement("td", { className: "py-1.5 pr-6 text-gray-500" }, /* @__PURE__ */ React__default.createElement(
|
|
47625
|
+
"a",
|
|
47626
|
+
{
|
|
47627
|
+
href: `#/collections/${doc.collectionName}/~`,
|
|
47628
|
+
onClick: () => onClose == null ? void 0 : onClose(),
|
|
47629
|
+
className: "underline hover:text-tina-orange-dark transition-colors"
|
|
47630
|
+
},
|
|
47631
|
+
doc.collectionLabel
|
|
47632
|
+
)),
|
|
47633
|
+
/* @__PURE__ */ React__default.createElement("td", { className: "py-1.5 text-gray-700" }, /* @__PURE__ */ React__default.createElement("span", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React__default.createElement(BiFile, { className: "text-gray-400 flex-shrink-0" }), doc.editUrl ? /* @__PURE__ */ React__default.createElement(
|
|
47634
|
+
"a",
|
|
47635
|
+
{
|
|
47636
|
+
href: doc.editUrl,
|
|
47637
|
+
onClick: () => onClose == null ? void 0 : onClose(),
|
|
47638
|
+
className: "underline hover:text-tina-orange-dark transition-colors break-all"
|
|
47639
|
+
},
|
|
47640
|
+
breadcrumb
|
|
47641
|
+
) : /* @__PURE__ */ React__default.createElement("span", { className: "break-all" }, breadcrumb)))
|
|
47642
|
+
);
|
|
47643
|
+
}))));
|
|
47644
|
+
};
|
|
47645
|
+
const MediaUsageDashboard = ({
|
|
47646
|
+
close: onClose
|
|
47647
|
+
}) => {
|
|
47648
|
+
const { mediaItems, isLoading, errorOccurred, progress, refresh } = useMediaUsageScanner();
|
|
47649
|
+
const [lightboxImage, setLightboxImage] = useState(null);
|
|
47650
|
+
const stats = useMemo(() => {
|
|
47651
|
+
const unusedCount = mediaItems.filter(
|
|
47652
|
+
(usage) => usage.usedIn.length === 0
|
|
47653
|
+
).length;
|
|
47654
|
+
const usedCount = mediaItems.length - unusedCount;
|
|
47655
|
+
return {
|
|
47656
|
+
totalFiles: mediaItems.length,
|
|
47657
|
+
unusedCount,
|
|
47658
|
+
usedCount
|
|
47659
|
+
};
|
|
47660
|
+
}, [mediaItems]);
|
|
47661
|
+
if (isLoading) {
|
|
47662
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
47663
|
+
DashboardLoadingState,
|
|
47664
|
+
{
|
|
47665
|
+
message: "Scanning Media Usage...",
|
|
47666
|
+
progress: { value: progress, label: "Scanning collections" }
|
|
47667
|
+
}
|
|
47668
|
+
);
|
|
47669
|
+
}
|
|
47670
|
+
if (errorOccurred) {
|
|
47671
|
+
return /* @__PURE__ */ React__default.createElement(DashboardErrorState, { message: "Something went wrong, unable to collect media usage statistics" });
|
|
47672
|
+
}
|
|
47673
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: "p-8 w-full max-w-6xl mx-auto font-sans" }, /* @__PURE__ */ React__default.createElement(
|
|
47674
|
+
DashboardTitleBar,
|
|
47675
|
+
{
|
|
47676
|
+
title: "Media Usage Dashboard",
|
|
47677
|
+
icon: /* @__PURE__ */ React__default.createElement(Image, null),
|
|
47678
|
+
controls: /* @__PURE__ */ React__default.createElement(
|
|
47679
|
+
Button,
|
|
47680
|
+
{
|
|
47681
|
+
variant: "outline",
|
|
47682
|
+
onClick: refresh,
|
|
47683
|
+
disabled: isLoading,
|
|
47684
|
+
className: "flex items-center gap-2 shadow-sm font-medium transition-colors"
|
|
47685
|
+
},
|
|
47686
|
+
/* @__PURE__ */ React__default.createElement(RefreshCw, { className: "w-4 h-4" }),
|
|
47687
|
+
"Refresh"
|
|
47688
|
+
)
|
|
47689
|
+
}
|
|
47690
|
+
), /* @__PURE__ */ React__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6 mb-8" }, /* @__PURE__ */ React__default.createElement(
|
|
47691
|
+
StatCard,
|
|
47692
|
+
{
|
|
47693
|
+
label: "Total Media Files",
|
|
47694
|
+
icon: /* @__PURE__ */ React__default.createElement(Database, { className: "text-2xl text-gray-700" }),
|
|
47695
|
+
iconClassName: "bg-gray-100",
|
|
47696
|
+
value: stats.totalFiles
|
|
47697
|
+
}
|
|
47698
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
47699
|
+
StatCard,
|
|
47700
|
+
{
|
|
47701
|
+
label: "In Use",
|
|
47702
|
+
icon: /* @__PURE__ */ React__default.createElement(CheckCircle2, { className: "text-2xl text-tina-orange-dark" }),
|
|
47703
|
+
iconClassName: "bg-tina-orange/10",
|
|
47704
|
+
value: stats.usedCount
|
|
47705
|
+
}
|
|
47706
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
47707
|
+
StatCard,
|
|
47708
|
+
{
|
|
47709
|
+
label: "Unused",
|
|
47710
|
+
icon: /* @__PURE__ */ React__default.createElement(
|
|
47711
|
+
ImageOff,
|
|
47712
|
+
{
|
|
47713
|
+
className: `text-2xl ${stats.unusedCount > 0 ? "text-orange-600" : "text-gray-400"}`
|
|
47714
|
+
}
|
|
47715
|
+
),
|
|
47716
|
+
iconClassName: stats.unusedCount > 0 ? "bg-orange-100" : "bg-gray-100",
|
|
47717
|
+
value: stats.unusedCount,
|
|
47718
|
+
valueClassName: stats.unusedCount > 0 ? "text-orange-600" : "text-gray-800"
|
|
47719
|
+
}
|
|
47720
|
+
)), /* @__PURE__ */ React__default.createElement(
|
|
47721
|
+
MediaUsageTable,
|
|
47722
|
+
{
|
|
47723
|
+
mediaItems,
|
|
47724
|
+
onClose,
|
|
47725
|
+
onPreview: setLightboxImage
|
|
47726
|
+
}
|
|
47727
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
47728
|
+
MediaLightbox,
|
|
47729
|
+
{
|
|
47730
|
+
item: lightboxImage,
|
|
47731
|
+
onClose: () => setLightboxImage(null)
|
|
47732
|
+
}
|
|
47733
|
+
));
|
|
47734
|
+
};
|
|
47735
|
+
const StatCard = ({
|
|
47736
|
+
label,
|
|
47737
|
+
icon,
|
|
47738
|
+
iconClassName,
|
|
47739
|
+
value,
|
|
47740
|
+
valueClassName = "text-gray-800"
|
|
47741
|
+
}) => /* @__PURE__ */ React__default.createElement("div", { className: "bg-white rounded-xl border border-gray-200 shadow-sm flex items-center gap-4 p-6" }, /* @__PURE__ */ React__default.createElement("div", { className: `${iconClassName} p-3 rounded-lg flex-shrink-0` }, icon), /* @__PURE__ */ React__default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React__default.createElement("p", { className: "text-sm text-gray-500 font-medium" }, label), /* @__PURE__ */ React__default.createElement("p", { className: `text-3xl font-bold ${valueClassName}` }, value)));
|
|
47742
|
+
const MediaUsageDashboardScreenPlugin = createScreen({
|
|
47743
|
+
name: "Media Usage",
|
|
47744
|
+
Component: MediaUsageDashboard,
|
|
47745
|
+
Icon: MdImage,
|
|
47746
|
+
layout: "popup",
|
|
47747
|
+
navCategory: "Dashboard"
|
|
47748
|
+
});
|
|
46799
47749
|
function createCloudConfig({
|
|
46800
47750
|
...options
|
|
46801
47751
|
}) {
|
|
@@ -46999,7 +47949,7 @@ const NavProvider = ({
|
|
|
46999
47949
|
const name = "tinacms";
|
|
47000
47950
|
const type = "module";
|
|
47001
47951
|
const typings = "dist/index.d.ts";
|
|
47002
|
-
const version$1 = "3.
|
|
47952
|
+
const version$1 = "3.7.1";
|
|
47003
47953
|
const main = "dist/index.js";
|
|
47004
47954
|
const module = "./dist/index.js";
|
|
47005
47955
|
const exports = {
|
|
@@ -47071,6 +48021,7 @@ const dependencies = {
|
|
|
47071
48021
|
"@udecode/plate-dnd": "catalog:",
|
|
47072
48022
|
"@udecode/plate-floating": "catalog:",
|
|
47073
48023
|
"@udecode/plate-heading": "catalog:",
|
|
48024
|
+
"@udecode/plate-highlight": "catalog:",
|
|
47074
48025
|
"@udecode/plate-horizontal-rule": "catalog:",
|
|
47075
48026
|
"@udecode/plate-indent-list": "catalog:",
|
|
47076
48027
|
"@udecode/plate-link": "catalog:",
|
|
@@ -47108,6 +48059,8 @@ const dependencies = {
|
|
|
47108
48059
|
"react-colorful": "catalog:",
|
|
47109
48060
|
"react-datetime": "catalog:",
|
|
47110
48061
|
"react-day-picker": "^9.13.0",
|
|
48062
|
+
"react-dnd": "catalog:",
|
|
48063
|
+
"react-dnd-html5-backend": "catalog:",
|
|
47111
48064
|
"react-dropzone": "catalog:",
|
|
47112
48065
|
"react-final-form": "catalog:",
|
|
47113
48066
|
"react-icons": "^5.4.0",
|
|
@@ -48045,11 +48998,11 @@ const FormLists = (props) => {
|
|
|
48045
48998
|
"input",
|
|
48046
48999
|
{
|
|
48047
49000
|
type: "checkbox",
|
|
48048
|
-
checked:
|
|
48049
|
-
onChange: (e3) => setShowReferences(
|
|
49001
|
+
checked: showReferences,
|
|
49002
|
+
onChange: (e3) => setShowReferences(e3.target.checked),
|
|
48050
49003
|
className: "w-4 h-4 text-orange-500 border-gray-300 rounded focus:ring-orange-500"
|
|
48051
49004
|
}
|
|
48052
|
-
), /* @__PURE__ */ React.createElement("span", null, "
|
|
49005
|
+
), /* @__PURE__ */ React.createElement("span", null, "Show all references"))), /* @__PURE__ */ React.createElement("div", { className: "flex-1 overflow-x-auto overflow-y-auto min-h-0" }, cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}` }, /* @__PURE__ */ React.createElement(
|
|
48053
49006
|
FormList,
|
|
48054
49007
|
{
|
|
48055
49008
|
setActiveFormId: (id2) => {
|
|
@@ -48821,6 +49774,9 @@ class TinaCMS extends CMS {
|
|
|
48821
49774
|
});
|
|
48822
49775
|
this.plugins.add(MediaManagerScreenPlugin);
|
|
48823
49776
|
this.plugins.add(PasswordScreenPlugin);
|
|
49777
|
+
if (isLocalClient) {
|
|
49778
|
+
this.plugins.add(MediaUsageDashboardScreenPlugin);
|
|
49779
|
+
}
|
|
48824
49780
|
if (isLocalClient !== true) {
|
|
48825
49781
|
if (clientId) {
|
|
48826
49782
|
this.plugins.add(
|
|
@@ -65044,7 +66000,8 @@ const CreateBranchModal = ({
|
|
|
65044
66000
|
safeSubmit,
|
|
65045
66001
|
path: path3,
|
|
65046
66002
|
values,
|
|
65047
|
-
crudType
|
|
66003
|
+
crudType,
|
|
66004
|
+
tinaForm
|
|
65048
66005
|
}) => {
|
|
65049
66006
|
const cms = useCMS$1();
|
|
65050
66007
|
const tinaApi = cms.api.tina;
|
|
@@ -65094,6 +66051,7 @@ const CreateBranchModal = ({
|
|
|
65094
66051
|
}
|
|
65095
66052
|
];
|
|
65096
66053
|
const executeEditorialWorkflow = async () => {
|
|
66054
|
+
var _a2;
|
|
65097
66055
|
try {
|
|
65098
66056
|
const branchName = `tina/${newBranchName}`;
|
|
65099
66057
|
setDisabled(true);
|
|
@@ -65108,7 +66066,21 @@ const CreateBranchModal = ({
|
|
|
65108
66066
|
graphql2 = UPDATE_DOCUMENT_GQL;
|
|
65109
66067
|
}
|
|
65110
66068
|
const collection = tinaApi.schema.getCollectionByFullPath(path3);
|
|
65111
|
-
|
|
66069
|
+
let submittedValues = values;
|
|
66070
|
+
if ((_a2 = collection == null ? void 0 : collection.ui) == null ? void 0 : _a2.beforeSubmit) {
|
|
66071
|
+
const valOverride = await collection.ui.beforeSubmit({
|
|
66072
|
+
cms,
|
|
66073
|
+
values,
|
|
66074
|
+
form: tinaForm
|
|
66075
|
+
});
|
|
66076
|
+
if (valOverride) {
|
|
66077
|
+
submittedValues = valOverride;
|
|
66078
|
+
}
|
|
66079
|
+
}
|
|
66080
|
+
const params = tinaApi.schema.transformPayload(
|
|
66081
|
+
collection.name,
|
|
66082
|
+
submittedValues
|
|
66083
|
+
);
|
|
65112
66084
|
const relativePath = pathRelativeToCollection(collection.path, path3);
|
|
65113
66085
|
const result = await tinaApi.executeEditorialWorkflow({
|
|
65114
66086
|
branchName,
|
|
@@ -65242,7 +66214,7 @@ const CreateBranchModal = ({
|
|
|
65242
66214
|
),
|
|
65243
66215
|
/* @__PURE__ */ React.createElement("div", { className: "text-center max-w-24" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm font-semibold leading-tight" }, step.name), /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-400 mt-1 leading-tight" }, step.description))
|
|
65244
66216
|
);
|
|
65245
|
-
})), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500" }, "Estimated time: 1-2 min "), isExecuting && currentStep > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-sm text-gray-500" }, /* @__PURE__ */ React.createElement("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20" }, /* @__PURE__ */ React.createElement(
|
|
66217
|
+
})), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500" }, "Estimated time: 1-2 min "), isExecuting && currentStep > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-sm text-gray-500 tabular-nums" }, /* @__PURE__ */ React.createElement("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20" }, /* @__PURE__ */ React.createElement(
|
|
65246
66218
|
"path",
|
|
65247
66219
|
{
|
|
65248
66220
|
fillRule: "evenodd",
|
|
@@ -65481,6 +66453,7 @@ const FormBuilder = ({
|
|
|
65481
66453
|
crudType: tinaForm.crudType,
|
|
65482
66454
|
path: tinaForm.path,
|
|
65483
66455
|
values: tinaForm.values,
|
|
66456
|
+
tinaForm,
|
|
65484
66457
|
close: () => setCreateBranchModalOpen(false)
|
|
65485
66458
|
}
|
|
65486
66459
|
), /* @__PURE__ */ React.createElement(DragDropContext, { onDragEnd: moveArrayItem }, /* @__PURE__ */ React.createElement(FormKeyBindings, { onSubmit: safeHandleSubmit }), /* @__PURE__ */ React.createElement(FormPortalProvider, null, /* @__PURE__ */ React.createElement(FormWrapper, { id: tinaForm.id }, (tinaForm == null ? void 0 : tinaForm.fields.length) ? /* @__PURE__ */ React.createElement(
|
|
@@ -67379,10 +68352,105 @@ const MarkToolbarButton = withRef$1(({ clear, nodeType, ...rest }, ref) => {
|
|
|
67379
68352
|
const { props } = useMarkToolbarButton(state);
|
|
67380
68353
|
return /* @__PURE__ */ React__default.createElement(ToolbarButton, { ref, ...props, ...rest });
|
|
67381
68354
|
});
|
|
68355
|
+
const highlightColors = [
|
|
68356
|
+
{ label: "Yellow", value: "#FEF08A" },
|
|
68357
|
+
{ label: "Green", value: "#BBF7D0" },
|
|
68358
|
+
{ label: "Blue", value: "#BFDBFE" },
|
|
68359
|
+
{ label: "Red", value: "#CC4141" }
|
|
68360
|
+
];
|
|
67382
68361
|
const BoldToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Bold (⌘+B)", nodeType: BoldPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.bold, null));
|
|
67383
68362
|
const StrikethroughToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Strikethrough", nodeType: StrikethroughPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.strikethrough, null));
|
|
67384
68363
|
const ItalicToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Italic (⌘+I)", nodeType: ItalicPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.italic, null));
|
|
67385
68364
|
const CodeToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Code (⌘+E)", nodeType: CodePlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.code, null));
|
|
68365
|
+
const HighlightToolbarButton = () => /* @__PURE__ */ React__default.createElement(HighlightColorToolbarButton, null);
|
|
68366
|
+
const useHighlightToolbar = () => {
|
|
68367
|
+
const editor = useEditorRef();
|
|
68368
|
+
const openState = useOpenState();
|
|
68369
|
+
const savedSelection = React__default.useRef(editor.selection);
|
|
68370
|
+
const inlineCodeActive = useMarkToolbarButtonState({
|
|
68371
|
+
nodeType: CodePlugin.key
|
|
68372
|
+
}).pressed;
|
|
68373
|
+
const rememberSelection = React__default.useCallback(() => {
|
|
68374
|
+
if (editor.selection) {
|
|
68375
|
+
savedSelection.current = structuredClone(editor.selection);
|
|
68376
|
+
}
|
|
68377
|
+
}, [editor]);
|
|
68378
|
+
React__default.useEffect(() => {
|
|
68379
|
+
if (openState.open) {
|
|
68380
|
+
rememberSelection();
|
|
68381
|
+
}
|
|
68382
|
+
}, [openState.open, rememberSelection]);
|
|
68383
|
+
const applyHighlight = React__default.useCallback(
|
|
68384
|
+
(highlightColor) => {
|
|
68385
|
+
if (inlineCodeActive) {
|
|
68386
|
+
openState.onOpenChange(false);
|
|
68387
|
+
return;
|
|
68388
|
+
}
|
|
68389
|
+
if (savedSelection.current) {
|
|
68390
|
+
editor.tf.select(structuredClone(savedSelection.current));
|
|
68391
|
+
}
|
|
68392
|
+
if (highlightColor) {
|
|
68393
|
+
editor.tf.addMark("highlight", true);
|
|
68394
|
+
editor.tf.addMark("highlightColor", highlightColor);
|
|
68395
|
+
} else {
|
|
68396
|
+
editor.tf.removeMark("highlight");
|
|
68397
|
+
editor.tf.removeMark("highlightColor");
|
|
68398
|
+
}
|
|
68399
|
+
editor.tf.setNodes(
|
|
68400
|
+
highlightColor ? {
|
|
68401
|
+
highlight: true,
|
|
68402
|
+
highlightColor
|
|
68403
|
+
} : {
|
|
68404
|
+
highlight: void 0,
|
|
68405
|
+
highlightColor: void 0
|
|
68406
|
+
},
|
|
68407
|
+
{
|
|
68408
|
+
at: editor.selection ?? void 0,
|
|
68409
|
+
match: (node3) => editor.api.isText(node3),
|
|
68410
|
+
split: true
|
|
68411
|
+
}
|
|
68412
|
+
);
|
|
68413
|
+
editor.tf.focus();
|
|
68414
|
+
openState.onOpenChange(false);
|
|
68415
|
+
},
|
|
68416
|
+
[editor, inlineCodeActive, openState]
|
|
68417
|
+
);
|
|
68418
|
+
return {
|
|
68419
|
+
applyHighlight,
|
|
68420
|
+
inlineCodeActive,
|
|
68421
|
+
openState,
|
|
68422
|
+
rememberSelection
|
|
68423
|
+
};
|
|
68424
|
+
};
|
|
68425
|
+
const HighlightColorToolbarButton = () => {
|
|
68426
|
+
const { applyHighlight, inlineCodeActive, openState, rememberSelection } = useHighlightToolbar();
|
|
68427
|
+
return /* @__PURE__ */ React__default.createElement(DropdownMenu$1, { modal: false, ...openState }, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement(
|
|
68428
|
+
ToolbarButton,
|
|
68429
|
+
{
|
|
68430
|
+
isDropdown: true,
|
|
68431
|
+
showArrow: true,
|
|
68432
|
+
pressed: openState.open,
|
|
68433
|
+
tooltip: "Highlight color",
|
|
68434
|
+
disabled: inlineCodeActive,
|
|
68435
|
+
onMouseDown: rememberSelection
|
|
68436
|
+
},
|
|
68437
|
+
/* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React__default.createElement(Icons.highlight, null), /* @__PURE__ */ React__default.createElement("span", { className: "sr-only" }, "Highlight color"))
|
|
68438
|
+
)), /* @__PURE__ */ React__default.createElement(DropdownMenuContent$1, { align: "start", className: "min-w-[180px]" }, /* @__PURE__ */ React__default.createElement(DropdownMenuItem$1, { onSelect: () => applyHighlight() }, "Clear highlight"), highlightColors.map((color) => /* @__PURE__ */ React__default.createElement(
|
|
68439
|
+
DropdownMenuItem$1,
|
|
68440
|
+
{
|
|
68441
|
+
key: color.value,
|
|
68442
|
+
onSelect: () => applyHighlight(color.value)
|
|
68443
|
+
},
|
|
68444
|
+
/* @__PURE__ */ React__default.createElement(
|
|
68445
|
+
"span",
|
|
68446
|
+
{
|
|
68447
|
+
className: "mr-2 inline-block size-4 rounded border border-gray-300",
|
|
68448
|
+
style: { backgroundColor: color.value }
|
|
68449
|
+
}
|
|
68450
|
+
),
|
|
68451
|
+
color.label
|
|
68452
|
+
))));
|
|
68453
|
+
};
|
|
67386
68454
|
const ListToolbarButton = withRef$1(({ nodeType = BulletedListPlugin.key, ...rest }, ref) => {
|
|
67387
68455
|
const state = useListToolbarButtonState({ nodeType });
|
|
67388
68456
|
const { props } = useListToolbarButton(state);
|
|
@@ -67616,6 +68684,11 @@ const toolbarItems = {
|
|
|
67616
68684
|
width: () => STANDARD_ICON_WIDTH,
|
|
67617
68685
|
Component: /* @__PURE__ */ React__default.createElement(StrikethroughToolbarButton, null)
|
|
67618
68686
|
},
|
|
68687
|
+
highlight: {
|
|
68688
|
+
label: "Highlight",
|
|
68689
|
+
width: () => STANDARD_ICON_WIDTH,
|
|
68690
|
+
Component: /* @__PURE__ */ React__default.createElement(HighlightToolbarButton, null)
|
|
68691
|
+
},
|
|
67619
68692
|
italic: {
|
|
67620
68693
|
label: "Italic",
|
|
67621
68694
|
width: () => STANDARD_ICON_WIDTH,
|
|
@@ -68803,7 +69876,7 @@ const FloatingToolbar = withRef$1(({ children, state, ...props }, propRef) => {
|
|
|
68803
69876
|
Toolbar,
|
|
68804
69877
|
{
|
|
68805
69878
|
className: cn$1(
|
|
68806
|
-
"absolute z-[
|
|
69879
|
+
"absolute z-[10799] whitespace-nowrap border bg-popover px-1 opacity-100 shadow-md print:hidden rounded-md"
|
|
68807
69880
|
),
|
|
68808
69881
|
...props,
|
|
68809
69882
|
...rootProps,
|
|
@@ -119698,6 +120771,7 @@ const resetBlockTypesCodeBlockRule = {
|
|
|
119698
120771
|
const viewPlugins = [
|
|
119699
120772
|
BasicMarksPlugin,
|
|
119700
120773
|
UnderlinePlugin,
|
|
120774
|
+
HighlightPlugin,
|
|
119701
120775
|
HeadingPlugin.configure({ options: { levels: 6 } }),
|
|
119702
120776
|
ParagraphPlugin,
|
|
119703
120777
|
CodeBlockPlugin.configure({
|
|
@@ -119708,6 +120782,30 @@ const viewPlugins = [
|
|
|
119708
120782
|
const CorrectNodeBehaviorPlugin = createSlatePlugin$1({
|
|
119709
120783
|
key: "WITH_CORRECT_NODE_BEHAVIOR"
|
|
119710
120784
|
});
|
|
120785
|
+
const ClearHighlightOnEnterPlugin = createSlatePlugin$1({
|
|
120786
|
+
key: "CLEAR_HIGHLIGHT_ON_ENTER"
|
|
120787
|
+
}).overrideEditor(({ editor, tf: { insertBreak: insertBreak2 } }) => ({
|
|
120788
|
+
transforms: {
|
|
120789
|
+
insertBreak() {
|
|
120790
|
+
const keyboardEvent = editor.currentKeyboardEvent;
|
|
120791
|
+
const isPlainEnter = (keyboardEvent == null ? void 0 : keyboardEvent.key) === "Enter" && !keyboardEvent.shiftKey && !keyboardEvent.metaKey && !keyboardEvent.ctrlKey && !keyboardEvent.altKey;
|
|
120792
|
+
const activeMarks = editor.api.marks();
|
|
120793
|
+
const hasHighlight = Boolean(
|
|
120794
|
+
(activeMarks == null ? void 0 : activeMarks.highlight) || (activeMarks == null ? void 0 : activeMarks.highlightColor)
|
|
120795
|
+
);
|
|
120796
|
+
insertBreak2();
|
|
120797
|
+
if (!isPlainEnter || !hasHighlight) {
|
|
120798
|
+
return;
|
|
120799
|
+
}
|
|
120800
|
+
editor.tf.removeMark("highlight");
|
|
120801
|
+
editor.tf.removeMark("highlightColor");
|
|
120802
|
+
editor.tf.unsetNodes(["highlight", "highlightColor"], {
|
|
120803
|
+
at: editor.selection ?? void 0,
|
|
120804
|
+
match: (node3) => editor.api.isText(node3)
|
|
120805
|
+
});
|
|
120806
|
+
}
|
|
120807
|
+
}
|
|
120808
|
+
}));
|
|
119711
120809
|
const editorPlugins = [
|
|
119712
120810
|
createMdxBlockPlugin,
|
|
119713
120811
|
createMdxInlinePlugin,
|
|
@@ -119717,6 +120815,7 @@ const editorPlugins = [
|
|
|
119717
120815
|
createBlockquoteEnterBreakPlugin,
|
|
119718
120816
|
createInvalidMarkdownPlugin,
|
|
119719
120817
|
CorrectNodeBehaviorPlugin,
|
|
120818
|
+
ClearHighlightOnEnterPlugin,
|
|
119720
120819
|
LinkPlugin.configure({
|
|
119721
120820
|
options: {
|
|
119722
120821
|
// Custom validation function to allow relative links, e.g., /about
|