tinacms 2.7.5 → 2.7.7

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.mjs CHANGED
@@ -12,9 +12,9 @@ import { withRef, cn as cn$1, withVariants, withProps, withCn, createPrimitiveEl
12
12
  import { toggleList, ELEMENT_UL, ELEMENT_OL, ELEMENT_H1 as ELEMENT_H1$1, ELEMENT_H2 as ELEMENT_H2$1, ELEMENT_H3 as ELEMENT_H3$1, ELEMENT_H4, ELEMENT_H5, ELEMENT_H6, ELEMENT_PARAGRAPH, ELEMENT_BLOCKQUOTE, ELEMENT_CODE_BLOCK, ELEMENT_CODE_LINE, ELEMENT_CODE_SYNTAX, ELEMENT_LI, ELEMENT_LINK, MARK_CODE, MARK_UNDERLINE, MARK_STRIKETHROUGH, MARK_ITALIC, MARK_BOLD, ELEMENT_HR, ELEMENT_TABLE, ELEMENT_TR, ELEMENT_TD, ELEMENT_TH, unwrapList, ELEMENT_TODO_LI, createTrailingBlockPlugin, createAutoformatPlugin, createExitBreakPlugin, KEYS_HEADING, createResetNodePlugin, createBasicMarksPlugin, createHeadingPlugin, createParagraphPlugin, createBlockquotePlugin, createUnderlinePlugin, createListPlugin, createIndentListPlugin, createHorizontalRulePlugin, createNodeIdPlugin, createTablePlugin, getListItemEntry, useListToolbarButtonState, useListToolbarButton } from "@udecode/plate";
13
13
  import { PlateElement, isCollapsed, findNodePath, getPointAfter, insertNodes, ELEMENT_DEFAULT, focusEditor, getPointBefore, setNodes, isElement, PlateLeaf, createPluginFactory, useComposedRef, useEditorRef, createPointRef, insertText, moveSelection, toggleNodeType, useElement, useRemoveNodeButton, useEditorSelector, isSelectionExpanded, withHOC, normalizeEditor, getBlockAbove, queryNode, getParentNode, isType, someNode, isSelectionAtBlockStart, setElements, insertNode, getPluginType, isBlock, isBlockAboveEmpty, findNode, PlateContent, getNodeEntries, useEditorState, collapseSelection, insertEmptyElement, useMarkToolbarButtonState, useMarkToolbarButton, usePlateSelectors, useEventEditorSelectors, PortalBody, useFormInputProps, createPlugins, Plate } from "@udecode/plate-common";
14
14
  import { ELEMENT_SLASH_INPUT, createSlashPlugin } from "@udecode/plate-slash-command";
15
- import { useSelected, useReadOnly, ReactEditor } from "slate-react";
16
15
  import { useCodeBlockElementState, useCodeSyntaxLeaf, ELEMENT_CODE_BLOCK as ELEMENT_CODE_BLOCK$1 } from "@udecode/plate-code-block";
17
16
  import MonacoEditor, { loader, useMonaco } from "@monaco-editor/react";
17
+ import { useSelected, useReadOnly, ReactEditor } from "slate-react";
18
18
  import { Combobox as Combobox$1, ComboboxInput, ComboboxButton, Transition, ComboboxOptions, ComboboxOption, Popover as Popover$3, PopoverButton, PopoverPanel, TransitionChild, Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItems, MenuItem } from "@headlessui/react";
19
19
  import { cva } from "class-variance-authority";
20
20
  import { Eye, SquarePen, Plus, AlignCenter as AlignCenter$1, AlignJustify, AlignLeft as AlignLeft$1, AlignRight as AlignRight$1, ChevronDown, PaintBucket, Quote, Check, ChevronRight, ChevronsUpDown, X, 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, Search, Settings, Strikethrough, Subscript, Superscript, Table, Text, Underline, Link2Off, Moon, SunMedium, Twitter } from "lucide-react";
@@ -2981,7 +2981,6 @@ const Components = () => {
2981
2981
  children,
2982
2982
  ...props
2983
2983
  }) => {
2984
- const selected = useSelected();
2985
2984
  return /* @__PURE__ */ React__default.createElement(
2986
2985
  "div",
2987
2986
  {
@@ -2992,8 +2991,7 @@ const Components = () => {
2992
2991
  ...attributes,
2993
2992
  ...props
2994
2993
  },
2995
- children,
2996
- selected && /* @__PURE__ */ React__default.createElement("span", { className: "absolute h-4 -top-2 inset-0 ring-2 ring-blue-100 ring-inset rounded-md z-10 pointer-events-none" })
2994
+ children
2997
2995
  );
2998
2996
  },
2999
2997
  [ELEMENT_TABLE]: TableElement,
@@ -8724,6 +8722,73 @@ class GlobalFormPlugin {
8724
8722
  };
8725
8723
  }
8726
8724
  }
8725
+ let Alerts$1 = class Alerts {
8726
+ constructor(events, map = {}) {
8727
+ this.events = events;
8728
+ this.map = map;
8729
+ this.alerts = /* @__PURE__ */ new Map();
8730
+ this.mapEventToAlert = (event) => {
8731
+ const toAlert = this.map[event.type];
8732
+ if (toAlert) {
8733
+ let getArgs;
8734
+ if (typeof toAlert === "function") {
8735
+ getArgs = toAlert;
8736
+ } else {
8737
+ getArgs = () => toAlert;
8738
+ }
8739
+ const { level, message, timeout } = getArgs(event);
8740
+ this.add(level, message, timeout);
8741
+ }
8742
+ };
8743
+ this.events.subscribe("*", this.mapEventToAlert);
8744
+ }
8745
+ setMap(eventsToAlerts) {
8746
+ this.map = {
8747
+ ...this.map,
8748
+ ...eventsToAlerts
8749
+ };
8750
+ }
8751
+ add(level, message, timeout = 4e3) {
8752
+ const alert = {
8753
+ level,
8754
+ message,
8755
+ timeout,
8756
+ id: `${message}|${Date.now()}`
8757
+ };
8758
+ this.alerts.set(alert.id, alert);
8759
+ this.events.dispatch({ type: "alerts:add", alert });
8760
+ let timeoutId = null;
8761
+ const dismiss = () => {
8762
+ clearTimeout(timeoutId);
8763
+ this.dismiss(alert);
8764
+ };
8765
+ timeoutId = level !== "error" ? setTimeout(dismiss, alert.timeout) : null;
8766
+ return dismiss;
8767
+ }
8768
+ dismiss(alert) {
8769
+ this.alerts.delete(alert.id);
8770
+ this.events.dispatch({ type: "alerts:remove", alert });
8771
+ }
8772
+ subscribe(cb) {
8773
+ const unsub = this.events.subscribe("alerts", cb);
8774
+ return () => unsub();
8775
+ }
8776
+ get all() {
8777
+ return Array.from(this.alerts.values());
8778
+ }
8779
+ info(message, timeout) {
8780
+ return this.add("info", message, timeout);
8781
+ }
8782
+ success(message, timeout) {
8783
+ return this.add("success", message, timeout);
8784
+ }
8785
+ warn(message, timeout) {
8786
+ return this.add("warn", message, timeout);
8787
+ }
8788
+ error(message, timeout) {
8789
+ return this.add("error", message, timeout);
8790
+ }
8791
+ };
8727
8792
  class PluginTypeManager {
8728
8793
  constructor(events) {
8729
8794
  this.events = events;
@@ -9568,128 +9633,42 @@ const _CMS = class _CMS2 {
9568
9633
  _CMS.ENABLED = { type: "cms:enable" };
9569
9634
  _CMS.DISABLED = { type: "cms:disable" };
9570
9635
  let CMS = _CMS;
9571
- let Alerts$1 = class Alerts {
9572
- constructor(events, map = {}) {
9573
- this.events = events;
9574
- this.map = map;
9575
- this.alerts = /* @__PURE__ */ new Map();
9576
- this.mapEventToAlert = (event) => {
9577
- const toAlert = this.map[event.type];
9578
- if (toAlert) {
9579
- let getArgs;
9580
- if (typeof toAlert === "function") {
9581
- getArgs = toAlert;
9582
- } else {
9583
- getArgs = () => toAlert;
9584
- }
9585
- const { level, message, timeout } = getArgs(event);
9586
- this.add(level, message, timeout);
9587
- }
9588
- };
9589
- this.events.subscribe("*", this.mapEventToAlert);
9590
- }
9591
- setMap(eventsToAlerts) {
9592
- this.map = {
9593
- ...this.map,
9594
- ...eventsToAlerts
9595
- };
9596
- }
9597
- add(level, message, timeout = 4e3) {
9598
- const alert = {
9599
- level,
9600
- message,
9601
- timeout,
9602
- id: `${message}|${Date.now()}`
9603
- };
9604
- this.alerts.set(alert.id, alert);
9605
- this.events.dispatch({ type: "alerts:add", alert });
9606
- let timeoutId = null;
9607
- const dismiss = () => {
9608
- clearTimeout(timeoutId);
9609
- this.dismiss(alert);
9610
- };
9611
- timeoutId = level !== "error" ? setTimeout(dismiss, alert.timeout) : null;
9612
- return dismiss;
9613
- }
9614
- dismiss(alert) {
9615
- this.alerts.delete(alert.id);
9616
- this.events.dispatch({ type: "alerts:remove", alert });
9617
- }
9618
- subscribe(cb) {
9619
- const unsub = this.events.subscribe("alerts", cb);
9620
- return () => unsub();
9621
- }
9622
- get all() {
9623
- return Array.from(this.alerts.values());
9624
- }
9625
- info(message, timeout) {
9626
- return this.add("info", message, timeout);
9627
- }
9628
- success(message, timeout) {
9629
- return this.add("success", message, timeout);
9630
- }
9631
- warn(message, timeout) {
9632
- return this.add("warn", message, timeout);
9633
- }
9634
- error(message, timeout) {
9635
- return this.add("error", message, timeout);
9636
- }
9636
+ const MarkdownFieldPlaceholder = {
9637
+ __type: "field",
9638
+ name: "markdown",
9639
+ Component: createPlaceholder(
9640
+ "Markdown"
9641
+ )
9637
9642
  };
9638
- const SidebarLoadingPlaceholder = () => /* @__PURE__ */ React.createElement(
9639
- "div",
9640
- {
9641
- className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
9642
- style: {
9643
- animationName: "fade-in",
9644
- animationDelay: "300ms",
9645
- animationTimingFunction: "ease-out",
9646
- animationIterationCount: 1,
9647
- animationFillMode: "both",
9648
- animationDuration: "150ms"
9649
- }
9650
- },
9651
- /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Please wait while TinaCMS", /* @__PURE__ */ React.createElement("br", null), "loads your content"),
9652
- /* @__PURE__ */ React.createElement(LoadingDots, { color: "var(--tina-color-primary)" })
9653
- );
9654
- class SidebarState {
9655
- constructor(events, options = {}) {
9656
- var _a, _b;
9657
- this.events = events;
9658
- this._isOpen = false;
9659
- this.position = "displace";
9660
- this.renderNav = true;
9661
- this.buttons = {
9662
- save: "Save",
9663
- reset: "Reset"
9664
- };
9665
- this.position = options.position || "displace";
9666
- this.renderNav = options.renderNav || true;
9667
- this.loadingPlaceholder = options.placeholder || SidebarLoadingPlaceholder;
9668
- if ((_a = options.buttons) == null ? void 0 : _a.save) {
9669
- this.buttons.save = options.buttons.save;
9670
- }
9671
- if ((_b = options.buttons) == null ? void 0 : _b.reset) {
9672
- this.buttons.reset = options.buttons.reset;
9673
- }
9674
- }
9675
- get isOpen() {
9676
- return this._isOpen;
9677
- }
9678
- set isOpen(nextValue) {
9679
- if (this._isOpen === nextValue) {
9680
- return;
9681
- }
9682
- this._isOpen = nextValue;
9683
- if (nextValue) {
9684
- this.events.dispatch({ type: "sidebar:opened" });
9685
- } else {
9686
- this.events.dispatch({ type: "sidebar:closed" });
9687
- }
9688
- }
9689
- subscribe(callback) {
9690
- const unsub = this.events.subscribe("sidebar", callback);
9691
- return () => unsub();
9692
- }
9643
+ const HtmlFieldPlaceholder = {
9644
+ __type: "field",
9645
+ name: "html",
9646
+ Component: createPlaceholder(
9647
+ "HTML"
9648
+ )
9649
+ };
9650
+ function createPlaceholder(name, _pr) {
9651
+ return (props) => {
9652
+ return /* @__PURE__ */ React__default.createElement(
9653
+ FieldMeta,
9654
+ {
9655
+ name: props.input.name,
9656
+ label: `${name} Field not Registered`,
9657
+ tinaForm: props.tinaForm
9658
+ },
9659
+ /* @__PURE__ */ React__default.createElement("p", { className: "whitespace-normal text-[15px] mt-2" }, "The ", name, " field is not registered. Some built-in field types are not bundled by default in an effort to control bundle size. Consult the Tina docs to learn how to use this field type."),
9660
+ /* @__PURE__ */ React__default.createElement("p", { className: "whitespace-normal text-[15px] mt-2" }, /* @__PURE__ */ React__default.createElement(
9661
+ "a",
9662
+ {
9663
+ className: "text-blue-500 underline",
9664
+ href: "https://tina.io/docs/editing/markdown/#registering-the-field-plugins",
9665
+ target: "_blank",
9666
+ rel: "noreferrer noopener"
9667
+ },
9668
+ "Tina Docs: Registering Field Plugins"
9669
+ ))
9670
+ );
9671
+ };
9693
9672
  }
9694
9673
  function createScreen({
9695
9674
  Component,
@@ -9738,2209 +9717,2228 @@ const ModalLayout = ({ children, name, close: close2, layout }) => {
9738
9717
  children
9739
9718
  )));
9740
9719
  };
9741
- function ImFilesEmpty(props) {
9742
- return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 16 16" }, "child": [{ "tag": "path", "attr": { "d": "M14.341 5.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.689 0.561 1.25 1.25 1.25h9.5c0.689 0 1.25-0.561 1.25-1.25v-7.75c0-0.224-0.068-0.615-0.659-1.421zM12.271 4.729c0.48 0.48 0.856 0.912 1.134 1.271h-2.406v-2.405c0.359 0.278 0.792 0.654 1.271 1.134v0zM14 14.75c0 0.136-0.114 0.25-0.25 0.25h-9.5c-0.136 0-0.25-0.114-0.25-0.25v-11.5c0-0.135 0.114-0.25 0.25-0.25 0 0 5.749-0 5.75 0v3.5c0 0.276 0.224 0.5 0.5 0.5h3.5v7.75z" }, "child": [] }, { "tag": "path", "attr": { "d": "M9.421 0.659c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.604 0.43 1.109 1 1.225v-12.725c0-0.135 0.115-0.25 0.25-0.25h7.607c-0.151-0.124-0.297-0.238-0.437-0.341z" }, "child": [] }] })(props);
9720
+ function dirname(path) {
9721
+ var _a, _b;
9722
+ const pattern = new RegExp("(?<prevDir>.*)/");
9723
+ return (_b = (_a = path.match(pattern)) == null ? void 0 : _a.groups) == null ? void 0 : _b.prevDir;
9743
9724
  }
9744
- function ImUsers(props) {
9745
- return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 18 16" }, "child": [{ "tag": "path", "attr": { "d": "M12 12.041v-0.825c1.102-0.621 2-2.168 2-3.716 0-2.485 0-4.5-3-4.5s-3 2.015-3 4.5c0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h14c0-2.015-2.608-3.682-6-3.959z" }, "child": [] }, { "tag": "path", "attr": { "d": "M5.112 12.427c0.864-0.565 1.939-0.994 3.122-1.256-0.235-0.278-0.449-0.588-0.633-0.922-0.475-0.863-0.726-1.813-0.726-2.748 0-1.344 0-2.614 0.478-3.653 0.464-1.008 1.299-1.633 2.488-1.867-0.264-1.195-0.968-1.98-2.841-1.98-3 0-3 2.015-3 4.5 0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h4.359c0.227-0.202 0.478-0.393 0.753-0.573z" }, "child": [] }] })(props);
9725
+ const BreadcrumbButton = ({ className = "", ...props }) => /* @__PURE__ */ React__default.createElement(
9726
+ "button",
9727
+ {
9728
+ className: "capitalize transition-colors duration-150 border-0 bg-transparent hover:text-blue-500 " + className,
9729
+ ...props
9730
+ }
9731
+ );
9732
+ function Breadcrumb$1({ directory = "", setDirectory }) {
9733
+ directory = directory.replace(/^\/|\/$/g, "");
9734
+ let prevDir = dirname(directory) || "";
9735
+ if (prevDir === ".") {
9736
+ prevDir = "";
9737
+ }
9738
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex items-center text-[16px] text-gray-300" }, directory !== "" && /* @__PURE__ */ React__default.createElement(
9739
+ IconButton,
9740
+ {
9741
+ variant: "ghost",
9742
+ className: "mr-2",
9743
+ onClick: () => setDirectory(prevDir)
9744
+ },
9745
+ /* @__PURE__ */ React__default.createElement(
9746
+ LeftArrowIcon,
9747
+ {
9748
+ className: `w-7 h-auto fill-gray-300 hover:fill-gray-900 transition duration-150 ease-out`
9749
+ }
9750
+ )
9751
+ ), /* @__PURE__ */ React__default.createElement(
9752
+ BreadcrumbButton,
9753
+ {
9754
+ onClick: () => setDirectory(""),
9755
+ className: directory === "" ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"
9756
+ },
9757
+ "Media"
9758
+ ), directory && directory.split("/").map((part, index, parts) => {
9759
+ const currentDir = parts.slice(0, index + 1).join("/");
9760
+ return /* @__PURE__ */ React__default.createElement(
9761
+ BreadcrumbButton,
9762
+ {
9763
+ className: "pl-1.5 " + (index + 1 === parts.length ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"),
9764
+ key: currentDir,
9765
+ onClick: () => {
9766
+ setDirectory(currentDir);
9767
+ }
9768
+ },
9769
+ part
9770
+ );
9771
+ }));
9746
9772
  }
9747
- const LocalWarning = () => {
9748
- return /* @__PURE__ */ React.createElement(
9749
- "a",
9773
+ const CopyField = ({ label, description, value }) => {
9774
+ const [copied, setCopied] = React__default.useState(false);
9775
+ const [fadeOut, setFadeOut] = React__default.useState(false);
9776
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, label && /* @__PURE__ */ React__default.createElement("label", { className: "w-full mb-1 block flex-1 text-sm font-bold leading-5 text-gray-700" }, label), /* @__PURE__ */ React__default.createElement(
9777
+ "span",
9750
9778
  {
9751
- className: "flex-grow-0 flex w-full text-xs items-center py-1 px-4 text-yellow-600 bg-gradient-to-r from-yellow-50 to-yellow-100 border-b border-gray-150 shadow-sm",
9752
- href: "https://tina.io/docs/tina-cloud/",
9753
- target: "_blank"
9779
+ onClick: () => {
9780
+ if (copied === true)
9781
+ return;
9782
+ setCopied(true);
9783
+ setTimeout(() => {
9784
+ setFadeOut(true);
9785
+ }, 2500);
9786
+ setTimeout(() => {
9787
+ setCopied(false);
9788
+ setFadeOut(false);
9789
+ }, 3e3);
9790
+ navigator.clipboard.writeText(value);
9791
+ },
9792
+ className: `shadow-inner text-base leading-5 whitespace-normal break-all px-3 py-2 text-gray-600 w-full bg-gray-50 border border-gray-200 transition-all ease-out duration-150 rounded-md relative overflow-hidden appearance-none flex items-center w-full cursor-pointer hover:bg-white hover:text-blue-500 ${copied ? `pointer-events-none` : ``}`
9754
9793
  },
9755
- /* @__PURE__ */ React.createElement(AiFillWarning, { className: "w-5 h-auto inline-block mr-1 opacity-70 text-yellow-600" }),
9794
+ /* @__PURE__ */ React__default.createElement(BiCopyAlt, { className: "relative text-blue-500 shrink-0 w-5 h-auto mr-1.5 -ml-0.5 z-20" }),
9756
9795
  " ",
9757
- "You are currently in",
9758
- /* @__PURE__ */ React.createElement("strong", { className: "ml-1 font-bold text-yellow-700" }, "Local Mode")
9759
- );
9796
+ value,
9797
+ " ",
9798
+ copied && /* @__PURE__ */ React__default.createElement(
9799
+ "span",
9800
+ {
9801
+ className: `${fadeOut ? `opacity-0` : `opacity-100`} text-blue-500 transition-opacity duration-500 absolute right-0 w-full h-full px-3 py-2 bg-white bg-opacity-90 flex items-center justify-center text-center tracking-wide font-medium z-10`
9802
+ },
9803
+ /* @__PURE__ */ React__default.createElement("span", null, "Copied to clipboard!")
9804
+ )
9805
+ ), description && /* @__PURE__ */ React__default.createElement("p", { className: "mt-2 text-sm text-gray-500" }, description));
9760
9806
  };
9761
- const BillingWarning = () => {
9762
- var _a;
9763
- const cms = useCMS$1();
9764
- const api = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina;
9765
- const isCustomContentApi = (api == null ? void 0 : api.isCustomContentApi) || false;
9766
- const [billingState, setBillingState] = React.useState(
9767
- null
9768
- );
9769
- React.useEffect(() => {
9770
- const fetchBillingState = async () => {
9771
- if (typeof (api == null ? void 0 : api.getBillingState) !== "function")
9772
- return;
9773
- const billingRes = await (api == null ? void 0 : api.getBillingState());
9774
- setBillingState(billingRes);
9775
- };
9776
- if (!isCustomContentApi)
9777
- fetchBillingState();
9778
- }, []);
9779
- if (isCustomContentApi || !billingState || billingState.billingState === "current") {
9780
- return /* @__PURE__ */ React.createElement(React.Fragment, null);
9807
+ function ListMediaItem({ item, onClick, active }) {
9808
+ let FileIcon = BiFile;
9809
+ if (item.type === "dir") {
9810
+ FileIcon = BiFolder;
9811
+ } else if (isVideo(item.src)) {
9812
+ FileIcon = BiMovie;
9781
9813
  }
9782
- return /* @__PURE__ */ React.createElement("div", { className: "flex-grow-0 flex flex-wrap w-full text-xs items-center justify-between gap-1.5 py-1.5 px-3 text-red-700 bg-gradient-to-br from-white via-red-50 to-red-100 border-b border-red-200" }, /* @__PURE__ */ React.createElement("span", { className: "flex items-center gap-1 font-bold" }, /* @__PURE__ */ React.createElement(BiError, { className: "w-5 h-auto flex-shrink-0 flex-grow-0 inline-block opacity-70 text-red-600" }), /* @__PURE__ */ React.createElement("span", { className: "flex whitespace-nowrap" }, "There is an issue with your billing.")), /* @__PURE__ */ React.createElement(
9783
- "a",
9814
+ const thumbnail = (item.thumbnails || {})["75x75"];
9815
+ return /* @__PURE__ */ React__default.createElement(
9816
+ "li",
9784
9817
  {
9785
- className: "text-xs text-blue-600 underline decoration-blue-200 hover:text-blue-500 hover:decoration-blue-500 transition-all ease-out duration-150 flex items-center gap-1 self-end",
9786
- href: `https://app.tina.io/projects/${billingState.clientId}/billing`,
9787
- target: "_blank"
9818
+ className: `group relative flex shrink-0 items-center transition duration-150 ease-out cursor-pointer border-b border-gray-150 ${active ? "bg-gradient-to-r from-white to-gray-50/50 text-blue-500 hover:bg-gray-50" : "bg-white hover:bg-gray-50/50 hover:text-blue-500"}`,
9819
+ onClick: () => {
9820
+ if (!active) {
9821
+ onClick(item);
9822
+ } else {
9823
+ onClick(false);
9824
+ }
9825
+ }
9788
9826
  },
9789
- "Visit Billing Page",
9790
- /* @__PURE__ */ React.createElement(BiRightArrowAlt, { className: "w-5 h-full opacity-70" })
9791
- ));
9792
- };
9793
- function FiInfo(props) {
9794
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "circle", "attr": { "cx": "12", "cy": "12", "r": "10" }, "child": [] }, { "tag": "line", "attr": { "x1": "12", "y1": "16", "x2": "12", "y2": "12" }, "child": [] }, { "tag": "line", "attr": { "x1": "12", "y1": "8", "x2": "12.01", "y2": "8" }, "child": [] }] })(props);
9795
- }
9796
- function FiMoreVertical(props) {
9797
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "circle", "attr": { "cx": "12", "cy": "12", "r": "1" }, "child": [] }, { "tag": "circle", "attr": { "cx": "12", "cy": "5", "r": "1" }, "child": [] }, { "tag": "circle", "attr": { "cx": "12", "cy": "19", "r": "1" }, "child": [] }] })(props);
9798
- }
9799
- function VscNewFile(props) {
9800
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 16 16", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "fillRule": "evenodd", "clipRule": "evenodd", "d": "M9.5 1.1l3.4 3.5.1.4v2h-1V6H8V2H3v11h4v1H2.5l-.5-.5v-12l.5-.5h6.7l.3.1zM9 2v3h2.9L9 2zm4 14h-1v-3H9v-1h3V9h1v3h3v1h-3v3z" }, "child": [] }] })(props);
9801
- }
9802
- const FormModal = ({ plugin, close: close2 }) => {
9803
- const cms = useCMS$1();
9804
- const form = useMemo(
9805
- () => new Form({
9806
- id: "create-form-id",
9807
- label: "create-form",
9808
- fields: plugin.fields,
9809
- actions: plugin.actions,
9810
- buttons: plugin.buttons,
9811
- initialValues: plugin.initialValues || {},
9812
- reset: plugin.reset,
9813
- onChange: plugin.onChange,
9814
- onSubmit: async (values) => {
9815
- await plugin.onSubmit(values, cms).then(() => {
9816
- close2();
9817
- });
9827
+ item.new && /* @__PURE__ */ React__default.createElement("span", { className: "absolute top-1.5 left-1.5 rounded-full shadow bg-green-100 border border-green-200 text-[10px] tracking-wide font-bold text-green-600 px-1.5 py-0.5 z-10" }, "NEW"),
9828
+ /* @__PURE__ */ React__default.createElement("div", { className: "w-16 h-16 bg-gray-50 border-r border-gray-150 overflow-hidden flex justify-center flex-shrink-0" }, isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement(
9829
+ "img",
9830
+ {
9831
+ className: "object-contain object-center w-full h-full origin-center transition-all duration-150 ease-out group-hover:scale-110",
9832
+ src: thumbnail,
9833
+ alt: item.filename
9818
9834
  }
9819
- }),
9820
- [close2, cms, plugin]
9835
+ ) : /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-1/2 h-full fill-gray-300" })),
9836
+ /* @__PURE__ */ React__default.createElement(
9837
+ "span",
9838
+ {
9839
+ className: "text-base flex-grow w-full break-words truncate px-3 py-2"
9840
+ },
9841
+ item.filename
9842
+ )
9821
9843
  );
9822
- return /* @__PURE__ */ React.createElement(Modal, { id: "content-creator-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement(PopupModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, plugin.name), /* @__PURE__ */ React.createElement(ModalBody, null, /* @__PURE__ */ React.createElement(FormBuilder, { form: { tinaForm: form } }))));
9823
- };
9824
- function HiOutlineClipboardList(props) {
9825
- return GenIcon({ "tag": "svg", "attr": { "fill": "none", "viewBox": "0 0 24 24", "strokeWidth": "2", "stroke": "currentColor", "aria-hidden": "true" }, "child": [{ "tag": "path", "attr": { "strokeLinecap": "round", "strokeLinejoin": "round", "d": "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" }, "child": [] }] })(props);
9826
9844
  }
9827
- const useGetEvents = (cms, cursor, existingEvents) => {
9828
- const [events, setEvents] = useState([]);
9829
- const [nextCursor, setNextCursor] = useState(void 0);
9830
- const [loading, setLoading] = useState(true);
9831
- const [error, setError] = useState(void 0);
9832
- React.useEffect(() => {
9833
- const fetchEvents = async () => {
9834
- var _a, _b, _c, _d, _e;
9835
- let doFetchEvents = false;
9836
- if (!((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi)) {
9837
- doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
9838
- }
9839
- if (doFetchEvents) {
9840
- try {
9841
- const { events: nextEvents, cursor: nextCursor2 } = await cms.api.tina.fetchEvents(15, cursor);
9842
- setEvents([...existingEvents, ...nextEvents]);
9843
- setNextCursor(nextCursor2);
9844
- } catch (error2) {
9845
- cms.alerts.error(
9846
- `[${error2.name}] GetEvents failed: ${error2.message}`,
9847
- 30 * 1e3
9848
- // 30 seconds
9849
- );
9850
- console.error(error2);
9851
- setEvents(void 0);
9852
- setError(error2);
9853
- }
9854
- setLoading(false);
9855
- }
9856
- };
9857
- setLoading(true);
9858
- fetchEvents();
9859
- }, [cms, cursor]);
9860
- return { events, cursor: nextCursor, loading, error };
9861
- };
9862
- function useSyncStatus$1(cms) {
9863
- var _a, _b;
9864
- const [syncStatus, setSyncStatus] = useState({ state: "loading", message: "Loading..." });
9865
- React.useEffect(() => {
9866
- const interval = setInterval(async () => {
9867
- var _a2, _b2, _c, _d, _e;
9868
- let doFetchEvents = false;
9869
- if (!((_b2 = (_a2 = cms.api) == null ? void 0 : _a2.tina) == null ? void 0 : _b2.isCustomContentApi)) {
9870
- doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
9871
- }
9872
- if (doFetchEvents) {
9873
- const { events } = await cms.api.tina.fetchEvents();
9874
- if (events.length === 0) {
9875
- setSyncStatus({ state: "success", message: "No Events" });
9876
- } else {
9877
- if (events[0].isError) {
9878
- setSyncStatus({
9879
- state: "error",
9880
- message: `Sync Failure ${events[0].message}`
9881
- });
9845
+ function GridMediaItem({ item, active, onClick }) {
9846
+ let FileIcon = BiFile;
9847
+ if (item.type === "dir") {
9848
+ FileIcon = BiFolder;
9849
+ } else if (isVideo(item.src)) {
9850
+ FileIcon = BiMovie;
9851
+ }
9852
+ const thumbnail = (item.thumbnails || {})["400x400"];
9853
+ return /* @__PURE__ */ React__default.createElement(
9854
+ "li",
9855
+ {
9856
+ className: `relative pb-[100%] h-0 block border border-gray-100 rounded-md overflow-hidden flex justify-center shrink-0 w-full transition duration-150 ease-out ${active ? "shadow-outline" : "shadow hover:shadow-md hover:scale-103 hover:border-gray-150"} ${item.type === "dir" ? "cursor-pointer" : ""}`
9857
+ },
9858
+ item.new && /* @__PURE__ */ React__default.createElement("span", { className: "absolute top-1.5 left-1.5 rounded-full shadow bg-green-100 border border-green-200 text-[10px] tracking-wide font-bold text-green-600 px-1.5 py-0.5 z-10" }, "NEW"),
9859
+ /* @__PURE__ */ React__default.createElement(
9860
+ "button",
9861
+ {
9862
+ className: "absolute w-full h-full flex items-center justify-center bg-white",
9863
+ onClick: () => {
9864
+ if (!active) {
9865
+ onClick(item);
9882
9866
  } else {
9883
- setSyncStatus({ state: "success", message: "Sync Successful" });
9867
+ onClick(false);
9884
9868
  }
9885
9869
  }
9886
- } else {
9887
- setSyncStatus({ state: "unauthorized", message: "Not Authenticated" });
9888
- }
9889
- }, 5e3);
9890
- return () => clearInterval(interval);
9891
- }, [(_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi]);
9892
- return syncStatus;
9870
+ },
9871
+ isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement(
9872
+ "img",
9873
+ {
9874
+ className: "object-contain object-center w-full h-full",
9875
+ src: thumbnail,
9876
+ alt: item.filename
9877
+ }
9878
+ ) : /* @__PURE__ */ React__default.createElement("div", { className: "p-4 w-full flex flex-col gap-4 items-center justify-center" }, /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-[30%] h-auto fill-gray-300" }), /* @__PURE__ */ React__default.createElement("span", { className: "block text-base text-gray-600 w-full break-words truncate" }, item.filename))
9879
+ )
9880
+ );
9893
9881
  }
9894
- const SyncErrorWidget = ({ cms }) => {
9895
- const syncStatus = useSyncStatus$1(cms);
9896
- if (syncStatus.state !== "error") {
9897
- return null;
9898
- }
9899
- return /* @__PURE__ */ React.createElement(
9900
- "div",
9882
+ const DeleteModal$1 = ({
9883
+ close: close2,
9884
+ deleteFunc,
9885
+ filename
9886
+ }) => {
9887
+ const [processing, setProcessing] = React__default.useState(false);
9888
+ return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, "Delete ", filename), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", null, "Are you sure you want to delete ", /* @__PURE__ */ React__default.createElement("strong", null, filename), "?")), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement(Button$1, { style: { flexGrow: 2 }, disabled: processing, onClick: close2 }, "Cancel"), /* @__PURE__ */ React__default.createElement(
9889
+ Button$1,
9901
9890
  {
9902
- title: syncStatus.message,
9903
- className: "flex-grow-0 flex text-xs items-center"
9891
+ style: { flexGrow: 3 },
9892
+ disabled: processing,
9893
+ variant: "danger",
9894
+ onClick: async () => {
9895
+ setProcessing(true);
9896
+ try {
9897
+ await deleteFunc();
9898
+ } catch (e) {
9899
+ console.error(e);
9900
+ } finally {
9901
+ close2();
9902
+ }
9903
+ }
9904
9904
  },
9905
- /* @__PURE__ */ React.createElement(MdSyncProblem, { className: "w-6 h-full ml-2 text-red-500 fill-current" })
9906
- );
9905
+ /* @__PURE__ */ React__default.createElement("span", { className: "mr-1" }, "Delete"),
9906
+ processing && /* @__PURE__ */ React__default.createElement(LoadingDots, null)
9907
+ ))));
9907
9908
  };
9908
- const EventsList = ({ cms }) => {
9909
- const [cursor, setCursor] = React.useState(void 0);
9910
- const [existingEvents, setExistingEvents] = React.useState([]);
9911
- const {
9912
- events,
9913
- cursor: nextCursor,
9914
- loading,
9915
- error
9916
- } = useGetEvents(cms, cursor, existingEvents);
9917
- return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-4 w-full h-full grow-0" }, events.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "shrink grow-0 overflow-scroll w-full rounded-md shadow ring-1 ring-black ring-opacity-5" }, /* @__PURE__ */ React.createElement("table", { className: "w-full divide-y divide-gray-100" }, events.map((event, index) => {
9918
- const date = new Date(event.timestamp).toDateString();
9919
- const time = new Date(event.timestamp).toTimeString();
9920
- return /* @__PURE__ */ React.createElement("tr", { className: index % 2 === 0 ? "" : "bg-gray-50" }, event.isError ? /* @__PURE__ */ React.createElement(
9921
- "td",
9922
- {
9923
- key: `${event.id}_error_icon`,
9924
- className: "py-3 pl-4 pr-0 w-0"
9925
- },
9926
- /* @__PURE__ */ React.createElement(BsExclamationOctagonFill, { className: "text-red-500 fill-current w-5 h-auto" })
9927
- ) : /* @__PURE__ */ React.createElement(
9928
- "td",
9929
- {
9930
- key: `${event.id}_ok_icon`,
9931
- className: "py-3 pl-4 pr-0 w-0"
9932
- },
9933
- /* @__PURE__ */ React.createElement(BsCheckCircleFill, { className: "text-green-500 fill-current w-5 h-auto" })
9934
- ), /* @__PURE__ */ React.createElement(
9935
- "td",
9936
- {
9937
- key: `${event.id}_msg`,
9938
- className: "whitespace-nowrap p-3 text-base text-gray-500"
9939
- },
9940
- event.message,
9941
- event.isError && /* @__PURE__ */ React.createElement("div", { className: "w-full text-gray-300 text-xs mt-0.5" }, event.id)
9942
- ), /* @__PURE__ */ React.createElement(
9943
- "td",
9944
- {
9945
- key: `${event.id}_ts`,
9946
- className: "whitespace-nowrap py-3 pl-3 pr-4 text-sm text-gray-500"
9947
- },
9948
- date,
9949
- /* @__PURE__ */ React.createElement("span", { className: "w-full block text-gray-300 text-xs mt-0.5" }, time)
9950
- ));
9951
- }).flat())), loading && /* @__PURE__ */ React.createElement("div", { className: "text-sm text-gray-400 text-center" }, "Loading..."), error && /* @__PURE__ */ React.createElement("div", null, "Error: ", error.message), /* @__PURE__ */ React.createElement("div", { className: "text-center flex-1" }, /* @__PURE__ */ React.createElement(
9909
+ const NewFolderModal = ({ onSubmit, close: close2 }) => {
9910
+ const [folderName, setFolderName] = React__default.useState("");
9911
+ return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, "New Folder"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", { className: "text-base text-gray-700 mb-2" }, "Please provide a name for your folder."), /* @__PURE__ */ React__default.createElement("p", { className: "text-sm text-gray-500 mb-4 italic" }, /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, "Note"), " – If you navigate away before uploading a media item, the folder will disappear."), /* @__PURE__ */ React__default.createElement(
9912
+ Input,
9913
+ {
9914
+ value: folderName,
9915
+ placeholder: "Folder Name",
9916
+ required: true,
9917
+ onChange: (e) => setFolderName(e.target.value)
9918
+ }
9919
+ )), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement(Button$1, { style: { flexGrow: 2 }, onClick: close2 }, "Cancel"), /* @__PURE__ */ React__default.createElement(
9952
9920
  Button$1,
9953
9921
  {
9922
+ disabled: !folderName,
9923
+ style: { flexGrow: 3 },
9924
+ variant: "primary",
9954
9925
  onClick: () => {
9955
- setExistingEvents(events);
9956
- setCursor(nextCursor);
9926
+ if (!folderName)
9927
+ return;
9928
+ onSubmit(folderName);
9929
+ close2();
9957
9930
  }
9958
9931
  },
9959
- "Load More Events"
9960
- )));
9932
+ "Create New Folder"
9933
+ ))));
9961
9934
  };
9962
- const SyncStatusModal = ({ closeEventsModal, cms }) => /* @__PURE__ */ React.createElement(Modal, null, /* @__PURE__ */ React.createElement(FullscreenModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: closeEventsModal }, "Event Log"), /* @__PURE__ */ React.createElement(ModalBody, { className: "flex h-full flex-col", padded: true }, /* @__PURE__ */ React.createElement(EventsList, { cms }))));
9963
- const SyncStatus = ({ cms, setEventsOpen }) => {
9964
- var _a, _b;
9965
- const syncStatus = useSyncStatus$1(cms);
9966
- function openEventsModal() {
9967
- setEventsOpen(true);
9968
- }
9969
- if ((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi) {
9935
+ const { useDropzone } = dropzone;
9936
+ const join = function(...parts) {
9937
+ const [first, last, slash] = [0, parts.length - 1, "/"];
9938
+ const matchLeadingSlash = new RegExp("^" + slash);
9939
+ const matchTrailingSlash = new RegExp(slash + "$");
9940
+ parts = parts.map(function(part, index) {
9941
+ if (index === first && part === "file://")
9942
+ return part;
9943
+ if (index > first)
9944
+ part = part.replace(matchLeadingSlash, "");
9945
+ if (index < last)
9946
+ part = part.replace(matchTrailingSlash, "");
9947
+ return part;
9948
+ });
9949
+ return parts.join(slash);
9950
+ };
9951
+ function MediaManager2() {
9952
+ const cms = useCMS();
9953
+ const [request, setRequest] = useState();
9954
+ useEffect(() => {
9955
+ return cms.events.subscribe("media:open", ({ type, ...request2 }) => {
9956
+ setRequest(request2);
9957
+ });
9958
+ }, []);
9959
+ if (!request)
9970
9960
  return null;
9971
- }
9972
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
9973
- "button",
9961
+ const close2 = () => setRequest(void 0);
9962
+ return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(FullscreenModal, null, /* @__PURE__ */ React__default.createElement("div", { className: "w-full bg-gray-50 flex items-center justify-between px-5 pt-3 m-0" }, /* @__PURE__ */ React__default.createElement("h2", { className: "text-gray-500 font-sans font-medium text-base leading-none m-0 block truncate" }, "Media Manager"), /* @__PURE__ */ React__default.createElement(
9963
+ "div",
9974
9964
  {
9975
- className: `text-lg px-4 py-2 first:pt-3 last:pb-3 tracking-wide whitespace-nowrap flex items-center opacity-80 text-gray-600 hover:text-blue-400 hover:bg-gray-50 hover:opacity-100`,
9976
- onClick: openEventsModal
9965
+ onClick: close2,
9966
+ className: "flex items-center fill-gray-400 cursor-pointer transition-colors duration-100 ease-out hover:fill-gray-700"
9977
9967
  },
9978
- syncStatus.state !== "error" ? /* @__PURE__ */ React.createElement(HiOutlineClipboardList, { className: "w-6 h-auto mr-2 text-blue-400" }) : /* @__PURE__ */ React.createElement(MdSyncProblem, { className: "w-6 h-auto mr-2 text-red-400" }),
9979
- " ",
9980
- "Event Log"
9981
- ));
9982
- };
9983
- const version = "2.7.5";
9984
- const Nav = ({
9985
- isLocalMode,
9986
- className = "",
9987
- children,
9988
- showCollections,
9989
- collectionsInfo,
9990
- screens,
9991
- cloudConfigs,
9992
- contentCreators,
9993
- sidebarWidth,
9994
- RenderNavSite,
9995
- RenderNavCloud,
9996
- RenderNavCollection,
9997
- AuthRenderNavCollection,
9968
+ /* @__PURE__ */ React__default.createElement(CloseIcon, { className: "w-6 h-auto" })
9969
+ )), /* @__PURE__ */ React__default.createElement(ModalBody, { className: "flex h-full flex-col" }, /* @__PURE__ */ React__default.createElement(MediaPicker, { ...request, close: close2 }))));
9970
+ }
9971
+ const defaultListError = new MediaListError({
9972
+ title: "Error fetching media",
9973
+ message: "Something went wrong while requesting the resource.",
9974
+ docsLink: "https://tina.io/docs/media/#media-store"
9975
+ });
9976
+ function MediaPicker({
9977
+ allowDelete,
9978
+ onSelect,
9979
+ close: close2,
9998
9980
  ...props
9999
- }) => {
10000
- const cms = useCMS$1();
10001
- const [eventsOpen, setEventsOpen] = React.useState(false);
10002
- const { contentCollections, authCollection } = collectionsInfo.collections.reduce(
10003
- (acc, collection) => {
10004
- if (collection.isAuthCollection) {
10005
- acc.authCollection = collection;
9981
+ }) {
9982
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
9983
+ const cms = useCMS();
9984
+ const [listState, setListState] = useState(() => {
9985
+ if (cms.media.isConfigured)
9986
+ return "loading";
9987
+ return "not-configured";
9988
+ });
9989
+ const [deleteModalOpen, setDeleteModalOpen] = React__default.useState(false);
9990
+ const [newFolderModalOpen, setNewFolderModalOpen] = React__default.useState(false);
9991
+ const [listError, setListError] = useState(defaultListError);
9992
+ const [directory, setDirectory] = useState(
9993
+ props.directory
9994
+ );
9995
+ const [list, setList] = useState({
9996
+ items: [],
9997
+ nextOffset: void 0
9998
+ });
9999
+ const resetList = () => setList({
10000
+ items: [],
10001
+ nextOffset: void 0
10002
+ });
10003
+ const [viewMode, setViewMode] = useState("grid");
10004
+ const [activeItem, setActiveItem] = useState(false);
10005
+ const closePreview = () => setActiveItem(false);
10006
+ const [refreshing, setRefreshing] = useState(false);
10007
+ const [loadFolders, setLoadFolders] = useState(true);
10008
+ const [offsetHistory, setOffsetHistory] = useState([]);
10009
+ const offset2 = offsetHistory[offsetHistory.length - 1];
10010
+ const resetOffset = () => setOffsetHistory([]);
10011
+ async function loadMedia(loadFolders2 = true) {
10012
+ setListState("loading");
10013
+ try {
10014
+ const _list = await cms.media.list({
10015
+ offset: offset2,
10016
+ limit: cms.media.pageSize,
10017
+ directory,
10018
+ thumbnailSizes: [
10019
+ { w: 75, h: 75 },
10020
+ { w: 400, h: 400 },
10021
+ { w: 1e3, h: 1e3 }
10022
+ ],
10023
+ filesOnly: !loadFolders2
10024
+ });
10025
+ setList({
10026
+ items: [...list.items, ..._list.items],
10027
+ nextOffset: _list.nextOffset
10028
+ });
10029
+ setListState("loaded");
10030
+ } catch (e) {
10031
+ console.error(e);
10032
+ if (e.ERR_TYPE === "MediaListError") {
10033
+ setListError(e);
10006
10034
  } else {
10007
- acc.contentCollections.push(collection);
10035
+ setListError(defaultListError);
10008
10036
  }
10009
- return acc;
10010
- },
10011
- {
10012
- contentCollections: []
10037
+ setListState("error");
10013
10038
  }
10014
- );
10015
- function closeEventsModal() {
10016
- setEventsOpen(false);
10017
10039
  }
10018
- const WrappedSyncStatus = React.forwardRef(
10019
- (props2, ref) => /* @__PURE__ */ React.createElement(SyncStatus, { ...props2 })
10020
- );
10021
- const screenCategories = screens.reduce(
10022
- (acc, screen) => {
10023
- const category = screen.navCategory || "Site";
10024
- acc[category] = acc[category] || [];
10025
- acc[category].push(screen);
10026
- return acc;
10027
- },
10028
- { Site: [] }
10029
- );
10030
- return /* @__PURE__ */ React.createElement(
10031
- "div",
10032
- {
10033
- className: `relative z-30 flex flex-col bg-white border-r border-gray-200 w-96 h-full ${className}`,
10034
- style: { maxWidth: `${sidebarWidth}px` },
10035
- ...props
10036
- },
10037
- /* @__PURE__ */ React.createElement("div", { className: "border-b border-gray-200" }, /* @__PURE__ */ React.createElement(Menu, { as: "div", className: "relative block" }, ({ open: open2 }) => /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
10038
- MenuButton,
10039
- {
10040
- className: `group w-full px-6 py-3 gap-2 flex justify-between items-center transition-colors duration-150 ease-out ${open2 ? "bg-gray-50" : "bg-transparent"}`
10041
- },
10042
- /* @__PURE__ */ React.createElement("span", { className: "text-left inline-flex items-center text-xl tracking-wide text-gray-800 flex-1 gap-1 opacity-80 group-hover:opacity-100 transition-opacity duration-150 ease-out" }, /* @__PURE__ */ React.createElement(
10043
- "svg",
10044
- {
10045
- viewBox: "0 0 32 32",
10046
- fill: "#EC4815",
10047
- xmlns: "http://www.w3.org/2000/svg",
10048
- className: "w-10 h-auto -ml-1"
10049
- },
10050
- /* @__PURE__ */ React.createElement("path", { d: "M18.6466 14.5553C19.9018 13.5141 20.458 7.36086 21.0014 5.14903C21.5447 2.9372 23.7919 3.04938 23.7919 3.04938C23.7919 3.04938 23.2085 4.06764 23.4464 4.82751C23.6844 5.58738 25.3145 6.26662 25.3145 6.26662L24.9629 7.19622C24.9629 7.19622 24.2288 7.10204 23.7919 7.9785C23.355 8.85496 24.3392 17.4442 24.3392 17.4442C24.3392 17.4442 21.4469 22.7275 21.4469 24.9206C21.4469 27.1136 22.4819 28.9515 22.4819 28.9515H21.0296C21.0296 28.9515 18.899 26.4086 18.462 25.1378C18.0251 23.8669 18.1998 22.596 18.1998 22.596C18.1998 22.596 15.8839 22.4646 13.8303 22.596C11.7767 22.7275 10.4072 24.498 10.16 25.4884C9.91287 26.4787 9.81048 28.9515 9.81048 28.9515H8.66211C7.96315 26.7882 7.40803 26.0129 7.70918 24.9206C8.54334 21.8949 8.37949 20.1788 8.18635 19.4145C7.99321 18.6501 6.68552 17.983 6.68552 17.983C7.32609 16.6741 7.97996 16.0452 10.7926 15.9796C13.6052 15.914 17.3915 15.5965 18.6466 14.5553Z" }),
10051
- /* @__PURE__ */ React.createElement("path", { d: "M11.1268 24.7939C11.1268 24.7939 11.4236 27.5481 13.0001 28.9516H14.3511C13.0001 27.4166 12.8527 23.4155 12.8527 23.4155C12.1656 23.6399 11.3045 24.3846 11.1268 24.7939Z" })
10052
- ), /* @__PURE__ */ React.createElement("span", null, "Tina")),
10053
- /* @__PURE__ */ React.createElement(SyncErrorWidget, { cms }),
10054
- /* @__PURE__ */ React.createElement(
10055
- FiMoreVertical,
10056
- {
10057
- className: `flex-0 w-6 h-full inline-block group-hover:opacity-80 transition-all duration-300 ease-in-out transform ${open2 ? "opacity-100 text-blue-400" : "text-gray-400 opacity-50 hover:opacity-70"}`
10058
- }
10059
- )
10060
- ), /* @__PURE__ */ React.createElement("div", { className: "transform translate-y-full absolute bottom-3 right-5 z-50" }, /* @__PURE__ */ React.createElement(
10061
- Transition,
10062
- {
10063
- enter: "transition duration-150 ease-out",
10064
- enterFrom: "transform opacity-0 -translate-y-2",
10065
- enterTo: "transform opacity-100 translate-y-0",
10066
- leave: "transition duration-75 ease-in",
10067
- leaveFrom: "transform opacity-100 translate-y-0",
10068
- leaveTo: "transform opacity-0 -translate-y-2"
10069
- },
10070
- /* @__PURE__ */ React.createElement(MenuItems, { className: "bg-white border border-gray-150 rounded-lg shadow-lg flex flex-col items-stretch overflow-hidden" }, /* @__PURE__ */ React.createElement(MenuItem, null, /* @__PURE__ */ React.createElement(
10071
- "button",
10072
- {
10073
- className: `text-lg px-4 py-2 first:pt-3 last:pb-3 tracking-wide whitespace-nowrap flex items-center opacity-80 text-gray-600 hover:text-blue-400 hover:bg-gray-50 hover:opacity-100`,
10074
- onClick: async () => {
10075
- var _a, _b, _c, _d, _e, _f, _g, _h;
10076
- updateBodyDisplacement({
10077
- displayState: "closed",
10078
- sidebarWidth: null,
10079
- resizingSidebar: false
10080
- });
10081
- try {
10082
- if ((_c = (_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.authProvider) == null ? void 0 : _c.logout) {
10083
- await ((_d = cms.api.tina) == null ? void 0 : _d.authProvider.logout());
10084
- if ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.onLogout) {
10085
- await ((_h = (_g = cms == null ? void 0 : cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.onLogout());
10086
- await new Promise(
10087
- (resolve) => setTimeout(resolve, 500)
10088
- );
10089
- }
10090
- window.location.href = new URL(
10091
- window.location.href
10092
- ).pathname;
10093
- }
10094
- } catch (e) {
10095
- cms.alerts.error(`Error logging out: ${e}`);
10096
- console.error("Unexpected error calling logout");
10097
- console.error(e);
10098
- }
10040
+ useEffect(() => {
10041
+ if (!refreshing)
10042
+ return;
10043
+ loadMedia();
10044
+ setRefreshing(false);
10045
+ }, [refreshing]);
10046
+ useEffect(() => {
10047
+ if (!cms.media.isConfigured)
10048
+ return;
10049
+ if (refreshing)
10050
+ return;
10051
+ loadMedia(loadFolders);
10052
+ if (loadFolders)
10053
+ setLoadFolders(false);
10054
+ return cms.events.subscribe(
10055
+ ["media:delete:success", "media:pageSize"],
10056
+ () => {
10057
+ setRefreshing(true);
10058
+ resetOffset();
10059
+ resetList();
10060
+ }
10061
+ );
10062
+ }, [offset2, directory, cms.media.isConfigured]);
10063
+ const onClickMediaItem = (item) => {
10064
+ if (!item) {
10065
+ setActiveItem(false);
10066
+ } else if (item.type === "dir") {
10067
+ setDirectory(
10068
+ item.directory === "." || item.directory === "" ? item.filename : join(item.directory, item.filename)
10069
+ );
10070
+ setLoadFolders(true);
10071
+ resetOffset();
10072
+ resetList();
10073
+ setActiveItem(false);
10074
+ } else {
10075
+ setActiveItem(item);
10076
+ }
10077
+ };
10078
+ let deleteMediaItem;
10079
+ if (allowDelete) {
10080
+ deleteMediaItem = async (item) => {
10081
+ await cms.media.delete(item);
10082
+ };
10083
+ }
10084
+ let selectMediaItem;
10085
+ if (onSelect) {
10086
+ selectMediaItem = (item) => {
10087
+ onSelect(item);
10088
+ if (close2)
10089
+ close2();
10090
+ };
10091
+ }
10092
+ const [uploading, setUploading] = useState(false);
10093
+ const accept = Array.isArray(
10094
+ (_c = (_b = (_a = cms.api.tina.schema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.media) == null ? void 0 : _c.accept
10095
+ ) ? (_f = (_e = (_d = cms.api.tina.schema.schema) == null ? void 0 : _d.config) == null ? void 0 : _e.media) == null ? void 0 : _f.accept.join(",") : (_i = (_h = (_g = cms.api.tina.schema.schema) == null ? void 0 : _g.config) == null ? void 0 : _h.media) == null ? void 0 : _i.accept;
10096
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({
10097
+ accept: dropzoneAcceptFromString(
10098
+ accept || cms.media.accept || DEFAULT_MEDIA_UPLOAD_TYPES
10099
+ ),
10100
+ maxSize: cms.media.maxSize,
10101
+ multiple: true,
10102
+ onDrop: async (files, fileRejections) => {
10103
+ try {
10104
+ setUploading(true);
10105
+ const mediaItems = await cms.media.persist(
10106
+ files.map((file) => {
10107
+ return {
10108
+ directory: directory || "/",
10109
+ file
10110
+ };
10111
+ })
10112
+ );
10113
+ const errorCodes = {
10114
+ "file-invalid-type": "Invalid file type",
10115
+ "file-too-large": "File too large",
10116
+ "file-too-small": "File too small",
10117
+ "too-many-files": "Too many files"
10118
+ };
10119
+ const printError = (error) => {
10120
+ const message = errorCodes[error.code];
10121
+ if (message) {
10122
+ return message;
10099
10123
  }
10100
- },
10101
- /* @__PURE__ */ React.createElement(BiExit, { className: "w-6 h-auto mr-2 text-blue-400" }),
10102
- " Log Out"
10103
- )), /* @__PURE__ */ React.createElement(MenuItem, null, /* @__PURE__ */ React.createElement(
10104
- WrappedSyncStatus,
10105
- {
10106
- cms,
10107
- setEventsOpen
10124
+ console.error(error);
10125
+ return "Unknown error";
10126
+ };
10127
+ if (fileRejections.length > 0) {
10128
+ const messages = [];
10129
+ fileRejections.map((fileRejection) => {
10130
+ messages.push(
10131
+ `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
10132
+ );
10133
+ });
10134
+ cms.alerts.error(() => {
10135
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React__default.createElement("br", null), messages.join(". "), ".");
10136
+ });
10108
10137
  }
10109
- )))
10110
- ))))),
10111
- eventsOpen && /* @__PURE__ */ React.createElement(SyncStatusModal, { cms, closeEventsModal }),
10112
- children,
10113
- /* @__PURE__ */ React.createElement("div", { className: "flex flex-col px-6 flex-1 overflow-auto" }, showCollections && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "flex space-x-1 justify-items-start uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, /* @__PURE__ */ React.createElement("span", null, "Collections"), isLocalMode && /* @__PURE__ */ React.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React.createElement(
10114
- "a",
10115
- {
10116
- href: "https://tina.io/docs/schema/#defining-collections",
10117
- target: "_blank"
10118
- },
10119
- /* @__PURE__ */ React.createElement(FiInfo, null)
10120
- ))), /* @__PURE__ */ React.createElement(
10121
- CollectionsList,
10122
- {
10123
- RenderNavCollection,
10124
- collections: contentCollections
10138
+ if (mediaItems.length !== 0) {
10139
+ setActiveItem(mediaItems[0]);
10140
+ setList((mediaList) => {
10141
+ return {
10142
+ items: [
10143
+ // all the newly added items are new
10144
+ ...mediaItems.map((x) => ({ ...x, new: true })),
10145
+ ...mediaList.items
10146
+ ],
10147
+ nextOffset: mediaList.nextOffset
10148
+ };
10149
+ });
10150
+ }
10151
+ } catch {
10125
10152
  }
10126
- )), (screenCategories.Site.length > 0 || contentCreators.length) > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Site"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screenCategories.Site.map((view) => {
10127
- return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
10128
- }), contentCreators.map((plugin, idx) => {
10129
- return /* @__PURE__ */ React.createElement(CreateContentNavItem, { key: `plugin-${idx}`, plugin });
10130
- }), authCollection && /* @__PURE__ */ React.createElement(
10131
- CollectionsList,
10132
- {
10133
- RenderNavCollection: AuthRenderNavCollection,
10134
- collections: [authCollection]
10153
+ setUploading(false);
10154
+ }
10155
+ });
10156
+ const { onClick, ...rootProps } = getRootProps();
10157
+ function disableScrollBody() {
10158
+ const body = document == null ? void 0 : document.body;
10159
+ body.style.overflow = "hidden";
10160
+ return () => {
10161
+ body.style.overflow = "auto";
10162
+ };
10163
+ }
10164
+ useEffect(disableScrollBody, []);
10165
+ const loaderRef = useRef(null);
10166
+ useEffect(() => {
10167
+ const observer = new IntersectionObserver((entries) => {
10168
+ const target = entries[0];
10169
+ if (target.isIntersecting && list.nextOffset) {
10170
+ setOffsetHistory((offsetHistory2) => [
10171
+ ...offsetHistory2,
10172
+ list.nextOffset
10173
+ ]);
10135
10174
  }
10136
- ))), Object.entries(screenCategories).map(([category, screens2]) => {
10137
- if (category !== "Site") {
10138
- return /* @__PURE__ */ React.createElement("div", { key: category }, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, category), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screens2.map((view) => {
10139
- return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
10140
- })));
10175
+ });
10176
+ if (loaderRef.current) {
10177
+ observer.observe(loaderRef.current);
10178
+ }
10179
+ return () => {
10180
+ if (loaderRef.current) {
10181
+ observer.unobserve(loaderRef.current);
10141
10182
  }
10142
- }), !!(cloudConfigs == null ? void 0 : cloudConfigs.length) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Cloud"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, cloudConfigs.map((config) => {
10143
- return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${config.name}` }, /* @__PURE__ */ React.createElement(RenderNavCloud, { config }));
10144
- }))), /* @__PURE__ */ React.createElement("div", { className: "grow" }), /* @__PURE__ */ React.createElement("span", { className: "font-sans font-light text-xs mb-3 mt-8 text-gray-500" }, "v", version))
10145
- );
10146
- };
10147
- const CollectionsList = ({
10148
- collections,
10149
- RenderNavCollection
10150
- }) => {
10151
- if (collections.length === 0) {
10152
- return /* @__PURE__ */ React.createElement("div", null, "No collections found");
10153
- }
10154
- return /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, collections.map((collection) => {
10155
- return /* @__PURE__ */ React.createElement("li", { key: `nav-collection-${collection.name}` }, /* @__PURE__ */ React.createElement(RenderNavCollection, { collection }));
10156
- }));
10157
- };
10158
- const CreateContentNavItem = ({ plugin }) => {
10159
- const [open2, setOpen] = React.useState(false);
10160
- return /* @__PURE__ */ React.createElement("li", { key: plugin.name }, /* @__PURE__ */ React.createElement(
10161
- "button",
10162
- {
10163
- className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100",
10164
- onClick: () => {
10165
- setOpen(true);
10166
- }
10167
- },
10168
- /* @__PURE__ */ React.createElement(VscNewFile, { className: "mr-3 h-6 opacity-80 w-auto" }),
10169
- " ",
10170
- plugin.name
10171
- ), open2 && /* @__PURE__ */ React.createElement(FormModal, { plugin, close: () => setOpen(false) }));
10172
- };
10173
- const ResizeHandle = () => {
10174
- const {
10175
- resizingSidebar,
10176
- setResizingSidebar,
10177
- fullscreen,
10178
- setSidebarWidth,
10179
- displayState
10180
- } = React.useContext(SidebarContext);
10181
- React.useEffect(() => {
10182
- const handleMouseUp = () => setResizingSidebar(false);
10183
- window.addEventListener("mouseup", handleMouseUp);
10184
- return () => {
10185
- window.removeEventListener("mouseup", handleMouseUp);
10186
10183
  };
10187
- }, []);
10188
- React.useEffect(() => {
10189
- const handleMouseMove = (e) => {
10190
- setSidebarWidth((sidebarWidth) => {
10191
- const newWidth = sidebarWidth + e.movementX;
10192
- const maxWidth = window.innerWidth - 8;
10193
- if (newWidth < minSidebarWidth) {
10194
- return minSidebarWidth;
10195
- } else if (newWidth > maxWidth) {
10196
- return maxWidth;
10197
- } else {
10198
- return newWidth;
10184
+ }, [list.nextOffset, loaderRef.current]);
10185
+ if (listState === "loading" && !((_j = list == null ? void 0 : list.items) == null ? void 0 : _j.length) || uploading) {
10186
+ return /* @__PURE__ */ React__default.createElement(LoadingMediaList, null);
10187
+ }
10188
+ if (listState === "not-configured") {
10189
+ return /* @__PURE__ */ React__default.createElement(
10190
+ DocsLink,
10191
+ {
10192
+ title: "No Media Store Configured",
10193
+ message: "To use the media manager, you need to configure a Media Store.",
10194
+ docsLink: "https://tina.io/docs/reference/media/overview/"
10195
+ }
10196
+ );
10197
+ }
10198
+ if (listState === "error") {
10199
+ const { title, message, docsLink } = listError;
10200
+ return /* @__PURE__ */ React__default.createElement(DocsLink, { title, message, docsLink });
10201
+ }
10202
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, deleteModalOpen && /* @__PURE__ */ React__default.createElement(
10203
+ DeleteModal$1,
10204
+ {
10205
+ filename: activeItem ? activeItem.filename : "",
10206
+ deleteFunc: async () => {
10207
+ if (activeItem) {
10208
+ await deleteMediaItem(activeItem);
10209
+ setActiveItem(false);
10199
10210
  }
10200
- });
10201
- };
10202
- if (resizingSidebar) {
10203
- window.addEventListener("mousemove", handleMouseMove);
10204
- document.body.classList.add("select-none");
10211
+ },
10212
+ close: () => setDeleteModalOpen(false)
10205
10213
  }
10206
- return () => {
10207
- window.removeEventListener("mousemove", handleMouseMove);
10208
- document.body.classList.remove("select-none");
10209
- };
10210
- }, [resizingSidebar]);
10211
- const handleresizingSidebar = () => setResizingSidebar(true);
10212
- if (fullscreen) {
10213
- return null;
10214
- }
10215
- return /* @__PURE__ */ React.createElement(
10216
- "div",
10214
+ ), newFolderModalOpen && /* @__PURE__ */ React__default.createElement(
10215
+ NewFolderModal,
10217
10216
  {
10218
- onMouseDown: handleresizingSidebar,
10219
- className: `z-100 absolute top-1/2 right-px w-2 h-32 bg-white rounded-r-md border border-gray-150 shadow-sm hover:shadow-md origin-left transition-all duration-150 ease-out transform translate-x-full -translate-y-1/2 group hover:bg-gray-50 ${displayState !== "closed" ? `opacity-100` : `opacity-0`} ${resizingSidebar ? `scale-110` : `scale-90 hover:scale-100`}`,
10220
- style: { cursor: "grab" }
10217
+ onSubmit: (name) => {
10218
+ setDirectory((oldDir) => {
10219
+ if (oldDir) {
10220
+ return join(oldDir, name);
10221
+ } else {
10222
+ return name;
10223
+ }
10224
+ });
10225
+ resetOffset();
10226
+ resetList();
10227
+ },
10228
+ close: () => setNewFolderModalOpen(false)
10229
+ }
10230
+ ), /* @__PURE__ */ React__default.createElement(MediaPickerWrap, null, /* @__PURE__ */ React__default.createElement(SyncStatusContainer, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-wrap items-center bg-gray-50 border-b border-gray-150 gap-4 py-3 px-5 shadow-sm flex-shrink-0" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-1 items-center gap-4" }, /* @__PURE__ */ React__default.createElement(ViewModeToggle, { viewMode, setViewMode }), /* @__PURE__ */ React__default.createElement(
10231
+ Breadcrumb$1,
10232
+ {
10233
+ directory,
10234
+ setDirectory: (dir) => {
10235
+ setDirectory(dir);
10236
+ setLoadFolders(true);
10237
+ resetOffset();
10238
+ resetList();
10239
+ setActiveItem(false);
10240
+ }
10241
+ }
10242
+ )), cms.media.store.isStatic ? null : /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-wrap items-center gap-4" }, /* @__PURE__ */ React__default.createElement(
10243
+ Button$1,
10244
+ {
10245
+ busy: false,
10246
+ variant: "white",
10247
+ onClick: () => {
10248
+ setRefreshing(true);
10249
+ resetOffset();
10250
+ resetList();
10251
+ setActiveItem(false);
10252
+ },
10253
+ className: "whitespace-nowrap"
10221
10254
  },
10222
- /* @__PURE__ */ React.createElement("span", { className: "absolute top-1/2 left-1/2 h-4/6 w-px bg-gray-200 transform -translate-y-1/2 -translate-x-1/2 opacity-30 transition-opacity duration-150 ease-out group-hover:opacity-100" })
10223
- );
10224
- };
10225
- const Item = ({
10226
- item,
10227
- depth,
10228
- setActiveFormId
10229
- }) => {
10230
- const cms = useCMS();
10231
- const depths = ["pl-6", "pl-10", "pl-14"];
10232
- const form = React.useMemo(
10233
- () => cms.state.forms.find(({ tinaForm }) => item.formId === tinaForm.id),
10234
- [item.formId]
10235
- );
10236
- return /* @__PURE__ */ React.createElement(
10237
- "button",
10255
+ "Refresh",
10256
+ /* @__PURE__ */ React__default.createElement(IoMdRefresh, { className: "w-6 h-full ml-2 opacity-70 text-blue-500" })
10257
+ ), /* @__PURE__ */ React__default.createElement(
10258
+ Button$1,
10238
10259
  {
10239
- type: "button",
10240
- key: item.path,
10241
- onClick: () => setActiveFormId(item.formId),
10242
- className: `${depths[depth] || "pl-12"} pr-6 py-3 w-full h-full bg-transparent border-none text-lg text-gray-700 group hover:bg-gray-50 transition-all ease-out duration-150 flex items-center justify-between gap-2`
10260
+ busy: false,
10261
+ variant: "white",
10262
+ onClick: () => {
10263
+ setNewFolderModalOpen(true);
10264
+ },
10265
+ className: "whitespace-nowrap"
10243
10266
  },
10244
- /* @__PURE__ */ React.createElement(BiEdit, { className: "opacity-70 w-5 h-auto text-blue-500 flex-none" }),
10245
- /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex flex-col gap-0.5 items-start" }, /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 font-sans text-xs font-semibold text-gray-700 whitespace-normal" }, form.tinaForm.label), /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 text-base truncate leading-tight text-gray-600" }, form.tinaForm.id))
10246
- );
10247
- };
10248
- const FormListItem = ({
10249
- item,
10250
- depth,
10251
- setActiveFormId
10252
- }) => {
10253
- var _a;
10254
- return /* @__PURE__ */ React.createElement("div", { className: "divide-y divide-gray-200" }, /* @__PURE__ */ React.createElement(Item, { setActiveFormId, item, depth }), item.subItems && /* @__PURE__ */ React.createElement("ul", { className: "divide-y divide-gray-200" }, (_a = item.subItems) == null ? void 0 : _a.map((subItem) => {
10255
- if (subItem.type === "document") {
10256
- return /* @__PURE__ */ React.createElement("li", { key: subItem.formId }, /* @__PURE__ */ React.createElement(
10257
- Item,
10258
- {
10259
- setActiveFormId,
10260
- depth: depth + 1,
10261
- item: subItem
10262
- }
10263
- ));
10264
- }
10265
- })));
10266
- };
10267
- const FormLists = (props) => {
10268
- const cms = useCMS();
10269
- return /* @__PURE__ */ React.createElement(
10270
- Transition,
10267
+ "New Folder",
10268
+ /* @__PURE__ */ React__default.createElement(BiFolder, { className: "w-6 h-full ml-2 opacity-70 text-blue-500" })
10269
+ ), /* @__PURE__ */ React__default.createElement(UploadButton, { onClick, uploading }))), /* @__PURE__ */ React__default.createElement("div", { className: "flex h-full overflow-hidden bg-white" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex w-full flex-col h-full @container" }, /* @__PURE__ */ React__default.createElement(
10270
+ "ul",
10271
10271
  {
10272
- appear: true,
10273
- show: true,
10274
- as: "div",
10275
- enter: "transition-all ease-out duration-150",
10276
- enterFrom: "opacity-0 -translate-x-1/2",
10277
- enterTo: "opacity-100",
10278
- leave: "transition-all ease-out duration-150",
10279
- leaveFrom: "opacity-100",
10280
- leaveTo: "opacity-0 -translate-x-1/2"
10272
+ ...rootProps,
10273
+ className: `h-full grow overflow-y-auto transition duration-150 ease-out bg-gradient-to-b from-gray-50/50 to-gray-50 ${list.items.length === 0 || viewMode === "list" && "w-full flex flex-1 flex-col justify-start -mb-px"} ${list.items.length > 0 && viewMode === "grid" && "w-full p-4 gap-4 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 4xl:grid-cols-6 6xl:grid-cols-9 auto-rows-auto content-start justify-start"} ${isDragActive ? `border-2 border-blue-500 rounded-lg` : ``}`
10281
10274
  },
10282
- cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}`, className: "pt-16" }, /* @__PURE__ */ React.createElement(
10283
- FormList,
10275
+ /* @__PURE__ */ React__default.createElement("input", { ...getInputProps() }),
10276
+ listState === "loaded" && list.items.length === 0 && /* @__PURE__ */ React__default.createElement(EmptyMediaList, null),
10277
+ viewMode === "list" && list.items.map((item) => /* @__PURE__ */ React__default.createElement(
10278
+ ListMediaItem,
10284
10279
  {
10285
- isEditing: props.isEditing,
10286
- setActiveFormId: (id) => {
10287
- cms.dispatch({ type: "forms:set-active-form-id", value: id });
10288
- },
10289
- formList
10290
- }
10291
- )))
10292
- );
10293
- };
10294
- const FormList = (props) => {
10295
- const cms = useCMS();
10296
- const listItems = React.useMemo(() => {
10297
- var _a;
10298
- const orderedListItems = [];
10299
- const globalItems = [];
10300
- const topItems = [];
10301
- props.formList.items.forEach((item) => {
10302
- if (item.type === "document") {
10303
- const form = cms.state.forms.find(
10304
- ({ tinaForm }) => tinaForm.id === item.formId
10305
- );
10306
- if (form.tinaForm.global) {
10307
- globalItems.push(item);
10308
- } else {
10309
- orderedListItems.push(item);
10310
- }
10311
- } else {
10312
- orderedListItems.push(item);
10280
+ key: item.id,
10281
+ item,
10282
+ onClick: onClickMediaItem,
10283
+ active: activeItem && activeItem.id === item.id
10313
10284
  }
10314
- });
10315
- if (((_a = orderedListItems[0]) == null ? void 0 : _a.type) === "document") {
10316
- topItems.push({ type: "list", label: "Documents" });
10317
- }
10318
- let extra = [];
10319
- if (globalItems.length) {
10320
- extra = [{ type: "list", label: "Global Documents" }, ...globalItems];
10321
- }
10322
- return [...topItems, ...orderedListItems, ...extra];
10323
- }, [JSON.stringify(props.formList.items)]);
10324
- return /* @__PURE__ */ React.createElement("ul", null, /* @__PURE__ */ React.createElement("li", { className: "divide-y divide-gray-200" }, listItems.map((item, index) => {
10325
- if (item.type === "list") {
10326
- return /* @__PURE__ */ React.createElement(
10327
- "div",
10328
- {
10329
- key: item.label,
10330
- className: `relative group text-left w-full bg-white shadow-sm
10331
- border-gray-100 px-6 -mt-px pb-3 ${index > 0 ? "pt-6 bg-gradient-to-b from-gray-50 via-white to-white" : "pt-3"}`
10332
- },
10333
- /* @__PURE__ */ React.createElement(
10334
- "span",
10335
- {
10336
- className: "text-sm tracking-wide font-bold text-gray-700 uppercase"
10337
- },
10338
- item.label
10339
- )
10340
- );
10341
- }
10342
- return /* @__PURE__ */ React.createElement(
10343
- FormListItem,
10285
+ )),
10286
+ viewMode === "grid" && list.items.map((item) => /* @__PURE__ */ React__default.createElement(
10287
+ GridMediaItem,
10344
10288
  {
10345
- setActiveFormId: (id) => props.setActiveFormId(id),
10346
- key: item.formId,
10289
+ key: item.id,
10347
10290
  item,
10348
- depth: 0
10291
+ onClick: onClickMediaItem,
10292
+ active: activeItem && activeItem.id === item.id
10349
10293
  }
10350
- );
10351
- })));
10352
- };
10353
- const SidebarNoFormsPlaceholder = () => /* @__PURE__ */ React.createElement(
10354
- "div",
10355
- {
10356
- className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
10357
- style: {
10358
- animationName: "fade-in",
10359
- animationDelay: "300ms",
10360
- animationTimingFunction: "ease-out",
10361
- animationIterationCount: 1,
10362
- animationFillMode: "both",
10363
- animationDuration: "150ms"
10364
- }
10365
- },
10366
- /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Looks like there's ", /* @__PURE__ */ React.createElement("br", null), "nothing to edit on ", /* @__PURE__ */ React.createElement("br", null), "this page."),
10367
- /* @__PURE__ */ React.createElement("p", { className: "block pt-5" }, /* @__PURE__ */ React.createElement(
10368
- Button$1,
10369
- {
10370
- href: "https://tina.io/docs/contextual-editing/overview",
10371
- target: "_blank",
10372
- as: "a"
10373
- },
10374
- /* @__PURE__ */ React.createElement(Emoji$1, { className: "mr-1.5" }, "📖"),
10375
- " Contextual Editing Docs"
10376
- ))
10377
- );
10378
- const Emoji$1 = ({ className = "", ...props }) => /* @__PURE__ */ React.createElement(
10379
- "span",
10380
- {
10381
- className: `text-[24px] leading-none inline-block ${className}`,
10382
- ...props
10383
- }
10384
- );
10385
- const minimumTimeToShowLoadingIndicator = 1e3;
10386
- const FormsView = ({ loadingPlaceholder } = {}) => {
10387
- const cms = useCMS$1();
10388
- const { setFormIsPristine } = React.useContext(SidebarContext);
10389
- const [isShowingLoading, setIsShowingLoading] = React.useState(true);
10390
- const [initialLoadComplete, setInitialLoadComplete] = React.useState(false);
10391
- React.useEffect(() => {
10392
- if (cms.state.isLoadingContent) {
10393
- setIsShowingLoading(true);
10394
- const timer = setTimeout(() => {
10395
- if (!cms.state.isLoadingContent) {
10396
- setIsShowingLoading(false);
10397
- setInitialLoadComplete(true);
10398
- }
10399
- }, minimumTimeToShowLoadingIndicator);
10400
- return () => clearTimeout(timer);
10401
- } else {
10402
- const timer = setTimeout(() => {
10403
- setIsShowingLoading(false);
10404
- setInitialLoadComplete(true);
10405
- }, minimumTimeToShowLoadingIndicator);
10406
- return () => clearTimeout(timer);
10407
- }
10408
- }, [cms.state.isLoadingContent]);
10409
- if (isShowingLoading || !initialLoadComplete) {
10410
- const LoadingPlaceholder = loadingPlaceholder || SidebarLoadingPlaceholder;
10411
- return /* @__PURE__ */ React.createElement(LoadingPlaceholder, null);
10412
- }
10413
- if (!cms.state.formLists.length) {
10414
- return /* @__PURE__ */ React.createElement(SidebarNoFormsPlaceholder, null);
10415
- }
10416
- const isMultiform = cms.state.forms.length > 1;
10417
- const activeForm = cms.state.forms.find(
10418
- ({ tinaForm }) => tinaForm.id === cms.state.activeFormId
10419
- );
10420
- const isEditing = !!activeForm;
10421
- if (isMultiform && !activeForm) {
10422
- return /* @__PURE__ */ React.createElement(FormLists, { isEditing });
10423
- }
10424
- const formMetas = cms.plugins.all("form:meta");
10425
- return /* @__PURE__ */ React.createElement(React.Fragment, null, activeForm && /* @__PURE__ */ React.createElement(FormWrapper$1, { isEditing, isMultiform }, isMultiform && /* @__PURE__ */ React.createElement(MultiformFormHeader, { activeForm }), !isMultiform && /* @__PURE__ */ React.createElement(FormHeader, { activeForm }), formMetas == null ? void 0 : formMetas.map((meta) => /* @__PURE__ */ React.createElement(React.Fragment, { key: meta.name }, /* @__PURE__ */ React.createElement(meta.Component, null))), /* @__PURE__ */ React.createElement(FormBuilder, { form: activeForm, onPristineChange: setFormIsPristine })));
10426
- };
10427
- const FormWrapper$1 = ({ isEditing, children }) => {
10428
- return /* @__PURE__ */ React.createElement(
10429
- "div",
10294
+ )),
10295
+ !!list.nextOffset && /* @__PURE__ */ React__default.createElement(LoadingMediaList, { ref: loaderRef })
10296
+ )), /* @__PURE__ */ React__default.createElement(
10297
+ ActiveItemPreview,
10430
10298
  {
10431
- className: "flex-1 flex flex-col flex-nowrap overflow-hidden h-full w-full relative bg-white",
10432
- style: isEditing ? {
10433
- transform: "none",
10434
- animationName: "fly-in-left",
10435
- animationDuration: "150ms",
10436
- animationDelay: "0",
10437
- animationIterationCount: 1,
10438
- animationTimingFunction: "ease-out"
10439
- } : {
10440
- transform: "translate3d(100%, 0, 0)"
10299
+ activeItem,
10300
+ close: closePreview,
10301
+ selectMediaItem,
10302
+ allowDelete: cms.media.store.isStatic ? false : allowDelete,
10303
+ deleteMediaItem: () => {
10304
+ setDeleteModalOpen(true);
10441
10305
  }
10442
- },
10443
- children
10444
- );
10445
- };
10446
- const MultiformFormHeader = ({
10447
- activeForm
10306
+ }
10307
+ )))));
10308
+ }
10309
+ const ActiveItemPreview = ({
10310
+ activeItem,
10311
+ close: close2,
10312
+ selectMediaItem,
10313
+ deleteMediaItem,
10314
+ allowDelete
10448
10315
  }) => {
10449
- const cms = useCMS$1();
10450
- const { formIsPristine } = React.useContext(SidebarContext);
10451
- return /* @__PURE__ */ React.createElement(
10316
+ const thumbnail = activeItem ? (activeItem.thumbnails || {})["1000x1000"] : "";
10317
+ return /* @__PURE__ */ React__default.createElement(
10452
10318
  "div",
10453
10319
  {
10454
- className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
10320
+ className: `shrink-0 h-full flex flex-col items-start gap-3 overflow-y-auto bg-white border-l border-gray-100 bg-white shadow-md transition ease-out duration-150 ${activeItem ? `p-4 opacity-100 w-[35%] max-w-[560px] min-w-[240px]` : `translate-x-8 opacity-0 w-[0px]`}`
10455
10321
  },
10456
- /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
10457
- "button",
10322
+ activeItem && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex grow-0 shrink-0 gap-2 w-full items-center justify-between" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg text-gray-600 w-full max-w-full break-words block truncate flex-1" }, activeItem.filename), /* @__PURE__ */ React__default.createElement(
10323
+ IconButton,
10458
10324
  {
10459
- type: "button",
10460
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10461
- onClick: () => {
10462
- const state = activeForm.tinaForm.finalForm.getState();
10463
- if (state.invalid === true) {
10464
- cms.alerts.error("Cannot navigate away from an invalid form.");
10465
- } else {
10466
- cms.dispatch({ type: "forms:set-active-form-id", value: null });
10467
- }
10325
+ variant: "ghost",
10326
+ className: "group grow-0 shrink-0",
10327
+ onClick: close2
10328
+ },
10329
+ /* @__PURE__ */ React__default.createElement(
10330
+ BiX,
10331
+ {
10332
+ className: `w-7 h-auto text-gray-500 opacity-50 group-hover:opacity-100 transition duration-150 ease-out`
10468
10333
  }
10334
+ )
10335
+ )), isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement("div", { className: "w-full max-h-[75%]" }, /* @__PURE__ */ React__default.createElement(
10336
+ "img",
10337
+ {
10338
+ className: "block border border-gray-100 rounded-md overflow-hidden object-center object-contain max-w-full max-h-full m-auto shadow",
10339
+ src: thumbnail,
10340
+ alt: activeItem.filename
10341
+ }
10342
+ )) : /* @__PURE__ */ React__default.createElement("span", { className: "p-3 border border-gray-100 rounded-md overflow-hidden bg-gray-50 shadow" }, /* @__PURE__ */ React__default.createElement(BiFile, { className: "w-14 h-auto fill-gray-300" })), /* @__PURE__ */ React__default.createElement("div", { className: "grow h-full w-full shrink flex flex-col gap-3 items-start justify-start" }, /* @__PURE__ */ React__default.createElement(CopyField, { value: absoluteImgURL(activeItem.src), label: "URL" })), /* @__PURE__ */ React__default.createElement("div", { className: "shrink-0 w-full flex flex-col justify-end items-start" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex w-full gap-3" }, selectMediaItem && /* @__PURE__ */ React__default.createElement(
10343
+ Button$1,
10344
+ {
10345
+ size: "medium",
10346
+ variant: "primary",
10347
+ className: "grow",
10348
+ onClick: () => selectMediaItem(activeItem)
10469
10349
  },
10470
- /* @__PURE__ */ React.createElement(BiDotsVertical, { className: "h-auto w-5 inline-block opacity-70" })
10471
- ), /* @__PURE__ */ React.createElement(
10472
- "button",
10350
+ "Insert",
10351
+ /* @__PURE__ */ React__default.createElement(BiArrowToBottom, { className: "ml-1 -mr-0.5 w-6 h-auto text-white opacity-70" })
10352
+ ), allowDelete && /* @__PURE__ */ React__default.createElement(
10353
+ Button$1,
10473
10354
  {
10474
- type: "button",
10475
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10476
- onClick: () => {
10477
- const collectionName = cms.api.tina.schema.getCollectionByFullPath(
10478
- cms.state.activeFormId
10479
- ).name;
10480
- window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
10481
- }
10355
+ variant: "white",
10356
+ size: "medium",
10357
+ className: "grow max-w-[40%]",
10358
+ onClick: deleteMediaItem
10482
10359
  },
10483
- /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
10484
- ), /* @__PURE__ */ React.createElement("span", { className: "opacity-30 text-sm leading-tight whitespace-nowrap flex-0" }, "/"), /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, activeForm.tinaForm.label || activeForm.tinaForm.id), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
10360
+ "Delete",
10361
+ /* @__PURE__ */ React__default.createElement(TrashIcon, { className: "ml-1 -mr-0.5 w-6 h-auto text-red-500 opacity-70" })
10362
+ ))))
10485
10363
  );
10486
10364
  };
10487
- const FormHeader = ({ activeForm }) => {
10488
- const { formIsPristine } = React.useContext(SidebarContext);
10489
- const cms = useCMS$1();
10490
- const shortFormLabel = activeForm.tinaForm.label ? activeForm.tinaForm.label.replace(/^.*[\\\/]/, "") : false;
10491
- return /* @__PURE__ */ React.createElement(
10492
- "div",
10365
+ const UploadButton = ({ onClick, uploading }) => {
10366
+ return /* @__PURE__ */ React__default.createElement(
10367
+ Button$1,
10493
10368
  {
10494
- className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
10369
+ variant: "primary",
10370
+ size: "custom",
10371
+ className: "text-sm h-10 px-6",
10372
+ busy: uploading,
10373
+ onClick
10495
10374
  },
10496
- /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
10497
- "button",
10375
+ uploading ? /* @__PURE__ */ React__default.createElement(LoadingDots, null) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload ", /* @__PURE__ */ React__default.createElement(BiCloudUpload, { className: "w-6 h-full ml-2 opacity-70" }))
10376
+ );
10377
+ };
10378
+ const LoadingMediaList = forwardRef(
10379
+ (props, ref) => {
10380
+ const { extraText, ...rest } = props;
10381
+ return /* @__PURE__ */ React__default.createElement(
10382
+ "div",
10498
10383
  {
10499
- type: "button",
10500
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10501
- onClick: () => {
10502
- const collectionName = cms.api.tina.schema.getCollectionByFullPath(
10503
- cms.state.activeFormId
10504
- ).name;
10505
- window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
10506
- }
10384
+ ref,
10385
+ className: "w-full h-full flex flex-col items-center justify-center",
10386
+ ...rest
10507
10387
  },
10508
- /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
10509
- ), shortFormLabel && /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, shortFormLabel), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
10510
- );
10388
+ extraText && /* @__PURE__ */ React__default.createElement("p", null, extraText),
10389
+ /* @__PURE__ */ React__default.createElement(LoadingDots, { color: "var(--tina-color-primary)" })
10390
+ );
10391
+ }
10392
+ );
10393
+ const MediaPickerWrap = ({ children }) => {
10394
+ return /* @__PURE__ */ React__default.createElement("div", { className: "h-full flex-1 text-gray-700 flex flex-col relative bg-gray-50 outline-none active:outline-none focus:outline-none" }, children);
10511
10395
  };
10512
- const SidebarContext = React.createContext(null);
10513
- const minPreviewWidth = 440;
10514
- const minSidebarWidth = 360;
10515
- const navBreakpoint = 1279;
10516
- const LOCALSTATEKEY = "tina.sidebarState";
10517
- const LOCALWIDTHKEY = "tina.sidebarWidth";
10518
- const defaultSidebarWidth = 440;
10519
- const defaultSidebarPosition = "displace";
10520
- const defaultSidebarState = "open";
10521
- function SidebarProvider({
10522
- position = defaultSidebarPosition,
10523
- resizingSidebar,
10524
- setResizingSidebar,
10525
- defaultWidth = defaultSidebarWidth,
10526
- sidebar
10527
- }) {
10396
+ const SyncStatusContext = createContext(
10397
+ void 0
10398
+ );
10399
+ const SyncStatusContainer = ({ children }) => {
10528
10400
  var _a, _b, _c;
10529
- useSubscribable(sidebar);
10530
- const cms = useCMS$1();
10531
- if (!cms.enabled)
10532
- return null;
10533
- return /* @__PURE__ */ React.createElement(
10534
- Sidebar$1,
10535
- {
10536
- position: ((_a = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _a.position) || position,
10537
- defaultWidth: ((_b = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _b.defaultWidth) || defaultWidth,
10538
- resizingSidebar,
10539
- setResizingSidebar,
10540
- renderNav: (
10541
- // @ts-ignore
10542
- typeof ((_c = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _c.renderNav) !== "undefined" ? (
10543
- // @ts-ignore
10544
- cms.sidebar.renderNav
10545
- ) : true
10546
- ),
10547
- sidebar
10548
- }
10549
- );
10550
- }
10551
- const useFetchCollections = (cms) => {
10552
- return { collections: cms.api.admin.fetchCollections(), loading: false };
10553
- };
10554
- const Sidebar$1 = ({
10555
- sidebar,
10556
- defaultWidth,
10557
- // defaultState,
10558
- position,
10559
- renderNav,
10560
- resizingSidebar,
10561
- setResizingSidebar
10562
- }) => {
10563
- var _a, _b, _c, _d, _e, _f;
10564
- const cms = useCMS$1();
10565
- const collectionsInfo = useFetchCollections(cms);
10566
- const [branchingEnabled, setBranchingEnabled] = React.useState(
10567
- () => cms.flags.get("branch-switcher")
10568
- );
10569
- React.useEffect(() => {
10570
- cms.events.subscribe("flag:set", ({ key, value }) => {
10571
- if (key === "branch-switcher") {
10572
- setBranchingEnabled(value);
10573
- }
10574
- });
10575
- }, [cms.events]);
10576
- const screens = cms.plugins.getType("screen");
10577
- const cloudConfigs = cms.plugins.getType("cloud-config");
10578
- useSubscribable(sidebar);
10579
- useSubscribable(screens);
10580
- const allScreens = screens.all();
10581
- const allConfigs = cloudConfigs.all();
10582
- const [menuIsOpen, setMenuIsOpen] = useState(false);
10583
- const [activeScreen, setActiveView] = useState(null);
10584
- const [sidebarWidth, setSidebarWidth] = React.useState(defaultWidth);
10585
- const [formIsPristine, setFormIsPristine] = React.useState(true);
10586
- const activeScreens = allScreens.filter(
10587
- (screen) => {
10588
- var _a2, _b2;
10589
- return screen.navCategory !== "Account" || ((_b2 = (_a2 = cms.api.tina) == null ? void 0 : _a2.authProvider) == null ? void 0 : _b2.getLoginStrategy()) === "UsernamePassword";
10590
- }
10591
- );
10592
- const setDisplayState = (value) => cms.dispatch({ type: "sidebar:set-display-state", value });
10593
- const displayState = cms.state.sidebarDisplayState;
10594
- React.useEffect(() => {
10595
- if (typeof window !== "undefined") {
10596
- const localSidebarState = window.localStorage.getItem(LOCALSTATEKEY);
10597
- const localSidebarWidth = window.localStorage.getItem(LOCALWIDTHKEY);
10598
- if (localSidebarState !== null) {
10599
- setDisplayState(JSON.parse(localSidebarState));
10600
- }
10601
- if (localSidebarWidth !== null) {
10602
- setSidebarWidth(JSON.parse(localSidebarWidth));
10401
+ const cms = useCMS();
10402
+ const isLocal = cms.api.tina.isLocalMode;
10403
+ const tinaMedia = (_c = (_b = (_a = cms.api.tina.schema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.media) == null ? void 0 : _c.tina;
10404
+ const hasTinaMedia = !!((tinaMedia == null ? void 0 : tinaMedia.mediaRoot) || (tinaMedia == null ? void 0 : tinaMedia.publicFolder));
10405
+ const doCheckSyncStatus = hasTinaMedia && !isLocal;
10406
+ const [syncStatus, setSyncStatus] = useState(doCheckSyncStatus ? "loading" : "synced");
10407
+ useEffect(() => {
10408
+ const checkSyncStatus = async () => {
10409
+ if (doCheckSyncStatus) {
10410
+ const project = await cms.api.tina.getProject();
10411
+ setSyncStatus(project.mediaBranch ? "synced" : "needs-sync");
10603
10412
  }
10413
+ };
10414
+ if (!cms.media.store.isStatic) {
10415
+ checkSyncStatus();
10604
10416
  }
10605
10417
  }, []);
10606
- React.useEffect(() => {
10607
- if (typeof window !== "undefined") {
10608
- const localSidebarState = window.localStorage.getItem(LOCALSTATEKEY);
10609
- if (localSidebarState === null) {
10610
- setDisplayState(defaultSidebarState);
10611
- }
10612
- }
10613
- }, [defaultSidebarState]);
10614
- React.useEffect(() => {
10615
- if (typeof window !== "undefined" && cms.enabled) {
10616
- window.localStorage.setItem(LOCALSTATEKEY, JSON.stringify(displayState));
10617
- }
10618
- }, [displayState, cms]);
10619
- React.useEffect(() => {
10620
- if (resizingSidebar) {
10621
- window.localStorage.setItem(LOCALWIDTHKEY, JSON.stringify(sidebarWidth));
10622
- }
10623
- }, [sidebarWidth, resizingSidebar]);
10624
- const isTinaAdminEnabled = cms.flags.get("tina-admin") === false ? false : true;
10625
- const contentCreators = isTinaAdminEnabled ? [] : cms.plugins.getType("content-creator").all();
10626
- const toggleFullscreen = () => {
10627
- if (displayState === "fullscreen") {
10628
- setDisplayState("open");
10629
- } else {
10630
- setDisplayState("fullscreen");
10418
+ return syncStatus == "needs-sync" ? /* @__PURE__ */ React__default.createElement("div", { className: "h-full flex items-center justify-center p-6 bg-gradient-to-t from-gray-200 to-transparent" }, /* @__PURE__ */ React__default.createElement("div", { className: "rounded-lg border shadow-sm px-4 lg:px-6 py-3 lg:py-4 bg-gradient-to-r from-yellow-50 to-yellow-100 border-yellow-200 mx-auto mb-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex items-start sm:items-center gap-2" }, /* @__PURE__ */ React__default.createElement(
10419
+ BiError,
10420
+ {
10421
+ className: `w-7 h-auto flex-shrink-0 text-yellow-400 -mt-px`
10631
10422
  }
10632
- };
10633
- const toggleSidebarOpen = () => {
10634
- cms.dispatch({ type: "toggle-edit-state" });
10635
- };
10636
- const toggleMenu = () => {
10637
- setMenuIsOpen((menuIsOpen2) => !menuIsOpen2);
10638
- };
10639
- React.useEffect(() => {
10640
- const updateLayout = () => {
10641
- if (displayState === "fullscreen") {
10642
- return;
10643
- }
10644
- updateBodyDisplacement({
10645
- position,
10646
- displayState,
10647
- sidebarWidth,
10648
- resizingSidebar
10649
- });
10650
- };
10651
- updateLayout();
10652
- window.addEventListener("resize", updateLayout);
10653
- return () => {
10654
- window.removeEventListener("resize", updateLayout);
10655
- };
10656
- }, [displayState, position, sidebarWidth, resizingSidebar]);
10657
- const windowWidth = useWindowWidth();
10658
- const displayNav = renderNav && (sidebarWidth > navBreakpoint && windowWidth > navBreakpoint || displayState === "fullscreen" && windowWidth > navBreakpoint);
10659
- const renderMobileNav = renderNav && (sidebarWidth < navBreakpoint + 1 || windowWidth < navBreakpoint + 1);
10660
- return /* @__PURE__ */ React.createElement(
10661
- SidebarContext.Provider,
10423
+ ), /* @__PURE__ */ React__default.createElement(
10424
+ "div",
10662
10425
  {
10663
- value: {
10664
- sidebarWidth,
10665
- setSidebarWidth,
10666
- displayState,
10667
- setDisplayState,
10668
- position,
10669
- toggleFullscreen,
10670
- toggleSidebarOpen,
10671
- resizingSidebar,
10672
- setResizingSidebar,
10673
- menuIsOpen,
10674
- setMenuIsOpen,
10675
- toggleMenu,
10676
- setActiveView,
10677
- formIsPristine,
10678
- setFormIsPristine
10679
- }
10426
+ className: `flex-1 flex flex-col items-start gap-0.5 text-base text-yellow-700`
10680
10427
  },
10681
- /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SidebarWrapper, null, /* @__PURE__ */ React.createElement(EditButton, null), displayNav && /* @__PURE__ */ React.createElement(
10682
- Nav,
10683
- {
10684
- isLocalMode: (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode,
10685
- showCollections: isTinaAdminEnabled,
10686
- collectionsInfo,
10687
- screens: activeScreens,
10688
- cloudConfigs: allConfigs,
10689
- contentCreators,
10690
- sidebarWidth,
10691
- RenderNavSite: ({ view }) => /* @__PURE__ */ React.createElement(
10692
- SidebarSiteLink,
10693
- {
10694
- view,
10695
- onClick: () => {
10696
- setActiveView(view);
10697
- setMenuIsOpen(false);
10698
- }
10699
- }
10700
- ),
10701
- RenderNavCloud: ({ config }) => /* @__PURE__ */ React.createElement(SidebarCloudLink$1, { config }),
10702
- RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
10703
- SidebarCollectionLink,
10704
- {
10705
- onClick: () => {
10706
- setMenuIsOpen(false);
10707
- },
10708
- collection
10709
- }
10710
- ),
10711
- AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
10712
- SidebarCollectionLink,
10713
- {
10714
- onClick: () => {
10715
- setMenuIsOpen(false);
10716
- },
10717
- collection,
10718
- Icon: ImUsers
10719
- }
10720
- )
10721
- }
10722
- ), /* @__PURE__ */ React.createElement(SidebarBody, null, /* @__PURE__ */ React.createElement(
10723
- SidebarHeader,
10724
- {
10725
- displayNav,
10726
- renderNav,
10727
- isLocalMode: (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.isLocalMode,
10728
- branchingEnabled
10729
- }
10730
- ), /* @__PURE__ */ React.createElement(FormsView, { loadingPlaceholder: sidebar.loadingPlaceholder }), activeScreen && /* @__PURE__ */ React.createElement(
10731
- ScreenPluginModal,
10732
- {
10733
- screen: activeScreen,
10734
- close: () => setActiveView(null)
10735
- }
10736
- )), /* @__PURE__ */ React.createElement(ResizeHandle, null)), renderMobileNav && /* @__PURE__ */ React.createElement(Transition, { show: menuIsOpen, as: "div" }, /* @__PURE__ */ React.createElement(
10737
- TransitionChild,
10738
- {
10739
- enter: "transform transition-all ease-out duration-300",
10740
- enterFrom: "opacity-0 -translate-x-full",
10741
- enterTo: "opacity-100 translate-x-0",
10742
- leave: "transform transition-all ease-in duration-200",
10743
- leaveFrom: "opacity-100 translate-x-0",
10744
- leaveTo: "opacity-0 -translate-x-full"
10745
- },
10746
- /* @__PURE__ */ React.createElement("div", { className: "fixed left-0 top-0 z-overlay h-full transform" }, /* @__PURE__ */ React.createElement(
10747
- Nav,
10748
- {
10749
- isLocalMode: (_f = (_e = cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.isLocalMode,
10750
- className: "rounded-r-md",
10751
- showCollections: isTinaAdminEnabled,
10752
- collectionsInfo,
10753
- screens: activeScreens,
10754
- cloudConfigs: allConfigs,
10755
- contentCreators,
10756
- sidebarWidth,
10757
- RenderNavSite: ({ view }) => /* @__PURE__ */ React.createElement(
10758
- SidebarSiteLink,
10759
- {
10760
- view,
10761
- onClick: () => {
10762
- setActiveView(view);
10763
- setMenuIsOpen(false);
10764
- }
10765
- }
10766
- ),
10767
- RenderNavCloud: ({ config }) => /* @__PURE__ */ React.createElement(SidebarCloudLink$1, { config }),
10768
- RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
10769
- SidebarCollectionLink,
10770
- {
10771
- onClick: () => {
10772
- setMenuIsOpen(false);
10773
- },
10774
- collection
10775
- }
10776
- ),
10777
- AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
10778
- SidebarCollectionLink,
10779
- {
10780
- onClick: () => {
10781
- setMenuIsOpen(false);
10782
- },
10783
- collection,
10784
- Icon: ImUsers
10785
- }
10786
- )
10787
- },
10788
- /* @__PURE__ */ React.createElement("div", { className: "absolute top-8 right-0 transform translate-x-full overflow-hidden" }, /* @__PURE__ */ React.createElement(
10789
- Button$1,
10790
- {
10791
- rounded: "right",
10792
- variant: "secondary",
10793
- onClick: () => {
10794
- setMenuIsOpen(false);
10795
- },
10796
- className: "transition-opacity duration-150 ease-out"
10797
- },
10798
- /* @__PURE__ */ React.createElement(IoMdClose, { className: "h-5 w-auto text-blue-500" })
10799
- ))
10800
- ))
10801
- ), /* @__PURE__ */ React.createElement(
10802
- TransitionChild,
10428
+ "Media needs to be turned on for this project.",
10429
+ /* @__PURE__ */ React__default.createElement(
10430
+ "a",
10803
10431
  {
10804
- enter: "ease-out duration-300",
10805
- enterFrom: "opacity-0",
10806
- enterTo: "opacity-80",
10807
- entered: "opacity-80",
10808
- leave: "ease-in duration-200",
10809
- leaveFrom: "opacity-80",
10810
- leaveTo: "opacity-0"
10432
+ className: "transition-all duration-150 ease-out text-blue-500 hover:text-blue-400 hover:underline underline decoration-blue-200 hover:decoration-blue-400 font-medium flex items-center justify-start gap-1",
10433
+ target: "_blank",
10434
+ href: `${cms.api.tina.appDashboardLink}/media`
10811
10435
  },
10812
- /* @__PURE__ */ React.createElement(
10813
- "div",
10814
- {
10815
- onClick: () => {
10816
- setMenuIsOpen(false);
10817
- },
10818
- className: "fixed z-menu inset-0 bg-gradient-to-br from-gray-800 via-gray-900 to-black"
10819
- }
10820
- )
10821
- )))
10822
- );
10436
+ "Sync Your Media In TinaCloud.",
10437
+ /* @__PURE__ */ React__default.createElement(BiLinkExternal, { className: `w-5 h-auto flex-shrink-0` })
10438
+ )
10439
+ )))) : /* @__PURE__ */ React__default.createElement(SyncStatusContext.Provider, { value: { syncStatus } }, children);
10823
10440
  };
10824
- const updateBodyDisplacement = ({
10825
- position = "overlay",
10826
- displayState,
10827
- sidebarWidth,
10828
- resizingSidebar
10829
- }) => {
10830
- const body = document.getElementsByTagName("body")[0];
10831
- const windowWidth = window.innerWidth;
10832
- if (position === "displace") {
10833
- body.style.transition = resizingSidebar ? "" : displayState === "fullscreen" ? "padding 0ms 150ms" : displayState === "closed" ? "padding 0ms 0ms" : "padding 0ms 300ms";
10834
- if (displayState === "open") {
10835
- const bodyDisplacement = Math.min(
10836
- sidebarWidth,
10837
- windowWidth - minPreviewWidth
10838
- );
10839
- body.style.paddingLeft = `${bodyDisplacement}px`;
10840
- } else {
10841
- body.style.paddingLeft = "0";
10842
- }
10843
- } else {
10844
- body.style.transition = "";
10845
- body.style.paddingLeft = "0";
10441
+ const useSyncStatus$1 = () => {
10442
+ const context = useContext(SyncStatusContext);
10443
+ if (!context) {
10444
+ throw new Error("useSyncStatus must be used within a SyncStatusProvider");
10846
10445
  }
10446
+ return context;
10847
10447
  };
10848
- const SidebarHeader = ({
10849
- branchingEnabled,
10850
- renderNav,
10851
- displayNav,
10852
- isLocalMode
10853
- }) => {
10854
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
10855
- const { toggleFullscreen, displayState, setMenuIsOpen, toggleSidebarOpen } = React.useContext(SidebarContext);
10856
- const displayMenuButton = renderNav && !displayNav;
10857
- const cms = useCMS$1();
10858
- const previewFunction = (_f = (_e = (_d = (_c = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.schema) == null ? void 0 : _c.config) == null ? void 0 : _d.config) == null ? void 0 : _e.ui) == null ? void 0 : _f.previewUrl;
10859
- const branch = (_h = (_g = cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.branch;
10860
- const previewUrl = typeof previewFunction === "function" ? (_i = previewFunction({ branch })) == null ? void 0 : _i.url : null;
10861
- return /* @__PURE__ */ React.createElement("div", { className: "flex-grow-0 w-full overflow-visible z-20" }, isLocalMode && /* @__PURE__ */ React.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", { className: "mt-4 -mb-14 w-full flex gap-3 items-center justify-between pointer-events-none" }, displayMenuButton && /* @__PURE__ */ React.createElement(
10862
- Button$1,
10863
- {
10864
- rounded: "right",
10865
- variant: "white",
10866
- onClick: () => {
10867
- setMenuIsOpen(true);
10868
- },
10869
- className: "pointer-events-auto -ml-px"
10870
- },
10871
- /* @__PURE__ */ React.createElement(BiMenu, { className: "h-6 w-auto text-blue-500" })
10872
- ), /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex gap-3 items-center shrink min-w-0" }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React.createElement(BranchButton, null), branchingEnabled && !isLocalMode && previewUrl && /* @__PURE__ */ React.createElement(
10873
- "button",
10448
+ const EmptyMediaList = () => {
10449
+ const { syncStatus } = useSyncStatus$1();
10450
+ return /* @__PURE__ */ React__default.createElement("div", { className: `p-12 text-xl opacity-50 text-center` }, syncStatus == "synced" ? "Drag and drop assets here" : "Loading...");
10451
+ };
10452
+ const DocsLink = ({ title, message, docsLink, ...props }) => {
10453
+ return /* @__PURE__ */ React__default.createElement("div", { className: "h-3/4 text-center flex flex-col justify-center", ...props }, /* @__PURE__ */ React__default.createElement("h2", { className: "mb-3 text-xl text-gray-600" }, title), /* @__PURE__ */ React__default.createElement("div", { className: "mb-3 text-base text-gray-700" }, message), /* @__PURE__ */ React__default.createElement(
10454
+ "a",
10874
10455
  {
10875
- className: "pointer-events-auto flex min-w-0 shrink gap-1 items-center justify-between form-select text-sm h-10 px-4 shadow text-gray-500 hover:text-blue-500 bg-white hover:bg-gray-50 border border-gray-100 transition-color duration-150 ease-out rounded-full focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out text-[12px] leading-tight min-w-[5rem]",
10876
- onClick: () => {
10877
- window.open(previewUrl, "_blank");
10878
- }
10456
+ href: docsLink,
10457
+ target: "_blank",
10458
+ rel: "noreferrer noopener",
10459
+ className: "font-bold text-blue-500 hover:text-blue-600 hover:underline transition-all ease-out duration-150"
10879
10460
  },
10880
- /* @__PURE__ */ React.createElement(BiLinkExternal, { className: "flex-shrink-0 w-4 h-auto text-blue-500/70 mr-1" }),
10881
- /* @__PURE__ */ React.createElement("span", { className: "truncate max-w-full min-w-0 shrink" }, "Preview")
10882
- )), /* @__PURE__ */ React.createElement(
10461
+ "Learn More"
10462
+ ));
10463
+ };
10464
+ const ViewModeToggle = ({ viewMode, setViewMode }) => {
10465
+ const toggleClasses = {
10466
+ base: "relative whitespace-nowrap flex items-center justify-center flex-1 block font-medium text-base py-1 transition-all ease-out duration-150 border",
10467
+ active: "bg-white text-blue-500 shadow-inner border-gray-50 border-t-gray-100",
10468
+ inactive: "bg-gray-50 text-gray-400 shadow border-gray-100 border-t-white"
10469
+ };
10470
+ return /* @__PURE__ */ React__default.createElement(
10883
10471
  "div",
10884
10472
  {
10885
- className: "flex items-center pointer-events-auto transition-opacity duration-150 ease-in-out -mr-px"
10473
+ className: `grow-0 flex justify-between rounded-md border border-gray-100`
10886
10474
  },
10887
- /* @__PURE__ */ React.createElement(
10888
- Button$1,
10475
+ /* @__PURE__ */ React__default.createElement(
10476
+ "button",
10889
10477
  {
10890
- rounded: "left",
10891
- variant: "white",
10892
- onClick: toggleSidebarOpen,
10893
- "aria-label": "closes cms sidebar",
10894
- className: "-mr-px"
10478
+ className: `${toggleClasses.base} px-2.5 rounded-l-md ${viewMode === "grid" ? toggleClasses.active : toggleClasses.inactive}`,
10479
+ onClick: () => {
10480
+ setViewMode("grid");
10481
+ }
10895
10482
  },
10896
- /* @__PURE__ */ React.createElement(MdOutlineArrowBackIos, { className: "h-[18px] w-auto -mr-1 text-blue-500" })
10483
+ /* @__PURE__ */ React__default.createElement(BiGridAlt, { className: "w-6 h-full opacity-70" })
10897
10484
  ),
10898
- /* @__PURE__ */ React.createElement(Button$1, { rounded: "custom", variant: "white", onClick: toggleFullscreen }, displayState === "fullscreen" ? (
10899
- // BiCollapseAlt
10900
- /* @__PURE__ */ React.createElement(
10901
- "svg",
10902
- {
10903
- className: "h-5 w-auto -mx-1 text-blue-500",
10904
- stroke: "currentColor",
10905
- fill: "currentColor",
10906
- strokeWidth: "0",
10907
- viewBox: "0 0 24 24",
10908
- xmlns: "http://www.w3.org/2000/svg"
10909
- },
10910
- /* @__PURE__ */ React.createElement("path", { d: "M2 15h7v7h2v-9H2v2zM15 2h-2v9h9V9h-7V2z" })
10911
- )
10912
- ) : /* @__PURE__ */ React.createElement(BiExpandAlt, { className: "h-5 -mx-1 w-auto text-blue-500" }))
10913
- )));
10914
- };
10915
- const SidebarSiteLink = ({
10916
- view,
10917
- onClick
10918
- }) => {
10919
- return /* @__PURE__ */ React.createElement(
10920
- "button",
10921
- {
10922
- className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100",
10923
- value: view.name,
10924
- onClick
10925
- },
10926
- /* @__PURE__ */ React.createElement(view.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }),
10927
- " ",
10928
- view.name
10929
- );
10930
- };
10931
- const SidebarCloudLink$1 = ({ config }) => {
10932
- if (config.text) {
10933
- return /* @__PURE__ */ React.createElement("span", { className: "text-base tracking-wide text-gray-500 flex items-center opacity-90" }, config.text, " ", /* @__PURE__ */ React.createElement(
10934
- "a",
10485
+ /* @__PURE__ */ React__default.createElement(
10486
+ "button",
10935
10487
  {
10936
- target: "_blank",
10937
- className: "ml-1 text-blue-600 hover:opacity-60",
10938
- href: config.link.href
10488
+ className: `${toggleClasses.base} px-2 rounded-r-md ${viewMode === "list" ? toggleClasses.active : toggleClasses.inactive}`,
10489
+ onClick: () => {
10490
+ setViewMode("list");
10491
+ }
10939
10492
  },
10940
- config.link.text
10941
- ));
10942
- }
10943
- return /* @__PURE__ */ React.createElement("span", { className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100" }, /* @__PURE__ */ React.createElement(config.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }), /* @__PURE__ */ React.createElement("a", { target: "_blank", href: config.link.href }, config.link.text));
10944
- };
10945
- const SidebarCollectionLink = ({
10946
- Icon = ImFilesEmpty,
10947
- collection,
10948
- onClick
10949
- }) => {
10950
- const cms = useCMS$1();
10951
- const tinaPreview = cms.flags.get("tina-preview") || false;
10952
- return /* @__PURE__ */ React.createElement(
10953
- "a",
10954
- {
10955
- onClick,
10956
- href: `${tinaPreview ? `/${tinaPreview}/index.html#` : "/admin#"}/collections/${collection.name}/~`,
10957
- className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100"
10958
- },
10959
- /* @__PURE__ */ React.createElement(Icon, { className: "mr-2 h-6 opacity-80 w-auto" }),
10960
- " ",
10961
- collection.label ? collection.label : collection.name
10962
- );
10963
- };
10964
- const EditButton = ({}) => {
10965
- const { displayState, toggleSidebarOpen } = React.useContext(SidebarContext);
10966
- return /* @__PURE__ */ React.createElement(
10967
- Button$1,
10968
- {
10969
- rounded: "right",
10970
- variant: "primary",
10971
- size: "custom",
10972
- onClick: toggleSidebarOpen,
10973
- className: `z-chrome absolute top-6 right-0 translate-x-full text-sm h-10 pl-3 pr-4 transition-all duration-300 ${displayState !== "closed" ? "opacity-0 ease-in pointer-events-none" : "ease-out pointer-events-auto"}`,
10974
- "aria-label": "opens cms sidebar"
10975
- },
10976
- /* @__PURE__ */ React.createElement(BiPencil, { className: "h-6 w-auto" })
10493
+ /* @__PURE__ */ React__default.createElement(BiListUl, { className: "w-8 h-full opacity-70" })
10494
+ )
10977
10495
  );
10978
10496
  };
10979
- const SidebarWrapper = ({ children }) => {
10980
- const { displayState, sidebarWidth, resizingSidebar } = React.useContext(SidebarContext);
10981
- return /* @__PURE__ */ React.createElement(
10982
- "div",
10983
- {
10984
- className: `fixed top-0 left-0 h-dvh z-base ${displayState === "closed" ? "pointer-events-none" : ""}`
10985
- },
10986
- /* @__PURE__ */ React.createElement(
10987
- "div",
10497
+ const MediaManagerScreenPlugin = createScreen({
10498
+ name: "Media Manager",
10499
+ Component: MediaPicker,
10500
+ Icon: MdOutlinePhotoLibrary,
10501
+ layout: "fullscreen",
10502
+ props: {
10503
+ allowDelete: true
10504
+ }
10505
+ });
10506
+ function UpdatePassword(props) {
10507
+ const cms = useCMS$1();
10508
+ const client = cms.api.tina;
10509
+ const [password, setPassword] = useState("");
10510
+ const [confirmPassword, setConfirmPassword] = useState("");
10511
+ const [dirty, setDirty] = useState(false);
10512
+ const [result, setResult] = useState(null);
10513
+ const [formState, setFormState] = useState("idle");
10514
+ const [passwordChangeRequired, setPasswordChangeRequired] = useState(false);
10515
+ useEffect(() => {
10516
+ var _a;
10517
+ (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.getUser().then(
10518
+ (user) => setPasswordChangeRequired((user == null ? void 0 : user.passwordChangeRequired) ?? false)
10519
+ );
10520
+ }, []);
10521
+ let err = null;
10522
+ if (dirty && password !== confirmPassword) {
10523
+ err = "Passwords do not match";
10524
+ }
10525
+ if (dirty && !password) {
10526
+ err = "Please enter a password";
10527
+ }
10528
+ const updatePassword = async () => {
10529
+ var _a;
10530
+ setResult(null);
10531
+ setFormState("busy");
10532
+ const res = await cms.api.tina.request(
10533
+ `mutation($password: String!) { updatePassword(password: $password) }`,
10988
10534
  {
10989
- className: `relative h-dvh transform flex ${displayState !== "closed" ? "" : "-translate-x-full"} ${resizingSidebar ? "transition-none" : displayState === "closed" ? "transition-all duration-300 ease-in" : displayState === "fullscreen" ? "transition-all duration-150 ease-out" : "transition-all duration-300 ease-out"}`,
10990
- style: {
10991
- width: displayState === "fullscreen" ? "100vw" : `${sidebarWidth}px`,
10992
- maxWidth: displayState === "fullscreen" ? "100vw" : "calc(100vw - 8px)",
10993
- minWidth: "360px"
10535
+ variables: {
10536
+ password
10537
+ }
10538
+ }
10539
+ );
10540
+ if (!(res == null ? void 0 : res.updatePassword)) {
10541
+ setResult("Error updating password");
10542
+ } else {
10543
+ setDirty(false);
10544
+ setPassword("");
10545
+ setConfirmPassword("");
10546
+ setResult("Password updated");
10547
+ setPasswordChangeRequired(false);
10548
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
10549
+ (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.logout().then(async () => {
10550
+ if (typeof (client == null ? void 0 : client.onLogout) === "function") {
10551
+ await client.onLogout();
10552
+ await new Promise((resolve) => setTimeout(resolve, 500));
10994
10553
  }
10554
+ window.location.href = new URL(window.location.href).pathname;
10555
+ }).catch((e) => console.error(e));
10556
+ }
10557
+ setFormState("idle");
10558
+ };
10559
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex justify-center items-center h-full" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col space-y-8 p-6" }, passwordChangeRequired && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-red-500" }, "Your password has expired. Please update your password."), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "New Password"), /* @__PURE__ */ React__default.createElement(
10560
+ BaseTextField,
10561
+ {
10562
+ type: "password",
10563
+ name: "password",
10564
+ id: "password",
10565
+ placeholder: "Enter password",
10566
+ className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
10567
+ value: password,
10568
+ onKeyDown: () => {
10569
+ setDirty(true);
10570
+ setResult(null);
10995
10571
  },
10996
- children
10997
- )
10998
- );
10999
- };
11000
- const SidebarBody = ({ children }) => {
11001
- return /* @__PURE__ */ React.createElement(
11002
- "div",
10572
+ onChange: (e) => setPassword(e.target.value),
10573
+ required: true
10574
+ }
10575
+ )), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "Confirm New Password"), /* @__PURE__ */ React__default.createElement(
10576
+ BaseTextField,
11003
10577
  {
11004
- className: "relative left-0 w-full h-full flex flex-col items-stretch bg-white border-r border-gray-200 overflow-hidden"
11005
- },
11006
- children
11007
- );
11008
- };
11009
- const MarkdownFieldPlaceholder = {
11010
- __type: "field",
11011
- name: "markdown",
11012
- Component: createPlaceholder(
11013
- "Markdown"
11014
- )
11015
- };
11016
- const HtmlFieldPlaceholder = {
11017
- __type: "field",
11018
- name: "html",
11019
- Component: createPlaceholder(
11020
- "HTML"
11021
- )
11022
- };
11023
- function createPlaceholder(name, _pr) {
11024
- return (props) => {
11025
- return /* @__PURE__ */ React__default.createElement(
11026
- FieldMeta,
11027
- {
11028
- name: props.input.name,
11029
- label: `${name} Field not Registered`,
11030
- tinaForm: props.tinaForm
10578
+ type: "password",
10579
+ name: "confirmPassword",
10580
+ id: "confirmPassword",
10581
+ placeholder: "Confirm password",
10582
+ className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
10583
+ value: confirmPassword,
10584
+ onKeyDown: () => {
10585
+ setDirty(true);
10586
+ setResult(null);
11031
10587
  },
11032
- /* @__PURE__ */ React__default.createElement("p", { className: "whitespace-normal text-[15px] mt-2" }, "The ", name, " field is not registered. Some built-in field types are not bundled by default in an effort to control bundle size. Consult the Tina docs to learn how to use this field type."),
11033
- /* @__PURE__ */ React__default.createElement("p", { className: "whitespace-normal text-[15px] mt-2" }, /* @__PURE__ */ React__default.createElement(
11034
- "a",
11035
- {
11036
- className: "text-blue-500 underline",
11037
- href: "https://tina.io/docs/editing/markdown/#registering-the-field-plugins",
11038
- target: "_blank",
11039
- rel: "noreferrer noopener"
11040
- },
11041
- "Tina Docs: Registering Field Plugins"
11042
- ))
11043
- );
11044
- };
10588
+ onChange: (e) => setConfirmPassword(e.target.value),
10589
+ required: true
10590
+ }
10591
+ )), result && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-gray-500" }, result), err && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-red-500" }, err), /* @__PURE__ */ React__default.createElement(
10592
+ Button$1,
10593
+ {
10594
+ onClick: updatePassword,
10595
+ disabled: err,
10596
+ variant: "primary",
10597
+ busy: formState === "busy"
10598
+ },
10599
+ "Update"
10600
+ ))));
11045
10601
  }
11046
- function dirname(path) {
11047
- var _a, _b;
11048
- const pattern = new RegExp("(?<prevDir>.*)/");
11049
- return (_b = (_a = path.match(pattern)) == null ? void 0 : _a.groups) == null ? void 0 : _b.prevDir;
10602
+ const PasswordScreenPlugin = createScreen({
10603
+ name: "Change Password",
10604
+ Component: UpdatePassword,
10605
+ Icon: MdVpnKey,
10606
+ layout: "fullscreen",
10607
+ navCategory: "Account"
10608
+ });
10609
+ function createCloudConfig({
10610
+ ...options
10611
+ }) {
10612
+ return {
10613
+ __type: "cloud-config",
10614
+ Icon: MdOutlineCloud,
10615
+ ...options
10616
+ };
11050
10617
  }
11051
- const BreadcrumbButton = ({ className = "", ...props }) => /* @__PURE__ */ React__default.createElement(
11052
- "button",
10618
+ const SidebarLoadingPlaceholder = () => /* @__PURE__ */ React.createElement(
10619
+ "div",
11053
10620
  {
11054
- className: "capitalize transition-colors duration-150 border-0 bg-transparent hover:text-blue-500 " + className,
11055
- ...props
11056
- }
10621
+ className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
10622
+ style: {
10623
+ animationName: "fade-in",
10624
+ animationDelay: "300ms",
10625
+ animationTimingFunction: "ease-out",
10626
+ animationIterationCount: 1,
10627
+ animationFillMode: "both",
10628
+ animationDuration: "150ms"
10629
+ }
10630
+ },
10631
+ /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Please wait while TinaCMS", /* @__PURE__ */ React.createElement("br", null), "loads your content"),
10632
+ /* @__PURE__ */ React.createElement(LoadingDots, { color: "var(--tina-color-primary)" })
11057
10633
  );
11058
- function Breadcrumb$1({ directory = "", setDirectory }) {
11059
- directory = directory.replace(/^\/|\/$/g, "");
11060
- let prevDir = dirname(directory) || "";
11061
- if (prevDir === ".") {
11062
- prevDir = "";
10634
+ class SidebarState {
10635
+ constructor(events, options = {}) {
10636
+ var _a, _b;
10637
+ this.events = events;
10638
+ this._isOpen = false;
10639
+ this.position = "displace";
10640
+ this.renderNav = true;
10641
+ this.buttons = {
10642
+ save: "Save",
10643
+ reset: "Reset"
10644
+ };
10645
+ this.position = options.position || "displace";
10646
+ this.renderNav = options.renderNav || true;
10647
+ this.loadingPlaceholder = options.placeholder || SidebarLoadingPlaceholder;
10648
+ if ((_a = options.buttons) == null ? void 0 : _a.save) {
10649
+ this.buttons.save = options.buttons.save;
10650
+ }
10651
+ if ((_b = options.buttons) == null ? void 0 : _b.reset) {
10652
+ this.buttons.reset = options.buttons.reset;
10653
+ }
10654
+ }
10655
+ get isOpen() {
10656
+ return this._isOpen;
10657
+ }
10658
+ set isOpen(nextValue) {
10659
+ if (this._isOpen === nextValue) {
10660
+ return;
10661
+ }
10662
+ this._isOpen = nextValue;
10663
+ if (nextValue) {
10664
+ this.events.dispatch({ type: "sidebar:opened" });
10665
+ } else {
10666
+ this.events.dispatch({ type: "sidebar:closed" });
10667
+ }
10668
+ }
10669
+ subscribe(callback) {
10670
+ const unsub = this.events.subscribe("sidebar", callback);
10671
+ return () => unsub();
11063
10672
  }
11064
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex items-center text-[16px] text-gray-300" }, directory !== "" && /* @__PURE__ */ React__default.createElement(
11065
- IconButton,
11066
- {
11067
- variant: "ghost",
11068
- className: "mr-2",
11069
- onClick: () => setDirectory(prevDir)
11070
- },
11071
- /* @__PURE__ */ React__default.createElement(
11072
- LeftArrowIcon,
11073
- {
11074
- className: `w-7 h-auto fill-gray-300 hover:fill-gray-900 transition duration-150 ease-out`
11075
- }
11076
- )
11077
- ), /* @__PURE__ */ React__default.createElement(
11078
- BreadcrumbButton,
11079
- {
11080
- onClick: () => setDirectory(""),
11081
- className: directory === "" ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"
11082
- },
11083
- "Media"
11084
- ), directory && directory.split("/").map((part, index, parts) => {
11085
- const currentDir = parts.slice(0, index + 1).join("/");
11086
- return /* @__PURE__ */ React__default.createElement(
11087
- BreadcrumbButton,
11088
- {
11089
- className: "pl-1.5 " + (index + 1 === parts.length ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"),
11090
- key: currentDir,
11091
- onClick: () => {
11092
- setDirectory(currentDir);
11093
- }
11094
- },
11095
- part
11096
- );
11097
- }));
11098
10673
  }
11099
- const CopyField = ({ label, description, value }) => {
11100
- const [copied, setCopied] = React__default.useState(false);
11101
- const [fadeOut, setFadeOut] = React__default.useState(false);
11102
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, label && /* @__PURE__ */ React__default.createElement("label", { className: "w-full mb-1 block flex-1 text-sm font-bold leading-5 text-gray-700" }, label), /* @__PURE__ */ React__default.createElement(
11103
- "span",
10674
+ function ImFilesEmpty(props) {
10675
+ return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 16 16" }, "child": [{ "tag": "path", "attr": { "d": "M14.341 5.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.689 0.561 1.25 1.25 1.25h9.5c0.689 0 1.25-0.561 1.25-1.25v-7.75c0-0.224-0.068-0.615-0.659-1.421zM12.271 4.729c0.48 0.48 0.856 0.912 1.134 1.271h-2.406v-2.405c0.359 0.278 0.792 0.654 1.271 1.134v0zM14 14.75c0 0.136-0.114 0.25-0.25 0.25h-9.5c-0.136 0-0.25-0.114-0.25-0.25v-11.5c0-0.135 0.114-0.25 0.25-0.25 0 0 5.749-0 5.75 0v3.5c0 0.276 0.224 0.5 0.5 0.5h3.5v7.75z" }, "child": [] }, { "tag": "path", "attr": { "d": "M9.421 0.659c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.604 0.43 1.109 1 1.225v-12.725c0-0.135 0.115-0.25 0.25-0.25h7.607c-0.151-0.124-0.297-0.238-0.437-0.341z" }, "child": [] }] })(props);
10676
+ }
10677
+ function ImUsers(props) {
10678
+ return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 18 16" }, "child": [{ "tag": "path", "attr": { "d": "M12 12.041v-0.825c1.102-0.621 2-2.168 2-3.716 0-2.485 0-4.5-3-4.5s-3 2.015-3 4.5c0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h14c0-2.015-2.608-3.682-6-3.959z" }, "child": [] }, { "tag": "path", "attr": { "d": "M5.112 12.427c0.864-0.565 1.939-0.994 3.122-1.256-0.235-0.278-0.449-0.588-0.633-0.922-0.475-0.863-0.726-1.813-0.726-2.748 0-1.344 0-2.614 0.478-3.653 0.464-1.008 1.299-1.633 2.488-1.867-0.264-1.195-0.968-1.98-2.841-1.98-3 0-3 2.015-3 4.5 0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h4.359c0.227-0.202 0.478-0.393 0.753-0.573z" }, "child": [] }] })(props);
10679
+ }
10680
+ const LocalWarning = () => {
10681
+ return /* @__PURE__ */ React.createElement(
10682
+ "a",
11104
10683
  {
11105
- onClick: () => {
11106
- if (copied === true)
11107
- return;
11108
- setCopied(true);
11109
- setTimeout(() => {
11110
- setFadeOut(true);
11111
- }, 2500);
11112
- setTimeout(() => {
11113
- setCopied(false);
11114
- setFadeOut(false);
11115
- }, 3e3);
11116
- navigator.clipboard.writeText(value);
11117
- },
11118
- className: `shadow-inner text-base leading-5 whitespace-normal break-all px-3 py-2 text-gray-600 w-full bg-gray-50 border border-gray-200 transition-all ease-out duration-150 rounded-md relative overflow-hidden appearance-none flex items-center w-full cursor-pointer hover:bg-white hover:text-blue-500 ${copied ? `pointer-events-none` : ``}`
10684
+ className: "flex-grow-0 flex w-full text-xs items-center py-1 px-4 text-yellow-600 bg-gradient-to-r from-yellow-50 to-yellow-100 border-b border-gray-150 shadow-sm",
10685
+ href: "https://tina.io/docs/tina-cloud/",
10686
+ target: "_blank"
11119
10687
  },
11120
- /* @__PURE__ */ React__default.createElement(BiCopyAlt, { className: "relative text-blue-500 shrink-0 w-5 h-auto mr-1.5 -ml-0.5 z-20" }),
11121
- " ",
11122
- value,
10688
+ /* @__PURE__ */ React.createElement(AiFillWarning, { className: "w-5 h-auto inline-block mr-1 opacity-70 text-yellow-600" }),
11123
10689
  " ",
11124
- copied && /* @__PURE__ */ React__default.createElement(
11125
- "span",
11126
- {
11127
- className: `${fadeOut ? `opacity-0` : `opacity-100`} text-blue-500 transition-opacity duration-500 absolute right-0 w-full h-full px-3 py-2 bg-white bg-opacity-90 flex items-center justify-center text-center tracking-wide font-medium z-10`
11128
- },
11129
- /* @__PURE__ */ React__default.createElement("span", null, "Copied to clipboard!")
11130
- )
11131
- ), description && /* @__PURE__ */ React__default.createElement("p", { className: "mt-2 text-sm text-gray-500" }, description));
10690
+ "You are currently in",
10691
+ /* @__PURE__ */ React.createElement("strong", { className: "ml-1 font-bold text-yellow-700" }, "Local Mode")
10692
+ );
11132
10693
  };
11133
- function ListMediaItem({ item, onClick, active }) {
11134
- let FileIcon = BiFile;
11135
- if (item.type === "dir") {
11136
- FileIcon = BiFolder;
11137
- } else if (isVideo(item.src)) {
11138
- FileIcon = BiMovie;
11139
- }
11140
- const thumbnail = (item.thumbnails || {})["75x75"];
11141
- return /* @__PURE__ */ React__default.createElement(
11142
- "li",
11143
- {
11144
- className: `group relative flex shrink-0 items-center transition duration-150 ease-out cursor-pointer border-b border-gray-150 ${active ? "bg-gradient-to-r from-white to-gray-50/50 text-blue-500 hover:bg-gray-50" : "bg-white hover:bg-gray-50/50 hover:text-blue-500"}`,
11145
- onClick: () => {
11146
- if (!active) {
11147
- onClick(item);
11148
- } else {
11149
- onClick(false);
11150
- }
11151
- }
11152
- },
11153
- item.new && /* @__PURE__ */ React__default.createElement("span", { className: "absolute top-1.5 left-1.5 rounded-full shadow bg-green-100 border border-green-200 text-[10px] tracking-wide font-bold text-green-600 px-1.5 py-0.5 z-10" }, "NEW"),
11154
- /* @__PURE__ */ React__default.createElement("div", { className: "w-16 h-16 bg-gray-50 border-r border-gray-150 overflow-hidden flex justify-center flex-shrink-0" }, isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement(
11155
- "img",
11156
- {
11157
- className: "object-contain object-center w-full h-full origin-center transition-all duration-150 ease-out group-hover:scale-110",
11158
- src: thumbnail,
11159
- alt: item.filename
11160
- }
11161
- ) : /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-1/2 h-full fill-gray-300" })),
11162
- /* @__PURE__ */ React__default.createElement(
11163
- "span",
11164
- {
11165
- className: "text-base flex-grow w-full break-words truncate px-3 py-2"
11166
- },
11167
- item.filename
11168
- )
10694
+ const BillingWarning = () => {
10695
+ var _a;
10696
+ const cms = useCMS$1();
10697
+ const api = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina;
10698
+ const isCustomContentApi = (api == null ? void 0 : api.isCustomContentApi) || false;
10699
+ const [billingState, setBillingState] = React.useState(
10700
+ null
11169
10701
  );
11170
- }
11171
- function GridMediaItem({ item, active, onClick }) {
11172
- let FileIcon = BiFile;
11173
- if (item.type === "dir") {
11174
- FileIcon = BiFolder;
11175
- } else if (isVideo(item.src)) {
11176
- FileIcon = BiMovie;
10702
+ React.useEffect(() => {
10703
+ const fetchBillingState = async () => {
10704
+ if (typeof (api == null ? void 0 : api.getBillingState) !== "function")
10705
+ return;
10706
+ const billingRes = await (api == null ? void 0 : api.getBillingState());
10707
+ setBillingState(billingRes);
10708
+ };
10709
+ if (!isCustomContentApi)
10710
+ fetchBillingState();
10711
+ }, []);
10712
+ if (isCustomContentApi || !billingState || billingState.billingState === "current") {
10713
+ return /* @__PURE__ */ React.createElement(React.Fragment, null);
11177
10714
  }
11178
- const thumbnail = (item.thumbnails || {})["400x400"];
11179
- return /* @__PURE__ */ React__default.createElement(
11180
- "li",
10715
+ return /* @__PURE__ */ React.createElement("div", { className: "flex-grow-0 flex flex-wrap w-full text-xs items-center justify-between gap-1.5 py-1.5 px-3 text-red-700 bg-gradient-to-br from-white via-red-50 to-red-100 border-b border-red-200" }, /* @__PURE__ */ React.createElement("span", { className: "flex items-center gap-1 font-bold" }, /* @__PURE__ */ React.createElement(BiError, { className: "w-5 h-auto flex-shrink-0 flex-grow-0 inline-block opacity-70 text-red-600" }), /* @__PURE__ */ React.createElement("span", { className: "flex whitespace-nowrap" }, "There is an issue with your billing.")), /* @__PURE__ */ React.createElement(
10716
+ "a",
11181
10717
  {
11182
- className: `relative pb-[100%] h-0 block border border-gray-100 rounded-md overflow-hidden flex justify-center shrink-0 w-full transition duration-150 ease-out ${active ? "shadow-outline" : "shadow hover:shadow-md hover:scale-103 hover:border-gray-150"} ${item.type === "dir" ? "cursor-pointer" : ""}`
10718
+ className: "text-xs text-blue-600 underline decoration-blue-200 hover:text-blue-500 hover:decoration-blue-500 transition-all ease-out duration-150 flex items-center gap-1 self-end",
10719
+ href: `https://app.tina.io/projects/${billingState.clientId}/billing`,
10720
+ target: "_blank"
11183
10721
  },
11184
- item.new && /* @__PURE__ */ React__default.createElement("span", { className: "absolute top-1.5 left-1.5 rounded-full shadow bg-green-100 border border-green-200 text-[10px] tracking-wide font-bold text-green-600 px-1.5 py-0.5 z-10" }, "NEW"),
11185
- /* @__PURE__ */ React__default.createElement(
11186
- "button",
11187
- {
11188
- className: "absolute w-full h-full flex items-center justify-center bg-white",
11189
- onClick: () => {
11190
- if (!active) {
11191
- onClick(item);
11192
- } else {
11193
- onClick(false);
11194
- }
11195
- }
11196
- },
11197
- isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement(
11198
- "img",
11199
- {
11200
- className: "object-contain object-center w-full h-full",
11201
- src: thumbnail,
11202
- alt: item.filename
11203
- }
11204
- ) : /* @__PURE__ */ React__default.createElement("div", { className: "p-4 w-full flex flex-col gap-4 items-center justify-center" }, /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-[30%] h-auto fill-gray-300" }), /* @__PURE__ */ React__default.createElement("span", { className: "block text-base text-gray-600 w-full break-words truncate" }, item.filename))
11205
- )
10722
+ "Visit Billing Page",
10723
+ /* @__PURE__ */ React.createElement(BiRightArrowAlt, { className: "w-5 h-full opacity-70" })
10724
+ ));
10725
+ };
10726
+ function FiInfo(props) {
10727
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "circle", "attr": { "cx": "12", "cy": "12", "r": "10" }, "child": [] }, { "tag": "line", "attr": { "x1": "12", "y1": "16", "x2": "12", "y2": "12" }, "child": [] }, { "tag": "line", "attr": { "x1": "12", "y1": "8", "x2": "12.01", "y2": "8" }, "child": [] }] })(props);
10728
+ }
10729
+ function FiMoreVertical(props) {
10730
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "circle", "attr": { "cx": "12", "cy": "12", "r": "1" }, "child": [] }, { "tag": "circle", "attr": { "cx": "12", "cy": "5", "r": "1" }, "child": [] }, { "tag": "circle", "attr": { "cx": "12", "cy": "19", "r": "1" }, "child": [] }] })(props);
10731
+ }
10732
+ function VscNewFile(props) {
10733
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 16 16", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "fillRule": "evenodd", "clipRule": "evenodd", "d": "M9.5 1.1l3.4 3.5.1.4v2h-1V6H8V2H3v11h4v1H2.5l-.5-.5v-12l.5-.5h6.7l.3.1zM9 2v3h2.9L9 2zm4 14h-1v-3H9v-1h3V9h1v3h3v1h-3v3z" }, "child": [] }] })(props);
10734
+ }
10735
+ const FormModal = ({ plugin, close: close2 }) => {
10736
+ const cms = useCMS$1();
10737
+ const form = useMemo(
10738
+ () => new Form({
10739
+ id: "create-form-id",
10740
+ label: "create-form",
10741
+ fields: plugin.fields,
10742
+ actions: plugin.actions,
10743
+ buttons: plugin.buttons,
10744
+ initialValues: plugin.initialValues || {},
10745
+ reset: plugin.reset,
10746
+ onChange: plugin.onChange,
10747
+ onSubmit: async (values) => {
10748
+ await plugin.onSubmit(values, cms).then(() => {
10749
+ close2();
10750
+ });
10751
+ }
10752
+ }),
10753
+ [close2, cms, plugin]
11206
10754
  );
10755
+ return /* @__PURE__ */ React.createElement(Modal, { id: "content-creator-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement(PopupModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, plugin.name), /* @__PURE__ */ React.createElement(ModalBody, null, /* @__PURE__ */ React.createElement(FormBuilder, { form: { tinaForm: form } }))));
10756
+ };
10757
+ function HiOutlineClipboardList(props) {
10758
+ return GenIcon({ "tag": "svg", "attr": { "fill": "none", "viewBox": "0 0 24 24", "strokeWidth": "2", "stroke": "currentColor", "aria-hidden": "true" }, "child": [{ "tag": "path", "attr": { "strokeLinecap": "round", "strokeLinejoin": "round", "d": "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" }, "child": [] }] })(props);
11207
10759
  }
11208
- const DeleteModal$1 = ({
11209
- close: close2,
11210
- deleteFunc,
11211
- filename
11212
- }) => {
11213
- const [processing, setProcessing] = React__default.useState(false);
11214
- return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, "Delete ", filename), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", null, "Are you sure you want to delete ", /* @__PURE__ */ React__default.createElement("strong", null, filename), "?")), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement(Button$1, { style: { flexGrow: 2 }, disabled: processing, onClick: close2 }, "Cancel"), /* @__PURE__ */ React__default.createElement(
11215
- Button$1,
11216
- {
11217
- style: { flexGrow: 3 },
11218
- disabled: processing,
11219
- variant: "danger",
11220
- onClick: async () => {
11221
- setProcessing(true);
10760
+ const useGetEvents = (cms, cursor, existingEvents) => {
10761
+ const [events, setEvents] = useState([]);
10762
+ const [nextCursor, setNextCursor] = useState(void 0);
10763
+ const [loading, setLoading] = useState(true);
10764
+ const [error, setError] = useState(void 0);
10765
+ React.useEffect(() => {
10766
+ const fetchEvents = async () => {
10767
+ var _a, _b, _c, _d, _e;
10768
+ let doFetchEvents = false;
10769
+ if (!((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi)) {
10770
+ doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
10771
+ }
10772
+ if (doFetchEvents) {
11222
10773
  try {
11223
- await deleteFunc();
11224
- } catch (e) {
11225
- console.error(e);
11226
- } finally {
11227
- close2();
10774
+ const { events: nextEvents, cursor: nextCursor2 } = await cms.api.tina.fetchEvents(15, cursor);
10775
+ setEvents([...existingEvents, ...nextEvents]);
10776
+ setNextCursor(nextCursor2);
10777
+ } catch (error2) {
10778
+ cms.alerts.error(
10779
+ `[${error2.name}] GetEvents failed: ${error2.message}`,
10780
+ 30 * 1e3
10781
+ // 30 seconds
10782
+ );
10783
+ console.error(error2);
10784
+ setEvents(void 0);
10785
+ setError(error2);
11228
10786
  }
10787
+ setLoading(false);
11229
10788
  }
11230
- },
11231
- /* @__PURE__ */ React__default.createElement("span", { className: "mr-1" }, "Delete"),
11232
- processing && /* @__PURE__ */ React__default.createElement(LoadingDots, null)
11233
- ))));
10789
+ };
10790
+ setLoading(true);
10791
+ fetchEvents();
10792
+ }, [cms, cursor]);
10793
+ return { events, cursor: nextCursor, loading, error };
11234
10794
  };
11235
- const NewFolderModal = ({ onSubmit, close: close2 }) => {
11236
- const [folderName, setFolderName] = React__default.useState("");
11237
- return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, "New Folder"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", { className: "text-base text-gray-700 mb-2" }, "Please provide a name for your folder."), /* @__PURE__ */ React__default.createElement("p", { className: "text-sm text-gray-500 mb-4 italic" }, /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, "Note"), " – If you navigate away before uploading a media item, the folder will disappear."), /* @__PURE__ */ React__default.createElement(
11238
- Input,
11239
- {
11240
- value: folderName,
11241
- placeholder: "Folder Name",
11242
- required: true,
11243
- onChange: (e) => setFolderName(e.target.value)
11244
- }
11245
- )), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement(Button$1, { style: { flexGrow: 2 }, onClick: close2 }, "Cancel"), /* @__PURE__ */ React__default.createElement(
10795
+ function useSyncStatus(cms) {
10796
+ var _a, _b;
10797
+ const [syncStatus, setSyncStatus] = useState({ state: "loading", message: "Loading..." });
10798
+ React.useEffect(() => {
10799
+ const interval = setInterval(async () => {
10800
+ var _a2, _b2, _c, _d, _e;
10801
+ let doFetchEvents = false;
10802
+ if (!((_b2 = (_a2 = cms.api) == null ? void 0 : _a2.tina) == null ? void 0 : _b2.isCustomContentApi)) {
10803
+ doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
10804
+ }
10805
+ if (doFetchEvents) {
10806
+ const { events } = await cms.api.tina.fetchEvents();
10807
+ if (events.length === 0) {
10808
+ setSyncStatus({ state: "success", message: "No Events" });
10809
+ } else {
10810
+ if (events[0].isError) {
10811
+ setSyncStatus({
10812
+ state: "error",
10813
+ message: `Sync Failure ${events[0].message}`
10814
+ });
10815
+ } else {
10816
+ setSyncStatus({ state: "success", message: "Sync Successful" });
10817
+ }
10818
+ }
10819
+ } else {
10820
+ setSyncStatus({ state: "unauthorized", message: "Not Authenticated" });
10821
+ }
10822
+ }, 5e3);
10823
+ return () => clearInterval(interval);
10824
+ }, [(_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi]);
10825
+ return syncStatus;
10826
+ }
10827
+ const SyncErrorWidget = ({ cms }) => {
10828
+ const syncStatus = useSyncStatus(cms);
10829
+ if (syncStatus.state !== "error") {
10830
+ return null;
10831
+ }
10832
+ return /* @__PURE__ */ React.createElement(
10833
+ "div",
10834
+ {
10835
+ title: syncStatus.message,
10836
+ className: "flex-grow-0 flex text-xs items-center"
10837
+ },
10838
+ /* @__PURE__ */ React.createElement(MdSyncProblem, { className: "w-6 h-full ml-2 text-red-500 fill-current" })
10839
+ );
10840
+ };
10841
+ const EventsList = ({ cms }) => {
10842
+ const [cursor, setCursor] = React.useState(void 0);
10843
+ const [existingEvents, setExistingEvents] = React.useState([]);
10844
+ const {
10845
+ events,
10846
+ cursor: nextCursor,
10847
+ loading,
10848
+ error
10849
+ } = useGetEvents(cms, cursor, existingEvents);
10850
+ return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-4 w-full h-full grow-0" }, events.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "shrink grow-0 overflow-scroll w-full rounded-md shadow ring-1 ring-black ring-opacity-5" }, /* @__PURE__ */ React.createElement("table", { className: "w-full divide-y divide-gray-100" }, events.map((event, index) => {
10851
+ const date = new Date(event.timestamp).toDateString();
10852
+ const time = new Date(event.timestamp).toTimeString();
10853
+ return /* @__PURE__ */ React.createElement("tr", { className: index % 2 === 0 ? "" : "bg-gray-50" }, event.isError ? /* @__PURE__ */ React.createElement(
10854
+ "td",
10855
+ {
10856
+ key: `${event.id}_error_icon`,
10857
+ className: "py-3 pl-4 pr-0 w-0"
10858
+ },
10859
+ /* @__PURE__ */ React.createElement(BsExclamationOctagonFill, { className: "text-red-500 fill-current w-5 h-auto" })
10860
+ ) : /* @__PURE__ */ React.createElement(
10861
+ "td",
10862
+ {
10863
+ key: `${event.id}_ok_icon`,
10864
+ className: "py-3 pl-4 pr-0 w-0"
10865
+ },
10866
+ /* @__PURE__ */ React.createElement(BsCheckCircleFill, { className: "text-green-500 fill-current w-5 h-auto" })
10867
+ ), /* @__PURE__ */ React.createElement(
10868
+ "td",
10869
+ {
10870
+ key: `${event.id}_msg`,
10871
+ className: "whitespace-nowrap p-3 text-base text-gray-500"
10872
+ },
10873
+ event.message,
10874
+ event.isError && /* @__PURE__ */ React.createElement("div", { className: "w-full text-gray-300 text-xs mt-0.5" }, event.id)
10875
+ ), /* @__PURE__ */ React.createElement(
10876
+ "td",
10877
+ {
10878
+ key: `${event.id}_ts`,
10879
+ className: "whitespace-nowrap py-3 pl-3 pr-4 text-sm text-gray-500"
10880
+ },
10881
+ date,
10882
+ /* @__PURE__ */ React.createElement("span", { className: "w-full block text-gray-300 text-xs mt-0.5" }, time)
10883
+ ));
10884
+ }).flat())), loading && /* @__PURE__ */ React.createElement("div", { className: "text-sm text-gray-400 text-center" }, "Loading..."), error && /* @__PURE__ */ React.createElement("div", null, "Error: ", error.message), /* @__PURE__ */ React.createElement("div", { className: "text-center flex-1" }, /* @__PURE__ */ React.createElement(
11246
10885
  Button$1,
11247
10886
  {
11248
- disabled: !folderName,
11249
- style: { flexGrow: 3 },
11250
- variant: "primary",
11251
10887
  onClick: () => {
11252
- if (!folderName)
11253
- return;
11254
- onSubmit(folderName);
11255
- close2();
10888
+ setExistingEvents(events);
10889
+ setCursor(nextCursor);
11256
10890
  }
11257
10891
  },
11258
- "Create New Folder"
11259
- ))));
11260
- };
11261
- const { useDropzone } = dropzone;
11262
- const join = function(...parts) {
11263
- const [first, last, slash] = [0, parts.length - 1, "/"];
11264
- const matchLeadingSlash = new RegExp("^" + slash);
11265
- const matchTrailingSlash = new RegExp(slash + "$");
11266
- parts = parts.map(function(part, index) {
11267
- if (index === first && part === "file://")
11268
- return part;
11269
- if (index > first)
11270
- part = part.replace(matchLeadingSlash, "");
11271
- if (index < last)
11272
- part = part.replace(matchTrailingSlash, "");
11273
- return part;
11274
- });
11275
- return parts.join(slash);
10892
+ "Load More Events"
10893
+ )));
11276
10894
  };
11277
- function MediaManager2() {
11278
- const cms = useCMS();
11279
- const [request, setRequest] = useState();
11280
- useEffect(() => {
11281
- return cms.events.subscribe("media:open", ({ type, ...request2 }) => {
11282
- setRequest(request2);
11283
- });
11284
- }, []);
11285
- if (!request)
10895
+ const SyncStatusModal = ({ closeEventsModal, cms }) => /* @__PURE__ */ React.createElement(Modal, null, /* @__PURE__ */ React.createElement(FullscreenModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: closeEventsModal }, "Event Log"), /* @__PURE__ */ React.createElement(ModalBody, { className: "flex h-full flex-col", padded: true }, /* @__PURE__ */ React.createElement(EventsList, { cms }))));
10896
+ const SyncStatus = ({ cms, setEventsOpen }) => {
10897
+ var _a, _b;
10898
+ const syncStatus = useSyncStatus(cms);
10899
+ function openEventsModal() {
10900
+ setEventsOpen(true);
10901
+ }
10902
+ if ((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi) {
11286
10903
  return null;
11287
- const close2 = () => setRequest(void 0);
11288
- return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(FullscreenModal, null, /* @__PURE__ */ React__default.createElement("div", { className: "w-full bg-gray-50 flex items-center justify-between px-5 pt-3 m-0" }, /* @__PURE__ */ React__default.createElement("h2", { className: "text-gray-500 font-sans font-medium text-base leading-none m-0 block truncate" }, "Media Manager"), /* @__PURE__ */ React__default.createElement(
11289
- "div",
10904
+ }
10905
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
10906
+ "button",
11290
10907
  {
11291
- onClick: close2,
11292
- className: "flex items-center fill-gray-400 cursor-pointer transition-colors duration-100 ease-out hover:fill-gray-700"
10908
+ className: `text-lg px-4 py-2 first:pt-3 last:pb-3 tracking-wide whitespace-nowrap flex items-center opacity-80 text-gray-600 hover:text-blue-400 hover:bg-gray-50 hover:opacity-100`,
10909
+ onClick: openEventsModal
11293
10910
  },
11294
- /* @__PURE__ */ React__default.createElement(CloseIcon, { className: "w-6 h-auto" })
11295
- )), /* @__PURE__ */ React__default.createElement(ModalBody, { className: "flex h-full flex-col" }, /* @__PURE__ */ React__default.createElement(MediaPicker, { ...request, close: close2 }))));
11296
- }
11297
- const defaultListError = new MediaListError({
11298
- title: "Error fetching media",
11299
- message: "Something went wrong while requesting the resource.",
11300
- docsLink: "https://tina.io/docs/media/#media-store"
11301
- });
11302
- function MediaPicker({
11303
- allowDelete,
11304
- onSelect,
11305
- close: close2,
10911
+ syncStatus.state !== "error" ? /* @__PURE__ */ React.createElement(HiOutlineClipboardList, { className: "w-6 h-auto mr-2 text-blue-400" }) : /* @__PURE__ */ React.createElement(MdSyncProblem, { className: "w-6 h-auto mr-2 text-red-400" }),
10912
+ " ",
10913
+ "Event Log"
10914
+ ));
10915
+ };
10916
+ const version = "2.7.7";
10917
+ const Nav = ({
10918
+ isLocalMode,
10919
+ className = "",
10920
+ children,
10921
+ showCollections,
10922
+ collectionsInfo,
10923
+ screens,
10924
+ cloudConfigs,
10925
+ contentCreators,
10926
+ sidebarWidth,
10927
+ RenderNavSite,
10928
+ RenderNavCloud,
10929
+ RenderNavCollection,
10930
+ AuthRenderNavCollection,
11306
10931
  ...props
11307
- }) {
11308
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
11309
- const cms = useCMS();
11310
- const [listState, setListState] = useState(() => {
11311
- if (cms.media.isConfigured)
11312
- return "loading";
11313
- return "not-configured";
11314
- });
11315
- const [deleteModalOpen, setDeleteModalOpen] = React__default.useState(false);
11316
- const [newFolderModalOpen, setNewFolderModalOpen] = React__default.useState(false);
11317
- const [listError, setListError] = useState(defaultListError);
11318
- const [directory, setDirectory] = useState(
11319
- props.directory
11320
- );
11321
- const [list, setList] = useState({
11322
- items: [],
11323
- nextOffset: void 0
11324
- });
11325
- const resetList = () => setList({
11326
- items: [],
11327
- nextOffset: void 0
11328
- });
11329
- const [viewMode, setViewMode] = useState("grid");
11330
- const [activeItem, setActiveItem] = useState(false);
11331
- const closePreview = () => setActiveItem(false);
11332
- const [refreshing, setRefreshing] = useState(false);
11333
- const [loadFolders, setLoadFolders] = useState(true);
11334
- const [offsetHistory, setOffsetHistory] = useState([]);
11335
- const offset2 = offsetHistory[offsetHistory.length - 1];
11336
- const resetOffset = () => setOffsetHistory([]);
11337
- async function loadMedia(loadFolders2 = true) {
11338
- setListState("loading");
11339
- try {
11340
- const _list = await cms.media.list({
11341
- offset: offset2,
11342
- limit: cms.media.pageSize,
11343
- directory,
11344
- thumbnailSizes: [
11345
- { w: 75, h: 75 },
11346
- { w: 400, h: 400 },
11347
- { w: 1e3, h: 1e3 }
11348
- ],
11349
- filesOnly: !loadFolders2
11350
- });
11351
- setList({
11352
- items: [...list.items, ..._list.items],
11353
- nextOffset: _list.nextOffset
11354
- });
11355
- setListState("loaded");
11356
- } catch (e) {
11357
- console.error(e);
11358
- if (e.ERR_TYPE === "MediaListError") {
11359
- setListError(e);
10932
+ }) => {
10933
+ const cms = useCMS$1();
10934
+ const [eventsOpen, setEventsOpen] = React.useState(false);
10935
+ const { contentCollections, authCollection } = collectionsInfo.collections.reduce(
10936
+ (acc, collection) => {
10937
+ if (collection.isAuthCollection) {
10938
+ acc.authCollection = collection;
11360
10939
  } else {
11361
- setListError(defaultListError);
11362
- }
11363
- setListState("error");
11364
- }
11365
- }
11366
- useEffect(() => {
11367
- if (!refreshing)
11368
- return;
11369
- loadMedia();
11370
- setRefreshing(false);
11371
- }, [refreshing]);
11372
- useEffect(() => {
11373
- if (!cms.media.isConfigured)
11374
- return;
11375
- if (refreshing)
11376
- return;
11377
- loadMedia(loadFolders);
11378
- if (loadFolders)
11379
- setLoadFolders(false);
11380
- return cms.events.subscribe(
11381
- ["media:delete:success", "media:pageSize"],
11382
- () => {
11383
- setRefreshing(true);
11384
- resetOffset();
11385
- resetList();
10940
+ acc.contentCollections.push(collection);
11386
10941
  }
11387
- );
11388
- }, [offset2, directory, cms.media.isConfigured]);
11389
- const onClickMediaItem = (item) => {
11390
- if (!item) {
11391
- setActiveItem(false);
11392
- } else if (item.type === "dir") {
11393
- setDirectory(
11394
- item.directory === "." || item.directory === "" ? item.filename : join(item.directory, item.filename)
11395
- );
11396
- setLoadFolders(true);
11397
- resetOffset();
11398
- resetList();
11399
- setActiveItem(false);
11400
- } else {
11401
- setActiveItem(item);
10942
+ return acc;
10943
+ },
10944
+ {
10945
+ contentCollections: []
11402
10946
  }
11403
- };
11404
- let deleteMediaItem;
11405
- if (allowDelete) {
11406
- deleteMediaItem = async (item) => {
11407
- await cms.media.delete(item);
11408
- };
11409
- }
11410
- let selectMediaItem;
11411
- if (onSelect) {
11412
- selectMediaItem = (item) => {
11413
- onSelect(item);
11414
- if (close2)
11415
- close2();
11416
- };
10947
+ );
10948
+ function closeEventsModal() {
10949
+ setEventsOpen(false);
11417
10950
  }
11418
- const [uploading, setUploading] = useState(false);
11419
- const accept = Array.isArray(
11420
- (_c = (_b = (_a = cms.api.tina.schema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.media) == null ? void 0 : _c.accept
11421
- ) ? (_f = (_e = (_d = cms.api.tina.schema.schema) == null ? void 0 : _d.config) == null ? void 0 : _e.media) == null ? void 0 : _f.accept.join(",") : (_i = (_h = (_g = cms.api.tina.schema.schema) == null ? void 0 : _g.config) == null ? void 0 : _h.media) == null ? void 0 : _i.accept;
11422
- const { getRootProps, getInputProps, isDragActive } = useDropzone({
11423
- accept: dropzoneAcceptFromString(
11424
- accept || cms.media.accept || DEFAULT_MEDIA_UPLOAD_TYPES
11425
- ),
11426
- maxSize: cms.media.maxSize,
11427
- multiple: true,
11428
- onDrop: async (files, fileRejections) => {
11429
- try {
11430
- setUploading(true);
11431
- const mediaItems = await cms.media.persist(
11432
- files.map((file) => {
11433
- return {
11434
- directory: directory || "/",
11435
- file
11436
- };
11437
- })
11438
- );
11439
- const errorCodes = {
11440
- "file-invalid-type": "Invalid file type",
11441
- "file-too-large": "File too large",
11442
- "file-too-small": "File too small",
11443
- "too-many-files": "Too many files"
11444
- };
11445
- const printError = (error) => {
11446
- const message = errorCodes[error.code];
11447
- if (message) {
11448
- return message;
11449
- }
11450
- console.error(error);
11451
- return "Unknown error";
11452
- };
11453
- if (fileRejections.length > 0) {
11454
- const messages = [];
11455
- fileRejections.map((fileRejection) => {
11456
- messages.push(
11457
- `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
11458
- );
11459
- });
11460
- cms.alerts.error(() => {
11461
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React__default.createElement("br", null), messages.join(". "), ".");
11462
- });
10951
+ const WrappedSyncStatus = React.forwardRef(
10952
+ (props2, ref) => /* @__PURE__ */ React.createElement(SyncStatus, { ...props2 })
10953
+ );
10954
+ const screenCategories = screens.reduce(
10955
+ (acc, screen) => {
10956
+ const category = screen.navCategory || "Site";
10957
+ acc[category] = acc[category] || [];
10958
+ acc[category].push(screen);
10959
+ return acc;
10960
+ },
10961
+ { Site: [] }
10962
+ );
10963
+ return /* @__PURE__ */ React.createElement(
10964
+ "div",
10965
+ {
10966
+ className: `relative z-30 flex flex-col bg-white border-r border-gray-200 w-96 h-full ${className}`,
10967
+ style: { maxWidth: `${sidebarWidth}px` },
10968
+ ...props
10969
+ },
10970
+ /* @__PURE__ */ React.createElement("div", { className: "border-b border-gray-200" }, /* @__PURE__ */ React.createElement(Menu, { as: "div", className: "relative block" }, ({ open: open2 }) => /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
10971
+ MenuButton,
10972
+ {
10973
+ className: `group w-full px-6 py-3 gap-2 flex justify-between items-center transition-colors duration-150 ease-out ${open2 ? "bg-gray-50" : "bg-transparent"}`
10974
+ },
10975
+ /* @__PURE__ */ React.createElement("span", { className: "text-left inline-flex items-center text-xl tracking-wide text-gray-800 flex-1 gap-1 opacity-80 group-hover:opacity-100 transition-opacity duration-150 ease-out" }, /* @__PURE__ */ React.createElement(
10976
+ "svg",
10977
+ {
10978
+ viewBox: "0 0 32 32",
10979
+ fill: "#EC4815",
10980
+ xmlns: "http://www.w3.org/2000/svg",
10981
+ className: "w-10 h-auto -ml-1"
10982
+ },
10983
+ /* @__PURE__ */ React.createElement("path", { d: "M18.6466 14.5553C19.9018 13.5141 20.458 7.36086 21.0014 5.14903C21.5447 2.9372 23.7919 3.04938 23.7919 3.04938C23.7919 3.04938 23.2085 4.06764 23.4464 4.82751C23.6844 5.58738 25.3145 6.26662 25.3145 6.26662L24.9629 7.19622C24.9629 7.19622 24.2288 7.10204 23.7919 7.9785C23.355 8.85496 24.3392 17.4442 24.3392 17.4442C24.3392 17.4442 21.4469 22.7275 21.4469 24.9206C21.4469 27.1136 22.4819 28.9515 22.4819 28.9515H21.0296C21.0296 28.9515 18.899 26.4086 18.462 25.1378C18.0251 23.8669 18.1998 22.596 18.1998 22.596C18.1998 22.596 15.8839 22.4646 13.8303 22.596C11.7767 22.7275 10.4072 24.498 10.16 25.4884C9.91287 26.4787 9.81048 28.9515 9.81048 28.9515H8.66211C7.96315 26.7882 7.40803 26.0129 7.70918 24.9206C8.54334 21.8949 8.37949 20.1788 8.18635 19.4145C7.99321 18.6501 6.68552 17.983 6.68552 17.983C7.32609 16.6741 7.97996 16.0452 10.7926 15.9796C13.6052 15.914 17.3915 15.5965 18.6466 14.5553Z" }),
10984
+ /* @__PURE__ */ React.createElement("path", { d: "M11.1268 24.7939C11.1268 24.7939 11.4236 27.5481 13.0001 28.9516H14.3511C13.0001 27.4166 12.8527 23.4155 12.8527 23.4155C12.1656 23.6399 11.3045 24.3846 11.1268 24.7939Z" })
10985
+ ), /* @__PURE__ */ React.createElement("span", null, "Tina")),
10986
+ /* @__PURE__ */ React.createElement(SyncErrorWidget, { cms }),
10987
+ /* @__PURE__ */ React.createElement(
10988
+ FiMoreVertical,
10989
+ {
10990
+ className: `flex-0 w-6 h-full inline-block group-hover:opacity-80 transition-all duration-300 ease-in-out transform ${open2 ? "opacity-100 text-blue-400" : "text-gray-400 opacity-50 hover:opacity-70"}`
11463
10991
  }
11464
- if (mediaItems.length !== 0) {
11465
- setActiveItem(mediaItems[0]);
11466
- setList((mediaList) => {
11467
- return {
11468
- items: [
11469
- // all the newly added items are new
11470
- ...mediaItems.map((x) => ({ ...x, new: true })),
11471
- ...mediaList.items
11472
- ],
11473
- nextOffset: mediaList.nextOffset
11474
- };
11475
- });
10992
+ )
10993
+ ), /* @__PURE__ */ React.createElement("div", { className: "transform translate-y-full absolute bottom-3 right-5 z-50" }, /* @__PURE__ */ React.createElement(
10994
+ Transition,
10995
+ {
10996
+ enter: "transition duration-150 ease-out",
10997
+ enterFrom: "transform opacity-0 -translate-y-2",
10998
+ enterTo: "transform opacity-100 translate-y-0",
10999
+ leave: "transition duration-75 ease-in",
11000
+ leaveFrom: "transform opacity-100 translate-y-0",
11001
+ leaveTo: "transform opacity-0 -translate-y-2"
11002
+ },
11003
+ /* @__PURE__ */ React.createElement(MenuItems, { className: "bg-white border border-gray-150 rounded-lg shadow-lg flex flex-col items-stretch overflow-hidden" }, /* @__PURE__ */ React.createElement(MenuItem, null, /* @__PURE__ */ React.createElement(
11004
+ "button",
11005
+ {
11006
+ className: `text-lg px-4 py-2 first:pt-3 last:pb-3 tracking-wide whitespace-nowrap flex items-center opacity-80 text-gray-600 hover:text-blue-400 hover:bg-gray-50 hover:opacity-100`,
11007
+ onClick: async () => {
11008
+ var _a, _b, _c, _d, _e, _f, _g, _h;
11009
+ updateBodyDisplacement({
11010
+ displayState: "closed",
11011
+ sidebarWidth: null,
11012
+ resizingSidebar: false
11013
+ });
11014
+ try {
11015
+ if ((_c = (_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.authProvider) == null ? void 0 : _c.logout) {
11016
+ await ((_d = cms.api.tina) == null ? void 0 : _d.authProvider.logout());
11017
+ if ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.onLogout) {
11018
+ await ((_h = (_g = cms == null ? void 0 : cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.onLogout());
11019
+ await new Promise(
11020
+ (resolve) => setTimeout(resolve, 500)
11021
+ );
11022
+ }
11023
+ window.location.href = new URL(
11024
+ window.location.href
11025
+ ).pathname;
11026
+ }
11027
+ } catch (e) {
11028
+ cms.alerts.error(`Error logging out: ${e}`);
11029
+ console.error("Unexpected error calling logout");
11030
+ console.error(e);
11031
+ }
11032
+ }
11033
+ },
11034
+ /* @__PURE__ */ React.createElement(BiExit, { className: "w-6 h-auto mr-2 text-blue-400" }),
11035
+ " Log Out"
11036
+ )), /* @__PURE__ */ React.createElement(MenuItem, null, /* @__PURE__ */ React.createElement(
11037
+ WrappedSyncStatus,
11038
+ {
11039
+ cms,
11040
+ setEventsOpen
11476
11041
  }
11477
- } catch {
11478
- }
11479
- setUploading(false);
11480
- }
11481
- });
11482
- const { onClick, ...rootProps } = getRootProps();
11483
- function disableScrollBody() {
11484
- const body = document == null ? void 0 : document.body;
11485
- body.style.overflow = "hidden";
11486
- return () => {
11487
- body.style.overflow = "auto";
11488
- };
11489
- }
11490
- useEffect(disableScrollBody, []);
11491
- const loaderRef = useRef(null);
11492
- useEffect(() => {
11493
- const observer = new IntersectionObserver((entries) => {
11494
- const target = entries[0];
11495
- if (target.isIntersecting && list.nextOffset) {
11496
- setOffsetHistory((offsetHistory2) => [
11497
- ...offsetHistory2,
11498
- list.nextOffset
11499
- ]);
11500
- }
11501
- });
11502
- if (loaderRef.current) {
11503
- observer.observe(loaderRef.current);
11504
- }
11505
- return () => {
11506
- if (loaderRef.current) {
11507
- observer.unobserve(loaderRef.current);
11042
+ )))
11043
+ ))))),
11044
+ eventsOpen && /* @__PURE__ */ React.createElement(SyncStatusModal, { cms, closeEventsModal }),
11045
+ children,
11046
+ /* @__PURE__ */ React.createElement("div", { className: "flex flex-col px-6 flex-1 overflow-auto" }, showCollections && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "flex space-x-1 justify-items-start uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, /* @__PURE__ */ React.createElement("span", null, "Collections"), isLocalMode && /* @__PURE__ */ React.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React.createElement(
11047
+ "a",
11048
+ {
11049
+ href: "https://tina.io/docs/schema/#defining-collections",
11050
+ target: "_blank"
11051
+ },
11052
+ /* @__PURE__ */ React.createElement(FiInfo, null)
11053
+ ))), /* @__PURE__ */ React.createElement(
11054
+ CollectionsList,
11055
+ {
11056
+ RenderNavCollection,
11057
+ collections: contentCollections
11508
11058
  }
11509
- };
11510
- }, [list.nextOffset, loaderRef.current]);
11511
- if (listState === "loading" && !((_j = list == null ? void 0 : list.items) == null ? void 0 : _j.length) || uploading) {
11512
- return /* @__PURE__ */ React__default.createElement(LoadingMediaList, null);
11513
- }
11514
- if (listState === "not-configured") {
11515
- return /* @__PURE__ */ React__default.createElement(
11516
- DocsLink,
11059
+ )), (screenCategories.Site.length > 0 || contentCreators.length) > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Site"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screenCategories.Site.map((view) => {
11060
+ return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
11061
+ }), contentCreators.map((plugin, idx) => {
11062
+ return /* @__PURE__ */ React.createElement(CreateContentNavItem, { key: `plugin-${idx}`, plugin });
11063
+ }), authCollection && /* @__PURE__ */ React.createElement(
11064
+ CollectionsList,
11517
11065
  {
11518
- title: "No Media Store Configured",
11519
- message: "To use the media manager, you need to configure a Media Store.",
11520
- docsLink: "https://tina.io/docs/reference/media/overview/"
11066
+ RenderNavCollection: AuthRenderNavCollection,
11067
+ collections: [authCollection]
11521
11068
  }
11522
- );
11069
+ ))), Object.entries(screenCategories).map(([category, screens2]) => {
11070
+ if (category !== "Site") {
11071
+ return /* @__PURE__ */ React.createElement("div", { key: category }, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, category), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screens2.map((view) => {
11072
+ return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
11073
+ })));
11074
+ }
11075
+ }), !!(cloudConfigs == null ? void 0 : cloudConfigs.length) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Cloud"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, cloudConfigs.map((config) => {
11076
+ return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${config.name}` }, /* @__PURE__ */ React.createElement(RenderNavCloud, { config }));
11077
+ }))), /* @__PURE__ */ React.createElement("div", { className: "grow" }), /* @__PURE__ */ React.createElement("span", { className: "font-sans font-light text-xs mb-3 mt-8 text-gray-500" }, "v", version))
11078
+ );
11079
+ };
11080
+ const CollectionsList = ({
11081
+ collections,
11082
+ RenderNavCollection
11083
+ }) => {
11084
+ if (collections.length === 0) {
11085
+ return /* @__PURE__ */ React.createElement("div", null, "No collections found");
11523
11086
  }
11524
- if (listState === "error") {
11525
- const { title, message, docsLink } = listError;
11526
- return /* @__PURE__ */ React__default.createElement(DocsLink, { title, message, docsLink });
11087
+ return /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, collections.map((collection) => {
11088
+ return /* @__PURE__ */ React.createElement("li", { key: `nav-collection-${collection.name}` }, /* @__PURE__ */ React.createElement(RenderNavCollection, { collection }));
11089
+ }));
11090
+ };
11091
+ const CreateContentNavItem = ({ plugin }) => {
11092
+ const [open2, setOpen] = React.useState(false);
11093
+ return /* @__PURE__ */ React.createElement("li", { key: plugin.name }, /* @__PURE__ */ React.createElement(
11094
+ "button",
11095
+ {
11096
+ className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100",
11097
+ onClick: () => {
11098
+ setOpen(true);
11099
+ }
11100
+ },
11101
+ /* @__PURE__ */ React.createElement(VscNewFile, { className: "mr-3 h-6 opacity-80 w-auto" }),
11102
+ " ",
11103
+ plugin.name
11104
+ ), open2 && /* @__PURE__ */ React.createElement(FormModal, { plugin, close: () => setOpen(false) }));
11105
+ };
11106
+ const ResizeHandle = () => {
11107
+ const {
11108
+ resizingSidebar,
11109
+ setResizingSidebar,
11110
+ fullscreen,
11111
+ setSidebarWidth,
11112
+ displayState
11113
+ } = React.useContext(SidebarContext);
11114
+ React.useEffect(() => {
11115
+ const handleMouseUp = () => setResizingSidebar(false);
11116
+ window.addEventListener("mouseup", handleMouseUp);
11117
+ return () => {
11118
+ window.removeEventListener("mouseup", handleMouseUp);
11119
+ };
11120
+ }, []);
11121
+ React.useEffect(() => {
11122
+ const handleMouseMove = (e) => {
11123
+ setSidebarWidth((sidebarWidth) => {
11124
+ const newWidth = sidebarWidth + e.movementX;
11125
+ const maxWidth = window.innerWidth - 8;
11126
+ if (newWidth < minSidebarWidth) {
11127
+ return minSidebarWidth;
11128
+ } else if (newWidth > maxWidth) {
11129
+ return maxWidth;
11130
+ } else {
11131
+ return newWidth;
11132
+ }
11133
+ });
11134
+ };
11135
+ if (resizingSidebar) {
11136
+ window.addEventListener("mousemove", handleMouseMove);
11137
+ document.body.classList.add("select-none");
11138
+ }
11139
+ return () => {
11140
+ window.removeEventListener("mousemove", handleMouseMove);
11141
+ document.body.classList.remove("select-none");
11142
+ };
11143
+ }, [resizingSidebar]);
11144
+ const handleresizingSidebar = () => setResizingSidebar(true);
11145
+ if (fullscreen) {
11146
+ return null;
11527
11147
  }
11528
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, deleteModalOpen && /* @__PURE__ */ React__default.createElement(
11529
- DeleteModal$1,
11148
+ return /* @__PURE__ */ React.createElement(
11149
+ "div",
11530
11150
  {
11531
- filename: activeItem ? activeItem.filename : "",
11532
- deleteFunc: async () => {
11533
- if (activeItem) {
11534
- await deleteMediaItem(activeItem);
11535
- setActiveItem(false);
11151
+ onMouseDown: handleresizingSidebar,
11152
+ className: `z-100 absolute top-1/2 right-px w-2 h-32 bg-white rounded-r-md border border-gray-150 shadow-sm hover:shadow-md origin-left transition-all duration-150 ease-out transform translate-x-full -translate-y-1/2 group hover:bg-gray-50 ${displayState !== "closed" ? `opacity-100` : `opacity-0`} ${resizingSidebar ? `scale-110` : `scale-90 hover:scale-100`}`,
11153
+ style: { cursor: "grab" }
11154
+ },
11155
+ /* @__PURE__ */ React.createElement("span", { className: "absolute top-1/2 left-1/2 h-4/6 w-px bg-gray-200 transform -translate-y-1/2 -translate-x-1/2 opacity-30 transition-opacity duration-150 ease-out group-hover:opacity-100" })
11156
+ );
11157
+ };
11158
+ const Item = ({
11159
+ item,
11160
+ depth,
11161
+ setActiveFormId
11162
+ }) => {
11163
+ const cms = useCMS();
11164
+ const depths = ["pl-6", "pl-10", "pl-14"];
11165
+ const form = React.useMemo(
11166
+ () => cms.state.forms.find(({ tinaForm }) => item.formId === tinaForm.id),
11167
+ [item.formId]
11168
+ );
11169
+ return /* @__PURE__ */ React.createElement(
11170
+ "button",
11171
+ {
11172
+ type: "button",
11173
+ key: item.path,
11174
+ onClick: () => setActiveFormId(item.formId),
11175
+ className: `${depths[depth] || "pl-12"} pr-6 py-3 w-full h-full bg-transparent border-none text-lg text-gray-700 group hover:bg-gray-50 transition-all ease-out duration-150 flex items-center justify-between gap-2`
11176
+ },
11177
+ /* @__PURE__ */ React.createElement(BiEdit, { className: "opacity-70 w-5 h-auto text-blue-500 flex-none" }),
11178
+ /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex flex-col gap-0.5 items-start" }, /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 font-sans text-xs font-semibold text-gray-700 whitespace-normal" }, form.tinaForm.label), /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 text-base truncate leading-tight text-gray-600" }, form.tinaForm.id))
11179
+ );
11180
+ };
11181
+ const FormListItem = ({
11182
+ item,
11183
+ depth,
11184
+ setActiveFormId
11185
+ }) => {
11186
+ var _a;
11187
+ return /* @__PURE__ */ React.createElement("div", { className: "divide-y divide-gray-200" }, /* @__PURE__ */ React.createElement(Item, { setActiveFormId, item, depth }), item.subItems && /* @__PURE__ */ React.createElement("ul", { className: "divide-y divide-gray-200" }, (_a = item.subItems) == null ? void 0 : _a.map((subItem) => {
11188
+ if (subItem.type === "document") {
11189
+ return /* @__PURE__ */ React.createElement("li", { key: subItem.formId }, /* @__PURE__ */ React.createElement(
11190
+ Item,
11191
+ {
11192
+ setActiveFormId,
11193
+ depth: depth + 1,
11194
+ item: subItem
11536
11195
  }
11537
- },
11538
- close: () => setDeleteModalOpen(false)
11196
+ ));
11539
11197
  }
11540
- ), newFolderModalOpen && /* @__PURE__ */ React__default.createElement(
11541
- NewFolderModal,
11198
+ })));
11199
+ };
11200
+ const FormLists = (props) => {
11201
+ const cms = useCMS();
11202
+ return /* @__PURE__ */ React.createElement(
11203
+ Transition,
11542
11204
  {
11543
- onSubmit: (name) => {
11544
- setDirectory((oldDir) => {
11545
- if (oldDir) {
11546
- return join(oldDir, name);
11205
+ appear: true,
11206
+ show: true,
11207
+ as: "div",
11208
+ enter: "transition-all ease-out duration-150",
11209
+ enterFrom: "opacity-0 -translate-x-1/2",
11210
+ enterTo: "opacity-100",
11211
+ leave: "transition-all ease-out duration-150",
11212
+ leaveFrom: "opacity-100",
11213
+ leaveTo: "opacity-0 -translate-x-1/2"
11214
+ },
11215
+ cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}`, className: "pt-16" }, /* @__PURE__ */ React.createElement(
11216
+ FormList,
11217
+ {
11218
+ isEditing: props.isEditing,
11219
+ setActiveFormId: (id) => {
11220
+ cms.dispatch({ type: "forms:set-active-form-id", value: id });
11221
+ },
11222
+ formList
11223
+ }
11224
+ )))
11225
+ );
11226
+ };
11227
+ const FormList = (props) => {
11228
+ const cms = useCMS();
11229
+ const listItems = React.useMemo(() => {
11230
+ var _a;
11231
+ const orderedListItems = [];
11232
+ const globalItems = [];
11233
+ const topItems = [];
11234
+ props.formList.items.forEach((item) => {
11235
+ if (item.type === "document") {
11236
+ const form = cms.state.forms.find(
11237
+ ({ tinaForm }) => tinaForm.id === item.formId
11238
+ );
11239
+ if (form.tinaForm.global) {
11240
+ globalItems.push(item);
11241
+ } else {
11242
+ orderedListItems.push(item);
11243
+ }
11244
+ } else {
11245
+ orderedListItems.push(item);
11246
+ }
11247
+ });
11248
+ if (((_a = orderedListItems[0]) == null ? void 0 : _a.type) === "document") {
11249
+ topItems.push({ type: "list", label: "Documents" });
11250
+ }
11251
+ let extra = [];
11252
+ if (globalItems.length) {
11253
+ extra = [{ type: "list", label: "Global Documents" }, ...globalItems];
11254
+ }
11255
+ return [...topItems, ...orderedListItems, ...extra];
11256
+ }, [JSON.stringify(props.formList.items)]);
11257
+ return /* @__PURE__ */ React.createElement("ul", null, /* @__PURE__ */ React.createElement("li", { className: "divide-y divide-gray-200" }, listItems.map((item, index) => {
11258
+ if (item.type === "list") {
11259
+ return /* @__PURE__ */ React.createElement(
11260
+ "div",
11261
+ {
11262
+ key: item.label,
11263
+ className: `relative group text-left w-full bg-white shadow-sm
11264
+ border-gray-100 px-6 -mt-px pb-3 ${index > 0 ? "pt-6 bg-gradient-to-b from-gray-50 via-white to-white" : "pt-3"}`
11265
+ },
11266
+ /* @__PURE__ */ React.createElement(
11267
+ "span",
11268
+ {
11269
+ className: "text-sm tracking-wide font-bold text-gray-700 uppercase"
11270
+ },
11271
+ item.label
11272
+ )
11273
+ );
11274
+ }
11275
+ return /* @__PURE__ */ React.createElement(
11276
+ FormListItem,
11277
+ {
11278
+ setActiveFormId: (id) => props.setActiveFormId(id),
11279
+ key: item.formId,
11280
+ item,
11281
+ depth: 0
11282
+ }
11283
+ );
11284
+ })));
11285
+ };
11286
+ const SidebarNoFormsPlaceholder = () => /* @__PURE__ */ React.createElement(
11287
+ "div",
11288
+ {
11289
+ className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
11290
+ style: {
11291
+ animationName: "fade-in",
11292
+ animationDelay: "300ms",
11293
+ animationTimingFunction: "ease-out",
11294
+ animationIterationCount: 1,
11295
+ animationFillMode: "both",
11296
+ animationDuration: "150ms"
11297
+ }
11298
+ },
11299
+ /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Looks like there's ", /* @__PURE__ */ React.createElement("br", null), "nothing to edit on ", /* @__PURE__ */ React.createElement("br", null), "this page."),
11300
+ /* @__PURE__ */ React.createElement("p", { className: "block pt-5" }, /* @__PURE__ */ React.createElement(
11301
+ Button$1,
11302
+ {
11303
+ href: "https://tina.io/docs/contextual-editing/overview",
11304
+ target: "_blank",
11305
+ as: "a"
11306
+ },
11307
+ /* @__PURE__ */ React.createElement(Emoji$1, { className: "mr-1.5" }, "📖"),
11308
+ " Contextual Editing Docs"
11309
+ ))
11310
+ );
11311
+ const Emoji$1 = ({ className = "", ...props }) => /* @__PURE__ */ React.createElement(
11312
+ "span",
11313
+ {
11314
+ className: `text-[24px] leading-none inline-block ${className}`,
11315
+ ...props
11316
+ }
11317
+ );
11318
+ const minimumTimeToShowLoadingIndicator = 1e3;
11319
+ const FormsView = ({ loadingPlaceholder } = {}) => {
11320
+ const cms = useCMS$1();
11321
+ const { setFormIsPristine } = React.useContext(SidebarContext);
11322
+ const [isShowingLoading, setIsShowingLoading] = React.useState(true);
11323
+ const [initialLoadComplete, setInitialLoadComplete] = React.useState(false);
11324
+ React.useEffect(() => {
11325
+ if (cms.state.isLoadingContent) {
11326
+ setIsShowingLoading(true);
11327
+ const timer = setTimeout(() => {
11328
+ if (!cms.state.isLoadingContent) {
11329
+ setIsShowingLoading(false);
11330
+ setInitialLoadComplete(true);
11331
+ }
11332
+ }, minimumTimeToShowLoadingIndicator);
11333
+ return () => clearTimeout(timer);
11334
+ } else {
11335
+ const timer = setTimeout(() => {
11336
+ setIsShowingLoading(false);
11337
+ setInitialLoadComplete(true);
11338
+ }, minimumTimeToShowLoadingIndicator);
11339
+ return () => clearTimeout(timer);
11340
+ }
11341
+ }, [cms.state.isLoadingContent]);
11342
+ if (isShowingLoading || !initialLoadComplete) {
11343
+ const LoadingPlaceholder = loadingPlaceholder || SidebarLoadingPlaceholder;
11344
+ return /* @__PURE__ */ React.createElement(LoadingPlaceholder, null);
11345
+ }
11346
+ if (!cms.state.formLists.length) {
11347
+ return /* @__PURE__ */ React.createElement(SidebarNoFormsPlaceholder, null);
11348
+ }
11349
+ const isMultiform = cms.state.forms.length > 1;
11350
+ const activeForm = cms.state.forms.find(
11351
+ ({ tinaForm }) => tinaForm.id === cms.state.activeFormId
11352
+ );
11353
+ const isEditing = !!activeForm;
11354
+ if (isMultiform && !activeForm) {
11355
+ return /* @__PURE__ */ React.createElement(FormLists, { isEditing });
11356
+ }
11357
+ const formMetas = cms.plugins.all("form:meta");
11358
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, activeForm && /* @__PURE__ */ React.createElement(FormWrapper$1, { isEditing, isMultiform }, isMultiform && /* @__PURE__ */ React.createElement(MultiformFormHeader, { activeForm }), !isMultiform && /* @__PURE__ */ React.createElement(FormHeader, { activeForm }), formMetas == null ? void 0 : formMetas.map((meta) => /* @__PURE__ */ React.createElement(React.Fragment, { key: meta.name }, /* @__PURE__ */ React.createElement(meta.Component, null))), /* @__PURE__ */ React.createElement(FormBuilder, { form: activeForm, onPristineChange: setFormIsPristine })));
11359
+ };
11360
+ const FormWrapper$1 = ({ isEditing, children }) => {
11361
+ return /* @__PURE__ */ React.createElement(
11362
+ "div",
11363
+ {
11364
+ className: "flex-1 flex flex-col flex-nowrap overflow-hidden h-full w-full relative bg-white",
11365
+ style: isEditing ? {
11366
+ transform: "none",
11367
+ animationName: "fly-in-left",
11368
+ animationDuration: "150ms",
11369
+ animationDelay: "0",
11370
+ animationIterationCount: 1,
11371
+ animationTimingFunction: "ease-out"
11372
+ } : {
11373
+ transform: "translate3d(100%, 0, 0)"
11374
+ }
11375
+ },
11376
+ children
11377
+ );
11378
+ };
11379
+ const MultiformFormHeader = ({
11380
+ activeForm
11381
+ }) => {
11382
+ const cms = useCMS$1();
11383
+ const { formIsPristine } = React.useContext(SidebarContext);
11384
+ return /* @__PURE__ */ React.createElement(
11385
+ "div",
11386
+ {
11387
+ className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
11388
+ },
11389
+ /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
11390
+ "button",
11391
+ {
11392
+ type: "button",
11393
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
11394
+ onClick: () => {
11395
+ const state = activeForm.tinaForm.finalForm.getState();
11396
+ if (state.invalid === true) {
11397
+ cms.alerts.error("Cannot navigate away from an invalid form.");
11547
11398
  } else {
11548
- return name;
11399
+ cms.dispatch({ type: "forms:set-active-form-id", value: null });
11549
11400
  }
11550
- });
11551
- resetOffset();
11552
- resetList();
11401
+ }
11402
+ },
11403
+ /* @__PURE__ */ React.createElement(BiDotsVertical, { className: "h-auto w-5 inline-block opacity-70" })
11404
+ ), /* @__PURE__ */ React.createElement(
11405
+ "button",
11406
+ {
11407
+ type: "button",
11408
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
11409
+ onClick: () => {
11410
+ const collectionName = cms.api.tina.schema.getCollectionByFullPath(
11411
+ cms.state.activeFormId
11412
+ ).name;
11413
+ window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
11414
+ }
11415
+ },
11416
+ /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
11417
+ ), /* @__PURE__ */ React.createElement("span", { className: "opacity-30 text-sm leading-tight whitespace-nowrap flex-0" }, "/"), /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, activeForm.tinaForm.label || activeForm.tinaForm.id), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
11418
+ );
11419
+ };
11420
+ const FormHeader = ({ activeForm }) => {
11421
+ const { formIsPristine } = React.useContext(SidebarContext);
11422
+ const cms = useCMS$1();
11423
+ const shortFormLabel = activeForm.tinaForm.label ? activeForm.tinaForm.label.replace(/^.*[\\\/]/, "") : false;
11424
+ return /* @__PURE__ */ React.createElement(
11425
+ "div",
11426
+ {
11427
+ className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
11428
+ },
11429
+ /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
11430
+ "button",
11431
+ {
11432
+ type: "button",
11433
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
11434
+ onClick: () => {
11435
+ const collectionName = cms.api.tina.schema.getCollectionByFullPath(
11436
+ cms.state.activeFormId
11437
+ ).name;
11438
+ window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
11439
+ }
11440
+ },
11441
+ /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
11442
+ ), shortFormLabel && /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, shortFormLabel), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
11443
+ );
11444
+ };
11445
+ const SidebarContext = React.createContext(null);
11446
+ const minPreviewWidth = 440;
11447
+ const minSidebarWidth = 360;
11448
+ const navBreakpoint = 1279;
11449
+ const LOCALSTATEKEY = "tina.sidebarState";
11450
+ const LOCALWIDTHKEY = "tina.sidebarWidth";
11451
+ const defaultSidebarWidth = 440;
11452
+ const defaultSidebarPosition = "displace";
11453
+ const defaultSidebarState = "open";
11454
+ function SidebarProvider({
11455
+ position = defaultSidebarPosition,
11456
+ resizingSidebar,
11457
+ setResizingSidebar,
11458
+ defaultWidth = defaultSidebarWidth,
11459
+ sidebar
11460
+ }) {
11461
+ var _a, _b, _c;
11462
+ useSubscribable(sidebar);
11463
+ const cms = useCMS$1();
11464
+ if (!cms.enabled)
11465
+ return null;
11466
+ return /* @__PURE__ */ React.createElement(
11467
+ Sidebar$1,
11468
+ {
11469
+ position: ((_a = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _a.position) || position,
11470
+ defaultWidth: ((_b = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _b.defaultWidth) || defaultWidth,
11471
+ resizingSidebar,
11472
+ setResizingSidebar,
11473
+ renderNav: (
11474
+ // @ts-ignore
11475
+ typeof ((_c = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _c.renderNav) !== "undefined" ? (
11476
+ // @ts-ignore
11477
+ cms.sidebar.renderNav
11478
+ ) : true
11479
+ ),
11480
+ sidebar
11481
+ }
11482
+ );
11483
+ }
11484
+ const useFetchCollections = (cms) => {
11485
+ return { collections: cms.api.admin.fetchCollections(), loading: false };
11486
+ };
11487
+ const Sidebar$1 = ({
11488
+ sidebar,
11489
+ defaultWidth,
11490
+ // defaultState,
11491
+ position,
11492
+ renderNav,
11493
+ resizingSidebar,
11494
+ setResizingSidebar
11495
+ }) => {
11496
+ var _a, _b, _c, _d, _e, _f;
11497
+ const cms = useCMS$1();
11498
+ const collectionsInfo = useFetchCollections(cms);
11499
+ const [branchingEnabled, setBranchingEnabled] = React.useState(
11500
+ () => cms.flags.get("branch-switcher")
11501
+ );
11502
+ React.useEffect(() => {
11503
+ cms.events.subscribe("flag:set", ({ key, value }) => {
11504
+ if (key === "branch-switcher") {
11505
+ setBranchingEnabled(value);
11506
+ }
11507
+ });
11508
+ }, [cms.events]);
11509
+ const screens = cms.plugins.getType("screen");
11510
+ const cloudConfigs = cms.plugins.getType("cloud-config");
11511
+ useSubscribable(sidebar);
11512
+ useSubscribable(screens);
11513
+ const allScreens = screens.all();
11514
+ const allConfigs = cloudConfigs.all();
11515
+ const [menuIsOpen, setMenuIsOpen] = useState(false);
11516
+ const [activeScreen, setActiveView] = useState(null);
11517
+ const [sidebarWidth, setSidebarWidth] = React.useState(defaultWidth);
11518
+ const [formIsPristine, setFormIsPristine] = React.useState(true);
11519
+ const activeScreens = allScreens.filter(
11520
+ (screen) => {
11521
+ var _a2, _b2;
11522
+ return screen.navCategory !== "Account" || ((_b2 = (_a2 = cms.api.tina) == null ? void 0 : _a2.authProvider) == null ? void 0 : _b2.getLoginStrategy()) === "UsernamePassword";
11523
+ }
11524
+ );
11525
+ const setDisplayState = (value) => cms.dispatch({ type: "sidebar:set-display-state", value });
11526
+ const displayState = cms.state.sidebarDisplayState;
11527
+ React.useEffect(() => {
11528
+ if (typeof window !== "undefined") {
11529
+ const localSidebarState = window.localStorage.getItem(LOCALSTATEKEY);
11530
+ const localSidebarWidth = window.localStorage.getItem(LOCALWIDTHKEY);
11531
+ if (localSidebarState !== null) {
11532
+ setDisplayState(JSON.parse(localSidebarState));
11533
+ }
11534
+ if (localSidebarWidth !== null) {
11535
+ setSidebarWidth(JSON.parse(localSidebarWidth));
11536
+ }
11537
+ }
11538
+ }, []);
11539
+ React.useEffect(() => {
11540
+ if (typeof window !== "undefined") {
11541
+ const localSidebarState = window.localStorage.getItem(LOCALSTATEKEY);
11542
+ if (localSidebarState === null) {
11543
+ setDisplayState(defaultSidebarState);
11544
+ }
11545
+ }
11546
+ }, [defaultSidebarState]);
11547
+ React.useEffect(() => {
11548
+ if (typeof window !== "undefined" && cms.enabled) {
11549
+ window.localStorage.setItem(LOCALSTATEKEY, JSON.stringify(displayState));
11550
+ }
11551
+ }, [displayState, cms]);
11552
+ React.useEffect(() => {
11553
+ if (resizingSidebar) {
11554
+ window.localStorage.setItem(LOCALWIDTHKEY, JSON.stringify(sidebarWidth));
11555
+ }
11556
+ }, [sidebarWidth, resizingSidebar]);
11557
+ const isTinaAdminEnabled = cms.flags.get("tina-admin") === false ? false : true;
11558
+ const contentCreators = isTinaAdminEnabled ? [] : cms.plugins.getType("content-creator").all();
11559
+ const toggleFullscreen = () => {
11560
+ if (displayState === "fullscreen") {
11561
+ setDisplayState("open");
11562
+ } else {
11563
+ setDisplayState("fullscreen");
11564
+ }
11565
+ };
11566
+ const toggleSidebarOpen = () => {
11567
+ cms.dispatch({ type: "toggle-edit-state" });
11568
+ };
11569
+ const toggleMenu = () => {
11570
+ setMenuIsOpen((menuIsOpen2) => !menuIsOpen2);
11571
+ };
11572
+ React.useEffect(() => {
11573
+ const updateLayout = () => {
11574
+ if (displayState === "fullscreen") {
11575
+ return;
11576
+ }
11577
+ updateBodyDisplacement({
11578
+ position,
11579
+ displayState,
11580
+ sidebarWidth,
11581
+ resizingSidebar
11582
+ });
11583
+ };
11584
+ updateLayout();
11585
+ window.addEventListener("resize", updateLayout);
11586
+ return () => {
11587
+ window.removeEventListener("resize", updateLayout);
11588
+ };
11589
+ }, [displayState, position, sidebarWidth, resizingSidebar]);
11590
+ const windowWidth = useWindowWidth();
11591
+ const displayNav = renderNav && (sidebarWidth > navBreakpoint && windowWidth > navBreakpoint || displayState === "fullscreen" && windowWidth > navBreakpoint);
11592
+ const renderMobileNav = renderNav && (sidebarWidth < navBreakpoint + 1 || windowWidth < navBreakpoint + 1);
11593
+ return /* @__PURE__ */ React.createElement(
11594
+ SidebarContext.Provider,
11595
+ {
11596
+ value: {
11597
+ sidebarWidth,
11598
+ setSidebarWidth,
11599
+ displayState,
11600
+ setDisplayState,
11601
+ position,
11602
+ toggleFullscreen,
11603
+ toggleSidebarOpen,
11604
+ resizingSidebar,
11605
+ setResizingSidebar,
11606
+ menuIsOpen,
11607
+ setMenuIsOpen,
11608
+ toggleMenu,
11609
+ setActiveView,
11610
+ formIsPristine,
11611
+ setFormIsPristine
11612
+ }
11613
+ },
11614
+ /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SidebarWrapper, null, /* @__PURE__ */ React.createElement(EditButton, null), displayNav && /* @__PURE__ */ React.createElement(
11615
+ Nav,
11616
+ {
11617
+ isLocalMode: (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode,
11618
+ showCollections: isTinaAdminEnabled,
11619
+ collectionsInfo,
11620
+ screens: activeScreens,
11621
+ cloudConfigs: allConfigs,
11622
+ contentCreators,
11623
+ sidebarWidth,
11624
+ RenderNavSite: ({ view }) => /* @__PURE__ */ React.createElement(
11625
+ SidebarSiteLink,
11626
+ {
11627
+ view,
11628
+ onClick: () => {
11629
+ setActiveView(view);
11630
+ setMenuIsOpen(false);
11631
+ }
11632
+ }
11633
+ ),
11634
+ RenderNavCloud: ({ config }) => /* @__PURE__ */ React.createElement(SidebarCloudLink$1, { config }),
11635
+ RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
11636
+ SidebarCollectionLink,
11637
+ {
11638
+ onClick: () => {
11639
+ setMenuIsOpen(false);
11640
+ },
11641
+ collection
11642
+ }
11643
+ ),
11644
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
11645
+ SidebarCollectionLink,
11646
+ {
11647
+ onClick: () => {
11648
+ setMenuIsOpen(false);
11649
+ },
11650
+ collection,
11651
+ Icon: ImUsers
11652
+ }
11653
+ )
11654
+ }
11655
+ ), /* @__PURE__ */ React.createElement(SidebarBody, null, /* @__PURE__ */ React.createElement(
11656
+ SidebarHeader,
11657
+ {
11658
+ displayNav,
11659
+ renderNav,
11660
+ isLocalMode: (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.isLocalMode,
11661
+ branchingEnabled
11662
+ }
11663
+ ), /* @__PURE__ */ React.createElement(FormsView, { loadingPlaceholder: sidebar.loadingPlaceholder }), activeScreen && /* @__PURE__ */ React.createElement(
11664
+ ScreenPluginModal,
11665
+ {
11666
+ screen: activeScreen,
11667
+ close: () => setActiveView(null)
11668
+ }
11669
+ )), /* @__PURE__ */ React.createElement(ResizeHandle, null)), renderMobileNav && /* @__PURE__ */ React.createElement(Transition, { show: menuIsOpen, as: "div" }, /* @__PURE__ */ React.createElement(
11670
+ TransitionChild,
11671
+ {
11672
+ enter: "transform transition-all ease-out duration-300",
11673
+ enterFrom: "opacity-0 -translate-x-full",
11674
+ enterTo: "opacity-100 translate-x-0",
11675
+ leave: "transform transition-all ease-in duration-200",
11676
+ leaveFrom: "opacity-100 translate-x-0",
11677
+ leaveTo: "opacity-0 -translate-x-full"
11678
+ },
11679
+ /* @__PURE__ */ React.createElement("div", { className: "fixed left-0 top-0 z-overlay h-full transform" }, /* @__PURE__ */ React.createElement(
11680
+ Nav,
11681
+ {
11682
+ isLocalMode: (_f = (_e = cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.isLocalMode,
11683
+ className: "rounded-r-md",
11684
+ showCollections: isTinaAdminEnabled,
11685
+ collectionsInfo,
11686
+ screens: activeScreens,
11687
+ cloudConfigs: allConfigs,
11688
+ contentCreators,
11689
+ sidebarWidth,
11690
+ RenderNavSite: ({ view }) => /* @__PURE__ */ React.createElement(
11691
+ SidebarSiteLink,
11692
+ {
11693
+ view,
11694
+ onClick: () => {
11695
+ setActiveView(view);
11696
+ setMenuIsOpen(false);
11697
+ }
11698
+ }
11699
+ ),
11700
+ RenderNavCloud: ({ config }) => /* @__PURE__ */ React.createElement(SidebarCloudLink$1, { config }),
11701
+ RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
11702
+ SidebarCollectionLink,
11703
+ {
11704
+ onClick: () => {
11705
+ setMenuIsOpen(false);
11706
+ },
11707
+ collection
11708
+ }
11709
+ ),
11710
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
11711
+ SidebarCollectionLink,
11712
+ {
11713
+ onClick: () => {
11714
+ setMenuIsOpen(false);
11715
+ },
11716
+ collection,
11717
+ Icon: ImUsers
11718
+ }
11719
+ )
11720
+ },
11721
+ /* @__PURE__ */ React.createElement("div", { className: "absolute top-8 right-0 transform translate-x-full overflow-hidden" }, /* @__PURE__ */ React.createElement(
11722
+ Button$1,
11723
+ {
11724
+ rounded: "right",
11725
+ variant: "secondary",
11726
+ onClick: () => {
11727
+ setMenuIsOpen(false);
11728
+ },
11729
+ className: "transition-opacity duration-150 ease-out"
11730
+ },
11731
+ /* @__PURE__ */ React.createElement(IoMdClose, { className: "h-5 w-auto text-blue-500" })
11732
+ ))
11733
+ ))
11734
+ ), /* @__PURE__ */ React.createElement(
11735
+ TransitionChild,
11736
+ {
11737
+ enter: "ease-out duration-300",
11738
+ enterFrom: "opacity-0",
11739
+ enterTo: "opacity-80",
11740
+ entered: "opacity-80",
11741
+ leave: "ease-in duration-200",
11742
+ leaveFrom: "opacity-80",
11743
+ leaveTo: "opacity-0"
11553
11744
  },
11554
- close: () => setNewFolderModalOpen(false)
11555
- }
11556
- ), /* @__PURE__ */ React__default.createElement(MediaPickerWrap, null, /* @__PURE__ */ React__default.createElement(SyncStatusContainer, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-wrap items-center bg-gray-50 border-b border-gray-150 gap-4 py-3 px-5 shadow-sm flex-shrink-0" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-1 items-center gap-4" }, /* @__PURE__ */ React__default.createElement(ViewModeToggle, { viewMode, setViewMode }), /* @__PURE__ */ React__default.createElement(
11557
- Breadcrumb$1,
11558
- {
11559
- directory,
11560
- setDirectory: (dir) => {
11561
- setDirectory(dir);
11562
- setLoadFolders(true);
11563
- resetOffset();
11564
- resetList();
11565
- setActiveItem(false);
11566
- }
11745
+ /* @__PURE__ */ React.createElement(
11746
+ "div",
11747
+ {
11748
+ onClick: () => {
11749
+ setMenuIsOpen(false);
11750
+ },
11751
+ className: "fixed z-menu inset-0 bg-gradient-to-br from-gray-800 via-gray-900 to-black"
11752
+ }
11753
+ )
11754
+ )))
11755
+ );
11756
+ };
11757
+ const updateBodyDisplacement = ({
11758
+ position = "overlay",
11759
+ displayState,
11760
+ sidebarWidth,
11761
+ resizingSidebar
11762
+ }) => {
11763
+ const body = document.getElementsByTagName("body")[0];
11764
+ const windowWidth = window.innerWidth;
11765
+ if (position === "displace") {
11766
+ body.style.transition = resizingSidebar ? "" : displayState === "fullscreen" ? "padding 0ms 150ms" : displayState === "closed" ? "padding 0ms 0ms" : "padding 0ms 300ms";
11767
+ if (displayState === "open") {
11768
+ const bodyDisplacement = Math.min(
11769
+ sidebarWidth,
11770
+ windowWidth - minPreviewWidth
11771
+ );
11772
+ body.style.paddingLeft = `${bodyDisplacement}px`;
11773
+ } else {
11774
+ body.style.paddingLeft = "0";
11567
11775
  }
11568
- )), cms.media.store.isStatic ? null : /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-wrap items-center gap-4" }, /* @__PURE__ */ React__default.createElement(
11776
+ } else {
11777
+ body.style.transition = "";
11778
+ body.style.paddingLeft = "0";
11779
+ }
11780
+ };
11781
+ const SidebarHeader = ({
11782
+ branchingEnabled,
11783
+ renderNav,
11784
+ displayNav,
11785
+ isLocalMode
11786
+ }) => {
11787
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
11788
+ const { toggleFullscreen, displayState, setMenuIsOpen, toggleSidebarOpen } = React.useContext(SidebarContext);
11789
+ const displayMenuButton = renderNav && !displayNav;
11790
+ const cms = useCMS$1();
11791
+ const previewFunction = (_f = (_e = (_d = (_c = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.schema) == null ? void 0 : _c.config) == null ? void 0 : _d.config) == null ? void 0 : _e.ui) == null ? void 0 : _f.previewUrl;
11792
+ const branch = (_h = (_g = cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.branch;
11793
+ const previewUrl = typeof previewFunction === "function" ? (_i = previewFunction({ branch })) == null ? void 0 : _i.url : null;
11794
+ return /* @__PURE__ */ React.createElement("div", { className: "flex-grow-0 w-full overflow-visible z-20" }, isLocalMode && /* @__PURE__ */ React.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", { className: "mt-4 -mb-14 w-full flex gap-3 items-center justify-between pointer-events-none" }, displayMenuButton && /* @__PURE__ */ React.createElement(
11569
11795
  Button$1,
11570
11796
  {
11571
- busy: false,
11797
+ rounded: "right",
11572
11798
  variant: "white",
11573
11799
  onClick: () => {
11574
- setRefreshing(true);
11575
- resetOffset();
11576
- resetList();
11577
- setActiveItem(false);
11800
+ setMenuIsOpen(true);
11578
11801
  },
11579
- className: "whitespace-nowrap"
11802
+ className: "pointer-events-auto -ml-px"
11580
11803
  },
11581
- "Refresh",
11582
- /* @__PURE__ */ React__default.createElement(IoMdRefresh, { className: "w-6 h-full ml-2 opacity-70 text-blue-500" })
11583
- ), /* @__PURE__ */ React__default.createElement(
11584
- Button$1,
11804
+ /* @__PURE__ */ React.createElement(BiMenu, { className: "h-6 w-auto text-blue-500" })
11805
+ ), /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex gap-3 items-center shrink min-w-0" }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React.createElement(BranchButton, null), branchingEnabled && !isLocalMode && previewUrl && /* @__PURE__ */ React.createElement(
11806
+ "button",
11585
11807
  {
11586
- busy: false,
11587
- variant: "white",
11808
+ className: "pointer-events-auto flex min-w-0 shrink gap-1 items-center justify-between form-select text-sm h-10 px-4 shadow text-gray-500 hover:text-blue-500 bg-white hover:bg-gray-50 border border-gray-100 transition-color duration-150 ease-out rounded-full focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out text-[12px] leading-tight min-w-[5rem]",
11588
11809
  onClick: () => {
11589
- setNewFolderModalOpen(true);
11590
- },
11591
- className: "whitespace-nowrap"
11592
- },
11593
- "New Folder",
11594
- /* @__PURE__ */ React__default.createElement(BiFolder, { className: "w-6 h-full ml-2 opacity-70 text-blue-500" })
11595
- ), /* @__PURE__ */ React__default.createElement(UploadButton, { onClick, uploading }))), /* @__PURE__ */ React__default.createElement("div", { className: "flex h-full overflow-hidden bg-white" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex w-full flex-col h-full @container" }, /* @__PURE__ */ React__default.createElement(
11596
- "ul",
11597
- {
11598
- ...rootProps,
11599
- className: `h-full grow overflow-y-auto transition duration-150 ease-out bg-gradient-to-b from-gray-50/50 to-gray-50 ${list.items.length === 0 || viewMode === "list" && "w-full flex flex-1 flex-col justify-start -mb-px"} ${list.items.length > 0 && viewMode === "grid" && "w-full p-4 gap-4 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 4xl:grid-cols-6 6xl:grid-cols-9 auto-rows-auto content-start justify-start"} ${isDragActive ? `border-2 border-blue-500 rounded-lg` : ``}`
11600
- },
11601
- /* @__PURE__ */ React__default.createElement("input", { ...getInputProps() }),
11602
- listState === "loaded" && list.items.length === 0 && /* @__PURE__ */ React__default.createElement(EmptyMediaList, null),
11603
- viewMode === "list" && list.items.map((item) => /* @__PURE__ */ React__default.createElement(
11604
- ListMediaItem,
11605
- {
11606
- key: item.id,
11607
- item,
11608
- onClick: onClickMediaItem,
11609
- active: activeItem && activeItem.id === item.id
11610
- }
11611
- )),
11612
- viewMode === "grid" && list.items.map((item) => /* @__PURE__ */ React__default.createElement(
11613
- GridMediaItem,
11614
- {
11615
- key: item.id,
11616
- item,
11617
- onClick: onClickMediaItem,
11618
- active: activeItem && activeItem.id === item.id
11619
- }
11620
- )),
11621
- !!list.nextOffset && /* @__PURE__ */ React__default.createElement(LoadingMediaList, { ref: loaderRef })
11622
- )), /* @__PURE__ */ React__default.createElement(
11623
- ActiveItemPreview,
11624
- {
11625
- activeItem,
11626
- close: closePreview,
11627
- selectMediaItem,
11628
- allowDelete: cms.media.store.isStatic ? false : allowDelete,
11629
- deleteMediaItem: () => {
11630
- setDeleteModalOpen(true);
11810
+ window.open(previewUrl, "_blank");
11631
11811
  }
11632
- }
11633
- )))));
11634
- }
11635
- const ActiveItemPreview = ({
11636
- activeItem,
11637
- close: close2,
11638
- selectMediaItem,
11639
- deleteMediaItem,
11640
- allowDelete
11641
- }) => {
11642
- const thumbnail = activeItem ? (activeItem.thumbnails || {})["1000x1000"] : "";
11643
- return /* @__PURE__ */ React__default.createElement(
11812
+ },
11813
+ /* @__PURE__ */ React.createElement(BiLinkExternal, { className: "flex-shrink-0 w-4 h-auto text-blue-500/70 mr-1" }),
11814
+ /* @__PURE__ */ React.createElement("span", { className: "truncate max-w-full min-w-0 shrink" }, "Preview")
11815
+ )), /* @__PURE__ */ React.createElement(
11644
11816
  "div",
11645
11817
  {
11646
- className: `shrink-0 h-full flex flex-col items-start gap-3 overflow-y-auto bg-white border-l border-gray-100 bg-white shadow-md transition ease-out duration-150 ${activeItem ? `p-4 opacity-100 w-[35%] max-w-[560px] min-w-[240px]` : `translate-x-8 opacity-0 w-[0px]`}`
11818
+ className: "flex items-center pointer-events-auto transition-opacity duration-150 ease-in-out -mr-px"
11647
11819
  },
11648
- activeItem && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex grow-0 shrink-0 gap-2 w-full items-center justify-between" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg text-gray-600 w-full max-w-full break-words block truncate flex-1" }, activeItem.filename), /* @__PURE__ */ React__default.createElement(
11649
- IconButton,
11650
- {
11651
- variant: "ghost",
11652
- className: "group grow-0 shrink-0",
11653
- onClick: close2
11654
- },
11655
- /* @__PURE__ */ React__default.createElement(
11656
- BiX,
11657
- {
11658
- className: `w-7 h-auto text-gray-500 opacity-50 group-hover:opacity-100 transition duration-150 ease-out`
11659
- }
11660
- )
11661
- )), isImage(thumbnail) ? /* @__PURE__ */ React__default.createElement("div", { className: "w-full max-h-[75%]" }, /* @__PURE__ */ React__default.createElement(
11662
- "img",
11663
- {
11664
- className: "block border border-gray-100 rounded-md overflow-hidden object-center object-contain max-w-full max-h-full m-auto shadow",
11665
- src: thumbnail,
11666
- alt: activeItem.filename
11667
- }
11668
- )) : /* @__PURE__ */ React__default.createElement("span", { className: "p-3 border border-gray-100 rounded-md overflow-hidden bg-gray-50 shadow" }, /* @__PURE__ */ React__default.createElement(BiFile, { className: "w-14 h-auto fill-gray-300" })), /* @__PURE__ */ React__default.createElement("div", { className: "grow h-full w-full shrink flex flex-col gap-3 items-start justify-start" }, /* @__PURE__ */ React__default.createElement(CopyField, { value: absoluteImgURL(activeItem.src), label: "URL" })), /* @__PURE__ */ React__default.createElement("div", { className: "shrink-0 w-full flex flex-col justify-end items-start" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex w-full gap-3" }, selectMediaItem && /* @__PURE__ */ React__default.createElement(
11669
- Button$1,
11670
- {
11671
- size: "medium",
11672
- variant: "primary",
11673
- className: "grow",
11674
- onClick: () => selectMediaItem(activeItem)
11675
- },
11676
- "Insert",
11677
- /* @__PURE__ */ React__default.createElement(BiArrowToBottom, { className: "ml-1 -mr-0.5 w-6 h-auto text-white opacity-70" })
11678
- ), allowDelete && /* @__PURE__ */ React__default.createElement(
11820
+ /* @__PURE__ */ React.createElement(
11679
11821
  Button$1,
11680
11822
  {
11823
+ rounded: "left",
11681
11824
  variant: "white",
11682
- size: "medium",
11683
- className: "grow max-w-[40%]",
11684
- onClick: deleteMediaItem
11825
+ onClick: toggleSidebarOpen,
11826
+ "aria-label": "closes cms sidebar",
11827
+ className: "-mr-px"
11685
11828
  },
11686
- "Delete",
11687
- /* @__PURE__ */ React__default.createElement(TrashIcon, { className: "ml-1 -mr-0.5 w-6 h-auto text-red-500 opacity-70" })
11688
- ))))
11689
- );
11829
+ /* @__PURE__ */ React.createElement(MdOutlineArrowBackIos, { className: "h-[18px] w-auto -mr-1 text-blue-500" })
11830
+ ),
11831
+ /* @__PURE__ */ React.createElement(Button$1, { rounded: "custom", variant: "white", onClick: toggleFullscreen }, displayState === "fullscreen" ? (
11832
+ // BiCollapseAlt
11833
+ /* @__PURE__ */ React.createElement(
11834
+ "svg",
11835
+ {
11836
+ className: "h-5 w-auto -mx-1 text-blue-500",
11837
+ stroke: "currentColor",
11838
+ fill: "currentColor",
11839
+ strokeWidth: "0",
11840
+ viewBox: "0 0 24 24",
11841
+ xmlns: "http://www.w3.org/2000/svg"
11842
+ },
11843
+ /* @__PURE__ */ React.createElement("path", { d: "M2 15h7v7h2v-9H2v2zM15 2h-2v9h9V9h-7V2z" })
11844
+ )
11845
+ ) : /* @__PURE__ */ React.createElement(BiExpandAlt, { className: "h-5 -mx-1 w-auto text-blue-500" }))
11846
+ )));
11690
11847
  };
11691
- const UploadButton = ({ onClick, uploading }) => {
11692
- return /* @__PURE__ */ React__default.createElement(
11693
- Button$1,
11848
+ const SidebarSiteLink = ({
11849
+ view,
11850
+ onClick
11851
+ }) => {
11852
+ return /* @__PURE__ */ React.createElement(
11853
+ "button",
11694
11854
  {
11695
- variant: "primary",
11696
- size: "custom",
11697
- className: "text-sm h-10 px-6",
11698
- busy: uploading,
11855
+ className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100",
11856
+ value: view.name,
11699
11857
  onClick
11700
11858
  },
11701
- uploading ? /* @__PURE__ */ React__default.createElement(LoadingDots, null) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload ", /* @__PURE__ */ React__default.createElement(BiCloudUpload, { className: "w-6 h-full ml-2 opacity-70" }))
11859
+ /* @__PURE__ */ React.createElement(view.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }),
11860
+ " ",
11861
+ view.name
11702
11862
  );
11703
11863
  };
11704
- const LoadingMediaList = forwardRef(
11705
- (props, ref) => {
11706
- const { extraText, ...rest } = props;
11707
- return /* @__PURE__ */ React__default.createElement(
11708
- "div",
11709
- {
11710
- ref,
11711
- className: "w-full h-full flex flex-col items-center justify-center",
11712
- ...rest
11713
- },
11714
- extraText && /* @__PURE__ */ React__default.createElement("p", null, extraText),
11715
- /* @__PURE__ */ React__default.createElement(LoadingDots, { color: "var(--tina-color-primary)" })
11716
- );
11717
- }
11718
- );
11719
- const MediaPickerWrap = ({ children }) => {
11720
- return /* @__PURE__ */ React__default.createElement("div", { className: "h-full flex-1 text-gray-700 flex flex-col relative bg-gray-50 outline-none active:outline-none focus:outline-none" }, children);
11721
- };
11722
- const SyncStatusContext = createContext(
11723
- void 0
11724
- );
11725
- const SyncStatusContainer = ({ children }) => {
11726
- var _a, _b, _c;
11727
- const cms = useCMS();
11728
- const isLocal = cms.api.tina.isLocalMode;
11729
- const tinaMedia = (_c = (_b = (_a = cms.api.tina.schema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.media) == null ? void 0 : _c.tina;
11730
- const hasTinaMedia = !!((tinaMedia == null ? void 0 : tinaMedia.mediaRoot) || (tinaMedia == null ? void 0 : tinaMedia.publicFolder));
11731
- const doCheckSyncStatus = hasTinaMedia && !isLocal;
11732
- const [syncStatus, setSyncStatus] = useState(doCheckSyncStatus ? "loading" : "synced");
11733
- useEffect(() => {
11734
- const checkSyncStatus = async () => {
11735
- if (doCheckSyncStatus) {
11736
- const project = await cms.api.tina.getProject();
11737
- setSyncStatus(project.mediaBranch ? "synced" : "needs-sync");
11738
- }
11739
- };
11740
- if (!cms.media.store.isStatic) {
11741
- checkSyncStatus();
11742
- }
11743
- }, []);
11744
- return syncStatus == "needs-sync" ? /* @__PURE__ */ React__default.createElement("div", { className: "h-full flex items-center justify-center p-6 bg-gradient-to-t from-gray-200 to-transparent" }, /* @__PURE__ */ React__default.createElement("div", { className: "rounded-lg border shadow-sm px-4 lg:px-6 py-3 lg:py-4 bg-gradient-to-r from-yellow-50 to-yellow-100 border-yellow-200 mx-auto mb-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex items-start sm:items-center gap-2" }, /* @__PURE__ */ React__default.createElement(
11745
- BiError,
11746
- {
11747
- className: `w-7 h-auto flex-shrink-0 text-yellow-400 -mt-px`
11748
- }
11749
- ), /* @__PURE__ */ React__default.createElement(
11750
- "div",
11751
- {
11752
- className: `flex-1 flex flex-col items-start gap-0.5 text-base text-yellow-700`
11753
- },
11754
- "Media needs to be turned on for this project.",
11755
- /* @__PURE__ */ React__default.createElement(
11864
+ const SidebarCloudLink$1 = ({ config }) => {
11865
+ if (config.text) {
11866
+ return /* @__PURE__ */ React.createElement("span", { className: "text-base tracking-wide text-gray-500 flex items-center opacity-90" }, config.text, " ", /* @__PURE__ */ React.createElement(
11756
11867
  "a",
11757
11868
  {
11758
- className: "transition-all duration-150 ease-out text-blue-500 hover:text-blue-400 hover:underline underline decoration-blue-200 hover:decoration-blue-400 font-medium flex items-center justify-start gap-1",
11759
11869
  target: "_blank",
11760
- href: `${cms.api.tina.appDashboardLink}/media`
11870
+ className: "ml-1 text-blue-600 hover:opacity-60",
11871
+ href: config.link.href
11761
11872
  },
11762
- "Sync Your Media In TinaCloud.",
11763
- /* @__PURE__ */ React__default.createElement(BiLinkExternal, { className: `w-5 h-auto flex-shrink-0` })
11764
- )
11765
- )))) : /* @__PURE__ */ React__default.createElement(SyncStatusContext.Provider, { value: { syncStatus } }, children);
11766
- };
11767
- const useSyncStatus = () => {
11768
- const context = useContext(SyncStatusContext);
11769
- if (!context) {
11770
- throw new Error("useSyncStatus must be used within a SyncStatusProvider");
11873
+ config.link.text
11874
+ ));
11771
11875
  }
11772
- return context;
11773
- };
11774
- const EmptyMediaList = () => {
11775
- const { syncStatus } = useSyncStatus();
11776
- return /* @__PURE__ */ React__default.createElement("div", { className: `p-12 text-xl opacity-50 text-center` }, syncStatus == "synced" ? "Drag and drop assets here" : "Loading...");
11876
+ return /* @__PURE__ */ React.createElement("span", { className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100" }, /* @__PURE__ */ React.createElement(config.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }), /* @__PURE__ */ React.createElement("a", { target: "_blank", href: config.link.href }, config.link.text));
11777
11877
  };
11778
- const DocsLink = ({ title, message, docsLink, ...props }) => {
11779
- return /* @__PURE__ */ React__default.createElement("div", { className: "h-3/4 text-center flex flex-col justify-center", ...props }, /* @__PURE__ */ React__default.createElement("h2", { className: "mb-3 text-xl text-gray-600" }, title), /* @__PURE__ */ React__default.createElement("div", { className: "mb-3 text-base text-gray-700" }, message), /* @__PURE__ */ React__default.createElement(
11878
+ const SidebarCollectionLink = ({
11879
+ Icon = ImFilesEmpty,
11880
+ collection,
11881
+ onClick
11882
+ }) => {
11883
+ const cms = useCMS$1();
11884
+ const tinaPreview = cms.flags.get("tina-preview") || false;
11885
+ return /* @__PURE__ */ React.createElement(
11780
11886
  "a",
11781
11887
  {
11782
- href: docsLink,
11783
- target: "_blank",
11784
- rel: "noreferrer noopener",
11785
- className: "font-bold text-blue-500 hover:text-blue-600 hover:underline transition-all ease-out duration-150"
11888
+ onClick,
11889
+ href: `${tinaPreview ? `/${tinaPreview}/index.html#` : "/admin#"}/collections/${collection.name}/~`,
11890
+ className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100"
11786
11891
  },
11787
- "Learn More"
11788
- ));
11892
+ /* @__PURE__ */ React.createElement(Icon, { className: "mr-2 h-6 opacity-80 w-auto" }),
11893
+ " ",
11894
+ collection.label ? collection.label : collection.name
11895
+ );
11789
11896
  };
11790
- const ViewModeToggle = ({ viewMode, setViewMode }) => {
11791
- const toggleClasses = {
11792
- base: "relative whitespace-nowrap flex items-center justify-center flex-1 block font-medium text-base py-1 transition-all ease-out duration-150 border",
11793
- active: "bg-white text-blue-500 shadow-inner border-gray-50 border-t-gray-100",
11794
- inactive: "bg-gray-50 text-gray-400 shadow border-gray-100 border-t-white"
11795
- };
11796
- return /* @__PURE__ */ React__default.createElement(
11897
+ const EditButton = ({}) => {
11898
+ const { displayState, toggleSidebarOpen } = React.useContext(SidebarContext);
11899
+ return /* @__PURE__ */ React.createElement(
11900
+ Button$1,
11901
+ {
11902
+ rounded: "right",
11903
+ variant: "primary",
11904
+ size: "custom",
11905
+ onClick: toggleSidebarOpen,
11906
+ className: `z-chrome absolute top-6 right-0 translate-x-full text-sm h-10 pl-3 pr-4 transition-all duration-300 ${displayState !== "closed" ? "opacity-0 ease-in pointer-events-none" : "ease-out pointer-events-auto"}`,
11907
+ "aria-label": "opens cms sidebar"
11908
+ },
11909
+ /* @__PURE__ */ React.createElement(BiPencil, { className: "h-6 w-auto" })
11910
+ );
11911
+ };
11912
+ const SidebarWrapper = ({ children }) => {
11913
+ const { displayState, sidebarWidth, resizingSidebar } = React.useContext(SidebarContext);
11914
+ return /* @__PURE__ */ React.createElement(
11797
11915
  "div",
11798
11916
  {
11799
- className: `grow-0 flex justify-between rounded-md border border-gray-100`
11917
+ className: `fixed top-0 left-0 h-dvh z-base ${displayState === "closed" ? "pointer-events-none" : ""}`
11800
11918
  },
11801
- /* @__PURE__ */ React__default.createElement(
11802
- "button",
11803
- {
11804
- className: `${toggleClasses.base} px-2.5 rounded-l-md ${viewMode === "grid" ? toggleClasses.active : toggleClasses.inactive}`,
11805
- onClick: () => {
11806
- setViewMode("grid");
11807
- }
11808
- },
11809
- /* @__PURE__ */ React__default.createElement(BiGridAlt, { className: "w-6 h-full opacity-70" })
11810
- ),
11811
- /* @__PURE__ */ React__default.createElement(
11812
- "button",
11919
+ /* @__PURE__ */ React.createElement(
11920
+ "div",
11813
11921
  {
11814
- className: `${toggleClasses.base} px-2 rounded-r-md ${viewMode === "list" ? toggleClasses.active : toggleClasses.inactive}`,
11815
- onClick: () => {
11816
- setViewMode("list");
11922
+ className: `relative h-dvh transform flex ${displayState !== "closed" ? "" : "-translate-x-full"} ${resizingSidebar ? "transition-none" : displayState === "closed" ? "transition-all duration-300 ease-in" : displayState === "fullscreen" ? "transition-all duration-150 ease-out" : "transition-all duration-300 ease-out"}`,
11923
+ style: {
11924
+ width: displayState === "fullscreen" ? "100vw" : `${sidebarWidth}px`,
11925
+ maxWidth: displayState === "fullscreen" ? "100vw" : "calc(100vw - 8px)",
11926
+ minWidth: "360px"
11817
11927
  }
11818
11928
  },
11819
- /* @__PURE__ */ React__default.createElement(BiListUl, { className: "w-8 h-full opacity-70" })
11929
+ children
11820
11930
  )
11821
11931
  );
11822
11932
  };
11823
- const MediaManagerScreenPlugin = createScreen({
11824
- name: "Media Manager",
11825
- Component: MediaPicker,
11826
- Icon: MdOutlinePhotoLibrary,
11827
- layout: "fullscreen",
11828
- props: {
11829
- allowDelete: true
11830
- }
11831
- });
11832
- function UpdatePassword(props) {
11833
- const cms = useCMS$1();
11834
- const client = cms.api.tina;
11835
- const [password, setPassword] = useState("");
11836
- const [confirmPassword, setConfirmPassword] = useState("");
11837
- const [dirty, setDirty] = useState(false);
11838
- const [result, setResult] = useState(null);
11839
- const [formState, setFormState] = useState("idle");
11840
- const [passwordChangeRequired, setPasswordChangeRequired] = useState(false);
11841
- useEffect(() => {
11842
- var _a;
11843
- (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.getUser().then(
11844
- (user) => setPasswordChangeRequired((user == null ? void 0 : user.passwordChangeRequired) ?? false)
11845
- );
11846
- }, []);
11847
- let err = null;
11848
- if (dirty && password !== confirmPassword) {
11849
- err = "Passwords do not match";
11850
- }
11851
- if (dirty && !password) {
11852
- err = "Please enter a password";
11853
- }
11854
- const updatePassword = async () => {
11855
- var _a;
11856
- setResult(null);
11857
- setFormState("busy");
11858
- const res = await cms.api.tina.request(
11859
- `mutation($password: String!) { updatePassword(password: $password) }`,
11860
- {
11861
- variables: {
11862
- password
11863
- }
11864
- }
11865
- );
11866
- if (!(res == null ? void 0 : res.updatePassword)) {
11867
- setResult("Error updating password");
11868
- } else {
11869
- setDirty(false);
11870
- setPassword("");
11871
- setConfirmPassword("");
11872
- setResult("Password updated");
11873
- setPasswordChangeRequired(false);
11874
- await new Promise((resolve) => setTimeout(resolve, 1e3));
11875
- (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.logout().then(async () => {
11876
- if (typeof (client == null ? void 0 : client.onLogout) === "function") {
11877
- await client.onLogout();
11878
- await new Promise((resolve) => setTimeout(resolve, 500));
11879
- }
11880
- window.location.href = new URL(window.location.href).pathname;
11881
- }).catch((e) => console.error(e));
11882
- }
11883
- setFormState("idle");
11884
- };
11885
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex justify-center items-center h-full" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col space-y-8 p-6" }, passwordChangeRequired && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-red-500" }, "Your password has expired. Please update your password."), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "New Password"), /* @__PURE__ */ React__default.createElement(
11886
- BaseTextField,
11887
- {
11888
- type: "password",
11889
- name: "password",
11890
- id: "password",
11891
- placeholder: "Enter password",
11892
- className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
11893
- value: password,
11894
- onKeyDown: () => {
11895
- setDirty(true);
11896
- setResult(null);
11897
- },
11898
- onChange: (e) => setPassword(e.target.value),
11899
- required: true
11900
- }
11901
- )), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "Confirm New Password"), /* @__PURE__ */ React__default.createElement(
11902
- BaseTextField,
11903
- {
11904
- type: "password",
11905
- name: "confirmPassword",
11906
- id: "confirmPassword",
11907
- placeholder: "Confirm password",
11908
- className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
11909
- value: confirmPassword,
11910
- onKeyDown: () => {
11911
- setDirty(true);
11912
- setResult(null);
11913
- },
11914
- onChange: (e) => setConfirmPassword(e.target.value),
11915
- required: true
11916
- }
11917
- )), result && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-gray-500" }, result), err && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-red-500" }, err), /* @__PURE__ */ React__default.createElement(
11918
- Button$1,
11933
+ const SidebarBody = ({ children }) => {
11934
+ return /* @__PURE__ */ React.createElement(
11935
+ "div",
11919
11936
  {
11920
- onClick: updatePassword,
11921
- disabled: err,
11922
- variant: "primary",
11923
- busy: formState === "busy"
11937
+ className: "relative left-0 w-full h-full flex flex-col items-stretch bg-white border-r border-gray-200 overflow-hidden"
11924
11938
  },
11925
- "Update"
11926
- ))));
11927
- }
11928
- const PasswordScreenPlugin = createScreen({
11929
- name: "Change Password",
11930
- Component: UpdatePassword,
11931
- Icon: MdVpnKey,
11932
- layout: "fullscreen",
11933
- navCategory: "Account"
11934
- });
11935
- function createCloudConfig({
11936
- ...options
11937
- }) {
11938
- return {
11939
- __type: "cloud-config",
11940
- Icon: MdOutlineCloud,
11941
- ...options
11942
- };
11943
- }
11939
+ children
11940
+ );
11941
+ };
11944
11942
  const DEFAULT_FIELDS = [
11945
11943
  TextFieldPlugin,
11946
11944
  TextareaFieldPlugin,
@@ -12028,7 +12026,7 @@ class TinaCMS extends CMS {
12028
12026
  name: "Support",
12029
12027
  link: {
12030
12028
  text: "Support",
12031
- href: "https:/tina.io/docs/support"
12029
+ href: "https://tina.io/docs/support"
12032
12030
  },
12033
12031
  Icon: MdOutlineHelpOutline
12034
12032
  })
@@ -32326,8 +32324,8 @@ This will work when developing locally but NOT when deployed to production.
32326
32324
  return client.request(query, { variables });
32327
32325
  };
32328
32326
  const GetCMS = ({ children }) => {
32327
+ const cms = useCMS$1();
32329
32328
  try {
32330
- const cms = useCMS$1();
32331
32329
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(cms));
32332
32330
  } catch (e) {
32333
32331
  return null;
@@ -33735,22 +33733,28 @@ const GetCollection = ({
33735
33733
  search
33736
33734
  }) => {
33737
33735
  const navigate = useNavigate();
33738
- const { collection, loading, error, reFetchCollection, collectionExtra } = search ? useSearchCollection(
33739
- cms,
33740
- collectionName,
33741
- includeDocuments,
33742
- folder,
33743
- startCursor || "",
33744
- search
33745
- ) : useGetCollection(
33746
- cms,
33747
- collectionName,
33748
- includeDocuments,
33749
- folder,
33750
- startCursor || "",
33751
- sortKey,
33752
- filterArgs
33753
- ) || {};
33736
+ const { collection, loading, error, reFetchCollection, collectionExtra } = search ? (
33737
+ // biome-ignore lint/correctness/useHookAtTopLevel: not ready to fix these yet
33738
+ useSearchCollection(
33739
+ cms,
33740
+ collectionName,
33741
+ includeDocuments,
33742
+ folder,
33743
+ startCursor || "",
33744
+ search
33745
+ )
33746
+ ) : (
33747
+ // biome-ignore lint/correctness/useHookAtTopLevel: not ready to fix these yet
33748
+ useGetCollection(
33749
+ cms,
33750
+ collectionName,
33751
+ includeDocuments,
33752
+ folder,
33753
+ startCursor || "",
33754
+ sortKey,
33755
+ filterArgs
33756
+ ) || {}
33757
+ );
33754
33758
  useEffect(() => {
33755
33759
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
33756
33760
  if (loading)
@@ -35099,3 +35103,4 @@ export {
35099
35103
  wrapFieldWithNoHeader,
35100
35104
  wrapFieldsWithMeta
35101
35105
  };
35106
+ //# sourceMappingURL=index.mjs.map