tinacms 2.7.5 → 2.7.6

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