tinacms 0.0.0-d240606-20250315175410 → 0.0.0-d28d795-20250427004334

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -43,6 +43,7 @@ import { twMerge } from "tailwind-merge";
43
43
  import { Command as Command$1 } from "cmdk";
44
44
  import { isHotkey } from "is-hotkey";
45
45
  import { Transforms, Element, Range, Path, Node, Editor as Editor$1 } from "slate";
46
+ import { useWindowWidth } from "@react-hook/window-size";
46
47
  import get from "lodash.get";
47
48
  import moment from "moment";
48
49
  import { formatDistanceToNow } from "date-fns";
@@ -52,14 +53,13 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
52
53
  import { ELEMENT_PARAGRAPH as ELEMENT_PARAGRAPH$1 } from "@udecode/plate-paragraph";
53
54
  import { ELEMENT_BLOCKQUOTE as ELEMENT_BLOCKQUOTE$1 } from "@udecode/plate-block-quote";
54
55
  import { useFloatingToolbarState, offset, flip, useFloatingToolbar } from "@udecode/plate-floating";
55
- import { useWindowWidth } from "@react-hook/window-size";
56
56
  import { getIntrospectionQuery, buildClientSchema, print, parse as parse$3, buildSchema } from "graphql";
57
- import gql from "graphql-tag";
58
57
  import { TinaSchema, addNamespaceToSchema, parseURL, resolveForm, normalizePath, validateSchema } from "@tinacms/schema-tools";
59
58
  import { NAMER, resolveField } from "@tinacms/schema-tools";
59
+ import gql from "graphql-tag";
60
60
  import { diff } from "@graphql-inspector/core";
61
61
  import * as yup from "yup";
62
- import { NavLink, useNavigate, useLocation, useParams, Link, useSearchParams, HashRouter, Routes, Route } from "react-router-dom";
62
+ import { NavLink, useLocation, useNavigate, useParams, Link, useSearchParams, HashRouter, Routes, Route } from "react-router-dom";
63
63
  import { stringifyMDX } from "@tinacms/mdx";
64
64
  const ModalProvider = ({ children }) => {
65
65
  const [modalRootContainerRef, setModalRootContainerRef] = useState(
@@ -4430,36 +4430,6 @@ function MdOutlineArrowBackIos(props) {
4430
4430
  function MdOutlinePerson(props) {
4431
4431
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0V0z" }, "child": [] }, { "tag": "path", "attr": { "d": "M12 6c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2m0 10c2.7 0 5.8 1.29 6 2H6c.23-.72 3.31-2 6-2m0-12C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 10c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }, "child": [] }] })(props);
4432
4432
  }
4433
- const BranchContext = React.createContext({
4434
- currentBranch: null,
4435
- setCurrentBranch: (branch) => {
4436
- console.warn("BranchContext not initialized");
4437
- }
4438
- });
4439
- const BranchDataProvider = ({
4440
- currentBranch,
4441
- setCurrentBranch,
4442
- children
4443
- }) => {
4444
- return /* @__PURE__ */ React.createElement(
4445
- BranchContext.Provider,
4446
- {
4447
- value: {
4448
- currentBranch,
4449
- setCurrentBranch
4450
- }
4451
- },
4452
- children
4453
- );
4454
- };
4455
- const useBranchData = () => {
4456
- const branchData = React.useContext(BranchContext);
4457
- const { dispatch } = useEvent("branch:change");
4458
- React.useEffect(() => {
4459
- dispatch({ branchName: branchData.currentBranch });
4460
- }, [branchData.currentBranch]);
4461
- return branchData;
4462
- };
4463
4433
  const textFieldClasses = "shadow-inner focus:shadow-outline focus:border-blue-500 focus:outline-none block text-base placeholder:text-gray-300 px-3 py-2 text-gray-600 w-full bg-white border border-gray-200 transition-all ease-out duration-150 focus:text-gray-900 rounded-md";
4464
4434
  const disabledClasses$1 = "opacity-50 pointer-events-none cursor-not-allowed";
4465
4435
  const BaseTextField = React.forwardRef(({ className, disabled, ...rest }, ref) => {
@@ -8063,9 +8033,6 @@ const PasswordFieldPlugin = {
8063
8033
  },
8064
8034
  parse: parse$2
8065
8035
  };
8066
- function GrCircleQuestion(props) {
8067
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "strokeWidth": "2", "d": "M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,15 L12,14 C12,13 12,12.5 13,12 C14,11.5 15,11 15,9.5 C15,8.5 14,7 12,7 C10,7 9,8.26413718 9,10 M12,16 L12,18" }, "child": [] }] })(props);
8068
- }
8069
8036
  function AiFillWarning(props) {
8070
8037
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 1024 1024" }, "child": [{ "tag": "path", "attr": { "d": "M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zM480 416c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v184c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V416zm32 352a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z" }, "child": [] }] })(props);
8071
8038
  }
@@ -8084,6 +8051,39 @@ function FaSpinner(props) {
8084
8051
  function FaUnlock(props) {
8085
8052
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 448 512" }, "child": [{ "tag": "path", "attr": { "d": "M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z" }, "child": [] }] })(props);
8086
8053
  }
8054
+ function GrCircleQuestion(props) {
8055
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "strokeWidth": "2", "d": "M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,15 L12,14 C12,13 12,12.5 13,12 C14,11.5 15,11 15,9.5 C15,8.5 14,7 12,7 C10,7 9,8.26413718 9,10 M12,16 L12,18" }, "child": [] }] })(props);
8056
+ }
8057
+ const BranchContext = React.createContext({
8058
+ currentBranch: null,
8059
+ setCurrentBranch: (branch) => {
8060
+ console.warn("BranchContext not initialized");
8061
+ }
8062
+ });
8063
+ const BranchDataProvider = ({
8064
+ currentBranch,
8065
+ setCurrentBranch,
8066
+ children
8067
+ }) => {
8068
+ return /* @__PURE__ */ React.createElement(
8069
+ BranchContext.Provider,
8070
+ {
8071
+ value: {
8072
+ currentBranch,
8073
+ setCurrentBranch
8074
+ }
8075
+ },
8076
+ children
8077
+ );
8078
+ };
8079
+ const useBranchData = () => {
8080
+ const branchData = React.useContext(BranchContext);
8081
+ const { dispatch } = useEvent("branch:change");
8082
+ React.useEffect(() => {
8083
+ dispatch({ branchName: branchData.currentBranch });
8084
+ }, [branchData.currentBranch]);
8085
+ return branchData;
8086
+ };
8087
8087
  function formatBranchName$1(str) {
8088
8088
  const pattern = /[^/\w-]+/g;
8089
8089
  const formattedStr = str.replace(pattern, "");
@@ -8182,7 +8182,7 @@ const BranchSwitcherLegacy = ({
8182
8182
  className: "transition-all duration-150 ease-out text-blue-600 hover:text-blue-400 hover:underline no-underline",
8183
8183
  href: "https://tina.io/docs/tina-cloud/"
8184
8184
  },
8185
- "Learn more about moving to production with Tina Cloud."
8185
+ "Learn more about moving to production with TinaCloud."
8186
8186
  )), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement(
8187
8187
  Button$1,
8188
8188
  {
@@ -8418,7 +8418,7 @@ const EditoralBranchSwitcher = ({
8418
8418
  className: "transition-all duration-150 ease-out text-blue-600 hover:text-blue-400 hover:underline no-underline",
8419
8419
  href: "https://tina.io/docs/tina-cloud/"
8420
8420
  },
8421
- "Learn more about moving to production with Tina Cloud."
8421
+ "Learn more about moving to production with TinaCloud."
8422
8422
  )), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement(
8423
8423
  Button$1,
8424
8424
  {
@@ -9450,7 +9450,7 @@ const E_BAD_ROUTE = new MediaListError({
9450
9450
  });
9451
9451
  new MediaListError({
9452
9452
  title: "An Error Occurred",
9453
- message: "Something went wrong accessing your media from Tina Cloud.",
9453
+ message: "Something went wrong accessing your media from TinaCloud.",
9454
9454
  docsLink: ""
9455
9455
  // TODO
9456
9456
  });
@@ -9635,7 +9635,7 @@ let Alerts$1 = class Alerts {
9635
9635
  return this.add("error", message, timeout);
9636
9636
  }
9637
9637
  };
9638
- const NoFormsPlaceholder = () => /* @__PURE__ */ React.createElement(
9638
+ const SidebarLoadingPlaceholder = () => /* @__PURE__ */ React.createElement(
9639
9639
  "div",
9640
9640
  {
9641
9641
  className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
@@ -9648,25 +9648,8 @@ const NoFormsPlaceholder = () => /* @__PURE__ */ React.createElement(
9648
9648
  animationDuration: "150ms"
9649
9649
  }
9650
9650
  },
9651
- /* @__PURE__ */ React.createElement(Emoji$1, { className: "pb-5" }, "🔎"),
9652
- /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Looks like there's ", /* @__PURE__ */ React.createElement("br", null), "nothing to edit on ", /* @__PURE__ */ React.createElement("br", null), "this page."),
9653
- /* @__PURE__ */ React.createElement("p", { className: "block" }, /* @__PURE__ */ React.createElement(
9654
- Button$1,
9655
- {
9656
- href: "https://tina.io/docs/tinacms-context/",
9657
- target: "_blank",
9658
- as: "a"
9659
- },
9660
- /* @__PURE__ */ React.createElement(Emoji$1, { className: "mr-1.5" }, "📖"),
9661
- " Contextual Editing"
9662
- ))
9663
- );
9664
- const Emoji$1 = ({ className = "", ...props }) => /* @__PURE__ */ React.createElement(
9665
- "span",
9666
- {
9667
- className: `text-[24px] leading-none inline-block ${className}`,
9668
- ...props
9669
- }
9651
+ /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Please wait while TinaCMS", /* @__PURE__ */ React.createElement("br", null), "loads your content"),
9652
+ /* @__PURE__ */ React.createElement(LoadingDots, { color: "var(--tina-color-primary)" })
9670
9653
  );
9671
9654
  class SidebarState {
9672
9655
  constructor(events, options = {}) {
@@ -9681,7 +9664,7 @@ class SidebarState {
9681
9664
  };
9682
9665
  this.position = options.position || "displace";
9683
9666
  this.renderNav = options.renderNav || true;
9684
- this.placeholder = options.placeholder || NoFormsPlaceholder;
9667
+ this.loadingPlaceholder = options.placeholder || SidebarLoadingPlaceholder;
9685
9668
  if ((_a = options.buttons) == null ? void 0 : _a.save) {
9686
9669
  this.buttons.save = options.buttons.save;
9687
9670
  }
@@ -9755,238 +9738,6 @@ const ModalLayout = ({ children, name, close: close2, layout }) => {
9755
9738
  children
9756
9739
  )));
9757
9740
  };
9758
- const Item = ({
9759
- item,
9760
- depth,
9761
- setActiveFormId
9762
- }) => {
9763
- const cms = useCMS();
9764
- const depths = ["pl-6", "pl-10", "pl-14"];
9765
- const form = React.useMemo(
9766
- () => cms.state.forms.find(({ tinaForm }) => item.formId === tinaForm.id),
9767
- [item.formId]
9768
- );
9769
- return /* @__PURE__ */ React.createElement(
9770
- "button",
9771
- {
9772
- type: "button",
9773
- key: item.path,
9774
- onClick: () => setActiveFormId(item.formId),
9775
- 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`
9776
- },
9777
- /* @__PURE__ */ React.createElement(BiEdit, { className: "opacity-70 w-5 h-auto text-blue-500 flex-none" }),
9778
- /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex flex-col gap-0.5 items-start" }, /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 font-sans text-xs font-semibold text-gray-700 whitespace-normal" }, form.tinaForm.label), /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 text-base truncate leading-tight text-gray-600" }, form.tinaForm.id))
9779
- );
9780
- };
9781
- const FormListItem = ({
9782
- item,
9783
- depth,
9784
- setActiveFormId
9785
- }) => {
9786
- var _a;
9787
- return /* @__PURE__ */ React.createElement("div", { className: "divide-y divide-gray-200" }, /* @__PURE__ */ React.createElement(Item, { setActiveFormId, item, depth }), item.subItems && /* @__PURE__ */ React.createElement("ul", { className: "divide-y divide-gray-200" }, (_a = item.subItems) == null ? void 0 : _a.map((subItem) => {
9788
- if (subItem.type === "document") {
9789
- return /* @__PURE__ */ React.createElement("li", { key: subItem.formId }, /* @__PURE__ */ React.createElement(
9790
- Item,
9791
- {
9792
- setActiveFormId,
9793
- depth: depth + 1,
9794
- item: subItem
9795
- }
9796
- ));
9797
- }
9798
- })));
9799
- };
9800
- const FormLists = (props) => {
9801
- const cms = useCMS();
9802
- return /* @__PURE__ */ React.createElement(
9803
- Transition,
9804
- {
9805
- appear: true,
9806
- show: true,
9807
- as: "div",
9808
- enter: "transition-all ease-out duration-150",
9809
- enterFrom: "opacity-0 -translate-x-1/2",
9810
- enterTo: "opacity-100",
9811
- leave: "transition-all ease-out duration-150",
9812
- leaveFrom: "opacity-100",
9813
- leaveTo: "opacity-0 -translate-x-1/2"
9814
- },
9815
- cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}`, className: "pt-16" }, /* @__PURE__ */ React.createElement(
9816
- FormList,
9817
- {
9818
- isEditing: props.isEditing,
9819
- setActiveFormId: (id) => {
9820
- cms.dispatch({ type: "forms:set-active-form-id", value: id });
9821
- },
9822
- formList
9823
- }
9824
- )))
9825
- );
9826
- };
9827
- const FormList = (props) => {
9828
- const cms = useCMS();
9829
- const listItems = React.useMemo(() => {
9830
- var _a;
9831
- const orderedListItems = [];
9832
- const globalItems = [];
9833
- const topItems = [];
9834
- props.formList.items.forEach((item) => {
9835
- if (item.type === "document") {
9836
- const form = cms.state.forms.find(
9837
- ({ tinaForm }) => tinaForm.id === item.formId
9838
- );
9839
- if (form.tinaForm.global) {
9840
- globalItems.push(item);
9841
- } else {
9842
- orderedListItems.push(item);
9843
- }
9844
- } else {
9845
- orderedListItems.push(item);
9846
- }
9847
- });
9848
- if (((_a = orderedListItems[0]) == null ? void 0 : _a.type) === "document") {
9849
- topItems.push({ type: "list", label: "Documents" });
9850
- }
9851
- let extra = [];
9852
- if (globalItems.length) {
9853
- extra = [{ type: "list", label: "Global Documents" }, ...globalItems];
9854
- }
9855
- return [...topItems, ...orderedListItems, ...extra];
9856
- }, [JSON.stringify(props.formList.items)]);
9857
- return /* @__PURE__ */ React.createElement("ul", null, /* @__PURE__ */ React.createElement("li", { className: "divide-y divide-gray-200" }, listItems.map((item, index) => {
9858
- if (item.type === "list") {
9859
- return /* @__PURE__ */ React.createElement(
9860
- "div",
9861
- {
9862
- key: item.label,
9863
- className: `relative group text-left w-full bg-white shadow-sm
9864
- 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"}`
9865
- },
9866
- /* @__PURE__ */ React.createElement(
9867
- "span",
9868
- {
9869
- className: "text-sm tracking-wide font-bold text-gray-700 uppercase"
9870
- },
9871
- item.label
9872
- )
9873
- );
9874
- }
9875
- return /* @__PURE__ */ React.createElement(
9876
- FormListItem,
9877
- {
9878
- setActiveFormId: (id) => props.setActiveFormId(id),
9879
- key: item.formId,
9880
- item,
9881
- depth: 0
9882
- }
9883
- );
9884
- })));
9885
- };
9886
- const FormsView = ({
9887
- children
9888
- }) => {
9889
- const cms = useCMS$1();
9890
- const { setFormIsPristine } = React.useContext(SidebarContext);
9891
- const isMultiform = cms.state.forms.length > 1;
9892
- const activeForm = cms.state.forms.find(
9893
- ({ tinaForm }) => tinaForm.id === cms.state.activeFormId
9894
- );
9895
- const isEditing = !!activeForm;
9896
- if (!cms.state.formLists.length) {
9897
- return /* @__PURE__ */ React.createElement(React.Fragment, null, " ", children, " ");
9898
- }
9899
- if (isMultiform && !activeForm) {
9900
- return /* @__PURE__ */ React.createElement(FormLists, { isEditing });
9901
- }
9902
- const formMetas = cms.plugins.all("form:meta");
9903
- return /* @__PURE__ */ React.createElement(React.Fragment, null, activeForm && /* @__PURE__ */ React.createElement(FormWrapper$1, { isEditing, isMultiform }, isMultiform && /* @__PURE__ */ React.createElement(MultiformFormHeader, { activeForm }), !isMultiform && /* @__PURE__ */ React.createElement(FormHeader, { activeForm }), formMetas == null ? void 0 : formMetas.map((meta) => /* @__PURE__ */ React.createElement(React.Fragment, { key: meta.name }, /* @__PURE__ */ React.createElement(meta.Component, null))), /* @__PURE__ */ React.createElement(FormBuilder, { form: activeForm, onPristineChange: setFormIsPristine })));
9904
- };
9905
- const FormWrapper$1 = ({ isEditing, children }) => {
9906
- return /* @__PURE__ */ React.createElement(
9907
- "div",
9908
- {
9909
- className: "flex-1 flex flex-col flex-nowrap overflow-hidden h-full w-full relative bg-white",
9910
- style: isEditing ? {
9911
- transform: "none",
9912
- animationName: "fly-in-left",
9913
- animationDuration: "150ms",
9914
- animationDelay: "0",
9915
- animationIterationCount: 1,
9916
- animationTimingFunction: "ease-out"
9917
- } : {
9918
- transform: "translate3d(100%, 0, 0)"
9919
- }
9920
- },
9921
- children
9922
- );
9923
- };
9924
- const MultiformFormHeader = ({
9925
- activeForm
9926
- }) => {
9927
- const cms = useCMS$1();
9928
- const { formIsPristine } = React.useContext(SidebarContext);
9929
- return /* @__PURE__ */ React.createElement(
9930
- "div",
9931
- {
9932
- className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
9933
- },
9934
- /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
9935
- "button",
9936
- {
9937
- type: "button",
9938
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
9939
- onClick: () => {
9940
- const state = activeForm.tinaForm.finalForm.getState();
9941
- if (state.invalid === true) {
9942
- cms.alerts.error("Cannot navigate away from an invalid form.");
9943
- } else {
9944
- cms.dispatch({ type: "forms:set-active-form-id", value: null });
9945
- }
9946
- }
9947
- },
9948
- /* @__PURE__ */ React.createElement(BiDotsVertical, { className: "h-auto w-5 inline-block opacity-70" })
9949
- ), /* @__PURE__ */ React.createElement(
9950
- "button",
9951
- {
9952
- type: "button",
9953
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
9954
- onClick: () => {
9955
- const collectionName = cms.api.tina.schema.getCollectionByFullPath(
9956
- cms.state.activeFormId
9957
- ).name;
9958
- window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
9959
- }
9960
- },
9961
- /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
9962
- ), /* @__PURE__ */ React.createElement("span", { className: "opacity-30 text-sm leading-tight whitespace-nowrap flex-0" }, "/"), /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, activeForm.tinaForm.label || activeForm.tinaForm.id), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
9963
- );
9964
- };
9965
- const FormHeader = ({ activeForm }) => {
9966
- const { formIsPristine } = React.useContext(SidebarContext);
9967
- const cms = useCMS$1();
9968
- const shortFormLabel = activeForm.tinaForm.label ? activeForm.tinaForm.label.replace(/^.*[\\\/]/, "") : false;
9969
- return /* @__PURE__ */ React.createElement(
9970
- "div",
9971
- {
9972
- className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
9973
- },
9974
- /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
9975
- "button",
9976
- {
9977
- type: "button",
9978
- className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
9979
- onClick: () => {
9980
- const collectionName = cms.api.tina.schema.getCollectionByFullPath(
9981
- cms.state.activeFormId
9982
- ).name;
9983
- window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
9984
- }
9985
- },
9986
- /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
9987
- ), shortFormLabel && /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, shortFormLabel), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
9988
- );
9989
- };
9990
9741
  function ImFilesEmpty(props) {
9991
9742
  return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 16 16" }, "child": [{ "tag": "path", "attr": { "d": "M14.341 5.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.689 0.561 1.25 1.25 1.25h9.5c0.689 0 1.25-0.561 1.25-1.25v-7.75c0-0.224-0.068-0.615-0.659-1.421zM12.271 4.729c0.48 0.48 0.856 0.912 1.134 1.271h-2.406v-2.405c0.359 0.278 0.792 0.654 1.271 1.134v0zM14 14.75c0 0.136-0.114 0.25-0.25 0.25h-9.5c-0.136 0-0.25-0.114-0.25-0.25v-11.5c0-0.135 0.114-0.25 0.25-0.25 0 0 5.749-0 5.75 0v3.5c0 0.276 0.224 0.5 0.5 0.5h3.5v7.75z" }, "child": [] }, { "tag": "path", "attr": { "d": "M9.421 0.659c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.604 0.43 1.109 1 1.225v-12.725c0-0.135 0.115-0.25 0.25-0.25h7.607c-0.151-0.124-0.297-0.238-0.437-0.341z" }, "child": [] }] })(props);
9992
9743
  }
@@ -10229,7 +9980,7 @@ const SyncStatus = ({ cms, setEventsOpen }) => {
10229
9980
  "Event Log"
10230
9981
  ));
10231
9982
  };
10232
- const version = "2.7.2";
9983
+ const version = "2.7.5";
10233
9984
  const Nav = ({
10234
9985
  isLocalMode,
10235
9986
  className = "",
@@ -10471,6 +10222,293 @@ const ResizeHandle = () => {
10471
10222
  /* @__PURE__ */ React.createElement("span", { className: "absolute top-1/2 left-1/2 h-4/6 w-px bg-gray-200 transform -translate-y-1/2 -translate-x-1/2 opacity-30 transition-opacity duration-150 ease-out group-hover:opacity-100" })
10472
10223
  );
10473
10224
  };
10225
+ const Item = ({
10226
+ item,
10227
+ depth,
10228
+ setActiveFormId
10229
+ }) => {
10230
+ const cms = useCMS();
10231
+ const depths = ["pl-6", "pl-10", "pl-14"];
10232
+ const form = React.useMemo(
10233
+ () => cms.state.forms.find(({ tinaForm }) => item.formId === tinaForm.id),
10234
+ [item.formId]
10235
+ );
10236
+ return /* @__PURE__ */ React.createElement(
10237
+ "button",
10238
+ {
10239
+ type: "button",
10240
+ key: item.path,
10241
+ onClick: () => setActiveFormId(item.formId),
10242
+ className: `${depths[depth] || "pl-12"} pr-6 py-3 w-full h-full bg-transparent border-none text-lg text-gray-700 group hover:bg-gray-50 transition-all ease-out duration-150 flex items-center justify-between gap-2`
10243
+ },
10244
+ /* @__PURE__ */ React.createElement(BiEdit, { className: "opacity-70 w-5 h-auto text-blue-500 flex-none" }),
10245
+ /* @__PURE__ */ React.createElement("div", { className: "flex-1 flex flex-col gap-0.5 items-start" }, /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 font-sans text-xs font-semibold text-gray-700 whitespace-normal" }, form.tinaForm.label), /* @__PURE__ */ React.createElement("div", { className: "group-hover:text-blue-500 text-base truncate leading-tight text-gray-600" }, form.tinaForm.id))
10246
+ );
10247
+ };
10248
+ const FormListItem = ({
10249
+ item,
10250
+ depth,
10251
+ setActiveFormId
10252
+ }) => {
10253
+ var _a;
10254
+ return /* @__PURE__ */ React.createElement("div", { className: "divide-y divide-gray-200" }, /* @__PURE__ */ React.createElement(Item, { setActiveFormId, item, depth }), item.subItems && /* @__PURE__ */ React.createElement("ul", { className: "divide-y divide-gray-200" }, (_a = item.subItems) == null ? void 0 : _a.map((subItem) => {
10255
+ if (subItem.type === "document") {
10256
+ return /* @__PURE__ */ React.createElement("li", { key: subItem.formId }, /* @__PURE__ */ React.createElement(
10257
+ Item,
10258
+ {
10259
+ setActiveFormId,
10260
+ depth: depth + 1,
10261
+ item: subItem
10262
+ }
10263
+ ));
10264
+ }
10265
+ })));
10266
+ };
10267
+ const FormLists = (props) => {
10268
+ const cms = useCMS();
10269
+ return /* @__PURE__ */ React.createElement(
10270
+ Transition,
10271
+ {
10272
+ appear: true,
10273
+ show: true,
10274
+ as: "div",
10275
+ enter: "transition-all ease-out duration-150",
10276
+ enterFrom: "opacity-0 -translate-x-1/2",
10277
+ enterTo: "opacity-100",
10278
+ leave: "transition-all ease-out duration-150",
10279
+ leaveFrom: "opacity-100",
10280
+ leaveTo: "opacity-0 -translate-x-1/2"
10281
+ },
10282
+ cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}`, className: "pt-16" }, /* @__PURE__ */ React.createElement(
10283
+ FormList,
10284
+ {
10285
+ isEditing: props.isEditing,
10286
+ setActiveFormId: (id) => {
10287
+ cms.dispatch({ type: "forms:set-active-form-id", value: id });
10288
+ },
10289
+ formList
10290
+ }
10291
+ )))
10292
+ );
10293
+ };
10294
+ const FormList = (props) => {
10295
+ const cms = useCMS();
10296
+ const listItems = React.useMemo(() => {
10297
+ var _a;
10298
+ const orderedListItems = [];
10299
+ const globalItems = [];
10300
+ const topItems = [];
10301
+ props.formList.items.forEach((item) => {
10302
+ if (item.type === "document") {
10303
+ const form = cms.state.forms.find(
10304
+ ({ tinaForm }) => tinaForm.id === item.formId
10305
+ );
10306
+ if (form.tinaForm.global) {
10307
+ globalItems.push(item);
10308
+ } else {
10309
+ orderedListItems.push(item);
10310
+ }
10311
+ } else {
10312
+ orderedListItems.push(item);
10313
+ }
10314
+ });
10315
+ if (((_a = orderedListItems[0]) == null ? void 0 : _a.type) === "document") {
10316
+ topItems.push({ type: "list", label: "Documents" });
10317
+ }
10318
+ let extra = [];
10319
+ if (globalItems.length) {
10320
+ extra = [{ type: "list", label: "Global Documents" }, ...globalItems];
10321
+ }
10322
+ return [...topItems, ...orderedListItems, ...extra];
10323
+ }, [JSON.stringify(props.formList.items)]);
10324
+ return /* @__PURE__ */ React.createElement("ul", null, /* @__PURE__ */ React.createElement("li", { className: "divide-y divide-gray-200" }, listItems.map((item, index) => {
10325
+ if (item.type === "list") {
10326
+ return /* @__PURE__ */ React.createElement(
10327
+ "div",
10328
+ {
10329
+ key: item.label,
10330
+ className: `relative group text-left w-full bg-white shadow-sm
10331
+ border-gray-100 px-6 -mt-px pb-3 ${index > 0 ? "pt-6 bg-gradient-to-b from-gray-50 via-white to-white" : "pt-3"}`
10332
+ },
10333
+ /* @__PURE__ */ React.createElement(
10334
+ "span",
10335
+ {
10336
+ className: "text-sm tracking-wide font-bold text-gray-700 uppercase"
10337
+ },
10338
+ item.label
10339
+ )
10340
+ );
10341
+ }
10342
+ return /* @__PURE__ */ React.createElement(
10343
+ FormListItem,
10344
+ {
10345
+ setActiveFormId: (id) => props.setActiveFormId(id),
10346
+ key: item.formId,
10347
+ item,
10348
+ depth: 0
10349
+ }
10350
+ );
10351
+ })));
10352
+ };
10353
+ const SidebarNoFormsPlaceholder = () => /* @__PURE__ */ React.createElement(
10354
+ "div",
10355
+ {
10356
+ className: "relative flex flex-col items-center justify-center text-center p-5 pb-16 w-full h-full overflow-y-auto",
10357
+ style: {
10358
+ animationName: "fade-in",
10359
+ animationDelay: "300ms",
10360
+ animationTimingFunction: "ease-out",
10361
+ animationIterationCount: 1,
10362
+ animationFillMode: "both",
10363
+ animationDuration: "150ms"
10364
+ }
10365
+ },
10366
+ /* @__PURE__ */ React.createElement("p", { className: "block pb-5" }, "Looks like there's ", /* @__PURE__ */ React.createElement("br", null), "nothing to edit on ", /* @__PURE__ */ React.createElement("br", null), "this page."),
10367
+ /* @__PURE__ */ React.createElement("p", { className: "block pt-5" }, /* @__PURE__ */ React.createElement(
10368
+ Button$1,
10369
+ {
10370
+ href: "https://tina.io/docs/contextual-editing/overview",
10371
+ target: "_blank",
10372
+ as: "a"
10373
+ },
10374
+ /* @__PURE__ */ React.createElement(Emoji$1, { className: "mr-1.5" }, "📖"),
10375
+ " Contextual Editing Docs"
10376
+ ))
10377
+ );
10378
+ const Emoji$1 = ({ className = "", ...props }) => /* @__PURE__ */ React.createElement(
10379
+ "span",
10380
+ {
10381
+ className: `text-[24px] leading-none inline-block ${className}`,
10382
+ ...props
10383
+ }
10384
+ );
10385
+ const minimumTimeToShowLoadingIndicator = 1e3;
10386
+ const FormsView = ({ loadingPlaceholder } = {}) => {
10387
+ const cms = useCMS$1();
10388
+ const { setFormIsPristine } = React.useContext(SidebarContext);
10389
+ const [isShowingLoading, setIsShowingLoading] = React.useState(true);
10390
+ const [initialLoadComplete, setInitialLoadComplete] = React.useState(false);
10391
+ React.useEffect(() => {
10392
+ if (cms.state.isLoadingContent) {
10393
+ setIsShowingLoading(true);
10394
+ const timer = setTimeout(() => {
10395
+ if (!cms.state.isLoadingContent) {
10396
+ setIsShowingLoading(false);
10397
+ setInitialLoadComplete(true);
10398
+ }
10399
+ }, minimumTimeToShowLoadingIndicator);
10400
+ return () => clearTimeout(timer);
10401
+ } else {
10402
+ const timer = setTimeout(() => {
10403
+ setIsShowingLoading(false);
10404
+ setInitialLoadComplete(true);
10405
+ }, minimumTimeToShowLoadingIndicator);
10406
+ return () => clearTimeout(timer);
10407
+ }
10408
+ }, [cms.state.isLoadingContent]);
10409
+ if (isShowingLoading || !initialLoadComplete) {
10410
+ const LoadingPlaceholder = loadingPlaceholder || SidebarLoadingPlaceholder;
10411
+ return /* @__PURE__ */ React.createElement(LoadingPlaceholder, null);
10412
+ }
10413
+ if (!cms.state.formLists.length) {
10414
+ return /* @__PURE__ */ React.createElement(SidebarNoFormsPlaceholder, null);
10415
+ }
10416
+ const isMultiform = cms.state.forms.length > 1;
10417
+ const activeForm = cms.state.forms.find(
10418
+ ({ tinaForm }) => tinaForm.id === cms.state.activeFormId
10419
+ );
10420
+ const isEditing = !!activeForm;
10421
+ if (isMultiform && !activeForm) {
10422
+ return /* @__PURE__ */ React.createElement(FormLists, { isEditing });
10423
+ }
10424
+ const formMetas = cms.plugins.all("form:meta");
10425
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, activeForm && /* @__PURE__ */ React.createElement(FormWrapper$1, { isEditing, isMultiform }, isMultiform && /* @__PURE__ */ React.createElement(MultiformFormHeader, { activeForm }), !isMultiform && /* @__PURE__ */ React.createElement(FormHeader, { activeForm }), formMetas == null ? void 0 : formMetas.map((meta) => /* @__PURE__ */ React.createElement(React.Fragment, { key: meta.name }, /* @__PURE__ */ React.createElement(meta.Component, null))), /* @__PURE__ */ React.createElement(FormBuilder, { form: activeForm, onPristineChange: setFormIsPristine })));
10426
+ };
10427
+ const FormWrapper$1 = ({ isEditing, children }) => {
10428
+ return /* @__PURE__ */ React.createElement(
10429
+ "div",
10430
+ {
10431
+ className: "flex-1 flex flex-col flex-nowrap overflow-hidden h-full w-full relative bg-white",
10432
+ style: isEditing ? {
10433
+ transform: "none",
10434
+ animationName: "fly-in-left",
10435
+ animationDuration: "150ms",
10436
+ animationDelay: "0",
10437
+ animationIterationCount: 1,
10438
+ animationTimingFunction: "ease-out"
10439
+ } : {
10440
+ transform: "translate3d(100%, 0, 0)"
10441
+ }
10442
+ },
10443
+ children
10444
+ );
10445
+ };
10446
+ const MultiformFormHeader = ({
10447
+ activeForm
10448
+ }) => {
10449
+ const cms = useCMS$1();
10450
+ const { formIsPristine } = React.useContext(SidebarContext);
10451
+ return /* @__PURE__ */ React.createElement(
10452
+ "div",
10453
+ {
10454
+ className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
10455
+ },
10456
+ /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
10457
+ "button",
10458
+ {
10459
+ type: "button",
10460
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10461
+ onClick: () => {
10462
+ const state = activeForm.tinaForm.finalForm.getState();
10463
+ if (state.invalid === true) {
10464
+ cms.alerts.error("Cannot navigate away from an invalid form.");
10465
+ } else {
10466
+ cms.dispatch({ type: "forms:set-active-form-id", value: null });
10467
+ }
10468
+ }
10469
+ },
10470
+ /* @__PURE__ */ React.createElement(BiDotsVertical, { className: "h-auto w-5 inline-block opacity-70" })
10471
+ ), /* @__PURE__ */ React.createElement(
10472
+ "button",
10473
+ {
10474
+ type: "button",
10475
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10476
+ onClick: () => {
10477
+ const collectionName = cms.api.tina.schema.getCollectionByFullPath(
10478
+ cms.state.activeFormId
10479
+ ).name;
10480
+ window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
10481
+ }
10482
+ },
10483
+ /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
10484
+ ), /* @__PURE__ */ React.createElement("span", { className: "opacity-30 text-sm leading-tight whitespace-nowrap flex-0" }, "/"), /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, activeForm.tinaForm.label || activeForm.tinaForm.id), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
10485
+ );
10486
+ };
10487
+ const FormHeader = ({ activeForm }) => {
10488
+ const { formIsPristine } = React.useContext(SidebarContext);
10489
+ const cms = useCMS$1();
10490
+ const shortFormLabel = activeForm.tinaForm.label ? activeForm.tinaForm.label.replace(/^.*[\\\/]/, "") : false;
10491
+ return /* @__PURE__ */ React.createElement(
10492
+ "div",
10493
+ {
10494
+ className: "pt-18 pb-4 px-6 border-b border-gray-200 bg-gradient-to-t from-white to-gray-50"
10495
+ },
10496
+ /* @__PURE__ */ React.createElement("div", { className: "max-w-form mx-auto flex gap-2 justify-between items-center" }, /* @__PURE__ */ React.createElement(
10497
+ "button",
10498
+ {
10499
+ type: "button",
10500
+ className: "pointer-events-auto text-xs text-blue-400 hover:text-blue-500 hover:underline transition-all ease-out duration-150",
10501
+ onClick: () => {
10502
+ const collectionName = cms.api.tina.schema.getCollectionByFullPath(
10503
+ cms.state.activeFormId
10504
+ ).name;
10505
+ window.location.href = `${new URL(window.location.href).pathname}#/collections/${collectionName}/~`;
10506
+ }
10507
+ },
10508
+ /* @__PURE__ */ React.createElement(BiHomeAlt, { className: "h-auto w-5 inline-block opacity-70" })
10509
+ ), shortFormLabel && /* @__PURE__ */ React.createElement("span", { className: "block w-full text-sm leading-tight whitespace-nowrap truncate" }, shortFormLabel), /* @__PURE__ */ React.createElement(FormStatus, { pristine: formIsPristine }))
10510
+ );
10511
+ };
10474
10512
  const SidebarContext = React.createContext(null);
10475
10513
  const minPreviewWidth = 440;
10476
10514
  const minSidebarWidth = 360;
@@ -10689,7 +10727,7 @@ const Sidebar$1 = ({
10689
10727
  isLocalMode: (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.isLocalMode,
10690
10728
  branchingEnabled
10691
10729
  }
10692
- ), /* @__PURE__ */ React.createElement(FormsView, null, /* @__PURE__ */ React.createElement(sidebar.placeholder, null)), activeScreen && /* @__PURE__ */ React.createElement(
10730
+ ), /* @__PURE__ */ React.createElement(FormsView, { loadingPlaceholder: sidebar.loadingPlaceholder }), activeScreen && /* @__PURE__ */ React.createElement(
10693
10731
  ScreenPluginModal,
10694
10732
  {
10695
10733
  screen: activeScreen,
@@ -11005,6 +11043,93 @@ function createPlaceholder(name, _pr) {
11005
11043
  );
11006
11044
  };
11007
11045
  }
11046
+ function dirname(path) {
11047
+ var _a, _b;
11048
+ const pattern = new RegExp("(?<prevDir>.*)/");
11049
+ return (_b = (_a = path.match(pattern)) == null ? void 0 : _a.groups) == null ? void 0 : _b.prevDir;
11050
+ }
11051
+ const BreadcrumbButton = ({ className = "", ...props }) => /* @__PURE__ */ React__default.createElement(
11052
+ "button",
11053
+ {
11054
+ className: "capitalize transition-colors duration-150 border-0 bg-transparent hover:text-blue-500 " + className,
11055
+ ...props
11056
+ }
11057
+ );
11058
+ function Breadcrumb$1({ directory = "", setDirectory }) {
11059
+ directory = directory.replace(/^\/|\/$/g, "");
11060
+ let prevDir = dirname(directory) || "";
11061
+ if (prevDir === ".") {
11062
+ prevDir = "";
11063
+ }
11064
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex items-center text-[16px] text-gray-300" }, directory !== "" && /* @__PURE__ */ React__default.createElement(
11065
+ IconButton,
11066
+ {
11067
+ variant: "ghost",
11068
+ className: "mr-2",
11069
+ onClick: () => setDirectory(prevDir)
11070
+ },
11071
+ /* @__PURE__ */ React__default.createElement(
11072
+ LeftArrowIcon,
11073
+ {
11074
+ className: `w-7 h-auto fill-gray-300 hover:fill-gray-900 transition duration-150 ease-out`
11075
+ }
11076
+ )
11077
+ ), /* @__PURE__ */ React__default.createElement(
11078
+ BreadcrumbButton,
11079
+ {
11080
+ onClick: () => setDirectory(""),
11081
+ className: directory === "" ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"
11082
+ },
11083
+ "Media"
11084
+ ), directory && directory.split("/").map((part, index, parts) => {
11085
+ const currentDir = parts.slice(0, index + 1).join("/");
11086
+ return /* @__PURE__ */ React__default.createElement(
11087
+ BreadcrumbButton,
11088
+ {
11089
+ className: "pl-1.5 " + (index + 1 === parts.length ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"),
11090
+ key: currentDir,
11091
+ onClick: () => {
11092
+ setDirectory(currentDir);
11093
+ }
11094
+ },
11095
+ part
11096
+ );
11097
+ }));
11098
+ }
11099
+ const CopyField = ({ label, description, value }) => {
11100
+ const [copied, setCopied] = React__default.useState(false);
11101
+ const [fadeOut, setFadeOut] = React__default.useState(false);
11102
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, label && /* @__PURE__ */ React__default.createElement("label", { className: "w-full mb-1 block flex-1 text-sm font-bold leading-5 text-gray-700" }, label), /* @__PURE__ */ React__default.createElement(
11103
+ "span",
11104
+ {
11105
+ onClick: () => {
11106
+ if (copied === true)
11107
+ return;
11108
+ setCopied(true);
11109
+ setTimeout(() => {
11110
+ setFadeOut(true);
11111
+ }, 2500);
11112
+ setTimeout(() => {
11113
+ setCopied(false);
11114
+ setFadeOut(false);
11115
+ }, 3e3);
11116
+ navigator.clipboard.writeText(value);
11117
+ },
11118
+ className: `shadow-inner text-base leading-5 whitespace-normal break-all px-3 py-2 text-gray-600 w-full bg-gray-50 border border-gray-200 transition-all ease-out duration-150 rounded-md relative overflow-hidden appearance-none flex items-center w-full cursor-pointer hover:bg-white hover:text-blue-500 ${copied ? `pointer-events-none` : ``}`
11119
+ },
11120
+ /* @__PURE__ */ React__default.createElement(BiCopyAlt, { className: "relative text-blue-500 shrink-0 w-5 h-auto mr-1.5 -ml-0.5 z-20" }),
11121
+ " ",
11122
+ value,
11123
+ " ",
11124
+ copied && /* @__PURE__ */ React__default.createElement(
11125
+ "span",
11126
+ {
11127
+ className: `${fadeOut ? `opacity-0` : `opacity-100`} text-blue-500 transition-opacity duration-500 absolute right-0 w-full h-full px-3 py-2 bg-white bg-opacity-90 flex items-center justify-center text-center tracking-wide font-medium z-10`
11128
+ },
11129
+ /* @__PURE__ */ React__default.createElement("span", null, "Copied to clipboard!")
11130
+ )
11131
+ ), description && /* @__PURE__ */ React__default.createElement("p", { className: "mt-2 text-sm text-gray-500" }, description));
11132
+ };
11008
11133
  function ListMediaItem({ item, onClick, active }) {
11009
11134
  let FileIcon = BiFile;
11010
11135
  if (item.type === "dir") {
@@ -11080,59 +11205,6 @@ function GridMediaItem({ item, active, onClick }) {
11080
11205
  )
11081
11206
  );
11082
11207
  }
11083
- function dirname(path) {
11084
- var _a, _b;
11085
- const pattern = new RegExp("(?<prevDir>.*)/");
11086
- return (_b = (_a = path.match(pattern)) == null ? void 0 : _a.groups) == null ? void 0 : _b.prevDir;
11087
- }
11088
- const BreadcrumbButton = ({ className = "", ...props }) => /* @__PURE__ */ React__default.createElement(
11089
- "button",
11090
- {
11091
- className: "capitalize transition-colors duration-150 border-0 bg-transparent hover:text-blue-500 " + className,
11092
- ...props
11093
- }
11094
- );
11095
- function Breadcrumb$1({ directory = "", setDirectory }) {
11096
- directory = directory.replace(/^\/|\/$/g, "");
11097
- let prevDir = dirname(directory) || "";
11098
- if (prevDir === ".") {
11099
- prevDir = "";
11100
- }
11101
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex items-center text-[16px] text-gray-300" }, directory !== "" && /* @__PURE__ */ React__default.createElement(
11102
- IconButton,
11103
- {
11104
- variant: "ghost",
11105
- className: "mr-2",
11106
- onClick: () => setDirectory(prevDir)
11107
- },
11108
- /* @__PURE__ */ React__default.createElement(
11109
- LeftArrowIcon,
11110
- {
11111
- className: `w-7 h-auto fill-gray-300 hover:fill-gray-900 transition duration-150 ease-out`
11112
- }
11113
- )
11114
- ), /* @__PURE__ */ React__default.createElement(
11115
- BreadcrumbButton,
11116
- {
11117
- onClick: () => setDirectory(""),
11118
- className: directory === "" ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"
11119
- },
11120
- "Media"
11121
- ), directory && directory.split("/").map((part, index, parts) => {
11122
- const currentDir = parts.slice(0, index + 1).join("/");
11123
- return /* @__PURE__ */ React__default.createElement(
11124
- BreadcrumbButton,
11125
- {
11126
- className: "pl-1.5 " + (index + 1 === parts.length ? "text-gray-500 font-bold" : "text-gray-300 font-medium after:pl-1.5 after:content-['/']"),
11127
- key: currentDir,
11128
- onClick: () => {
11129
- setDirectory(currentDir);
11130
- }
11131
- },
11132
- part
11133
- );
11134
- }));
11135
- }
11136
11208
  const DeleteModal$1 = ({
11137
11209
  close: close2,
11138
11210
  deleteFunc,
@@ -11186,40 +11258,6 @@ const NewFolderModal = ({ onSubmit, close: close2 }) => {
11186
11258
  "Create New Folder"
11187
11259
  ))));
11188
11260
  };
11189
- const CopyField = ({ label, description, value }) => {
11190
- const [copied, setCopied] = React__default.useState(false);
11191
- const [fadeOut, setFadeOut] = React__default.useState(false);
11192
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, label && /* @__PURE__ */ React__default.createElement("label", { className: "w-full mb-1 block flex-1 text-sm font-bold leading-5 text-gray-700" }, label), /* @__PURE__ */ React__default.createElement(
11193
- "span",
11194
- {
11195
- onClick: () => {
11196
- if (copied === true)
11197
- return;
11198
- setCopied(true);
11199
- setTimeout(() => {
11200
- setFadeOut(true);
11201
- }, 2500);
11202
- setTimeout(() => {
11203
- setCopied(false);
11204
- setFadeOut(false);
11205
- }, 3e3);
11206
- navigator.clipboard.writeText(value);
11207
- },
11208
- 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` : ``}`
11209
- },
11210
- /* @__PURE__ */ React__default.createElement(BiCopyAlt, { className: "relative text-blue-500 shrink-0 w-5 h-auto mr-1.5 -ml-0.5 z-20" }),
11211
- " ",
11212
- value,
11213
- " ",
11214
- copied && /* @__PURE__ */ React__default.createElement(
11215
- "span",
11216
- {
11217
- 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`
11218
- },
11219
- /* @__PURE__ */ React__default.createElement("span", null, "Copied to clipboard!")
11220
- )
11221
- ), description && /* @__PURE__ */ React__default.createElement("p", { className: "mt-2 text-sm text-gray-500" }, description));
11222
- };
11223
11261
  const { useDropzone } = dropzone;
11224
11262
  const join = function(...parts) {
11225
11263
  const [first, last, slash] = [0, parts.length - 1, "/"];
@@ -11721,7 +11759,7 @@ const SyncStatusContainer = ({ children }) => {
11721
11759
  target: "_blank",
11722
11760
  href: `${cms.api.tina.appDashboardLink}/media`
11723
11761
  },
11724
- "Sync Your Media In Tina Cloud.",
11762
+ "Sync Your Media In TinaCloud.",
11725
11763
  /* @__PURE__ */ React__default.createElement(BiLinkExternal, { className: `w-5 h-auto flex-shrink-0` })
11726
11764
  )
11727
11765
  )))) : /* @__PURE__ */ React__default.createElement(SyncStatusContext.Provider, { value: { syncStatus } }, children);
@@ -12053,6 +12091,7 @@ const initialState = (cms) => {
12053
12091
  forms: [],
12054
12092
  formLists: [],
12055
12093
  editingMode: "basic",
12094
+ isLoadingContent: false,
12056
12095
  quickEditSupported: false,
12057
12096
  sidebarDisplayState: ((_a = cms == null ? void 0 : cms.sidebar) == null ? void 0 : _a.defaultState) || "open"
12058
12097
  };
@@ -12112,7 +12151,12 @@ function tinaReducer(state, action) {
12112
12151
  }
12113
12152
  });
12114
12153
  }
12115
- return { ...state, activeFormId, formLists: nextFormLists };
12154
+ return {
12155
+ ...state,
12156
+ activeFormId,
12157
+ formLists: nextFormLists,
12158
+ isLoadingContent: false
12159
+ };
12116
12160
  }
12117
12161
  case "form-lists:remove": {
12118
12162
  const nextFormLists = state.formLists.filter(
@@ -12181,6 +12225,9 @@ function tinaReducer(state, action) {
12181
12225
  }
12182
12226
  return { ...state, sidebarDisplayState: action.value };
12183
12227
  }
12228
+ case "sidebar:set-loading-state": {
12229
+ return { ...state, isLoadingContent: action.value };
12230
+ }
12184
12231
  default:
12185
12232
  throw new Error(`Unhandled action ${action.type}`);
12186
12233
  }
@@ -12866,7 +12913,6 @@ const CreateBranchModel = ({
12866
12913
  }) => {
12867
12914
  const cms = useCMS$1();
12868
12915
  const tinaApi = cms.api.tina;
12869
- tinaApi.branch;
12870
12916
  const [disabled, setDisabled] = React.useState(false);
12871
12917
  const [newBranchName, setNewBranchName] = React.useState("");
12872
12918
  const [error, setError] = React.useState("");
@@ -12892,10 +12938,10 @@ const CreateBranchModel = ({
12892
12938
  const newUrl = window.location.href.replace(hash, newHash);
12893
12939
  window.location.href = newUrl;
12894
12940
  };
12895
- return /* @__PURE__ */ React.createElement(Modal, null, /* @__PURE__ */ React.createElement(PopupModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React.createElement(BiGitBranch, { className: "w-6 h-auto mr-1 text-blue-500 opacity-70" }), " ", "Create Branch"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("p", { className: "text-base text-gray-700 mb-2" }, "This branch is ", /* @__PURE__ */ React.createElement("strong", null, "protected"), ". Create a new branch to save your changes."), /* @__PURE__ */ React.createElement(
12941
+ return /* @__PURE__ */ React.createElement(Modal, null, /* @__PURE__ */ React.createElement(PopupModal, null, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React.createElement(BiGitBranch, { className: "w-6 h-auto mr-1 text-blue-500 opacity-70" }), " ", "Create Branch"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("p", { className: "text-lg text-gray-700 font-bold mb-2" }, "This content is protected 🚧"), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4" }, "To make changes, you need to create a copy then get it approved and merged for it to go live."), /* @__PURE__ */ React.createElement(
12896
12942
  PrefixedTextField,
12897
12943
  {
12898
- placeholder: "Branch Name",
12944
+ placeholder: "e.g. {{PAGE-NAME}}-updates",
12899
12945
  value: newBranchName,
12900
12946
  onChange: (e) => {
12901
12947
  setError("");
@@ -30318,9 +30364,31 @@ function popupWindow(url, title, window2, w, h) {
30318
30364
  }
30319
30365
  const TINA_LOGIN_EVENT = "tinaCloudLogin";
30320
30366
  const AUTH_TOKEN_KEY = "tinacms-auth";
30321
- const authenticate = (clientId, frontendUrl) => {
30322
- return new Promise((resolve) => {
30367
+ const generateRandomString = (length) => {
30368
+ const array = new Uint32Array(length);
30369
+ window.crypto.getRandomValues(array);
30370
+ return Array.from(array, (dec) => ("0" + dec.toString(16)).slice(-2)).join(
30371
+ ""
30372
+ );
30373
+ };
30374
+ const generateCodeChallenge = async (codeVerifier) => {
30375
+ const encoder = new TextEncoder();
30376
+ const data = encoder.encode(codeVerifier);
30377
+ const digest = await window.crypto.subtle.digest("SHA-256", data);
30378
+ return btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
30379
+ };
30380
+ const authenticate = (clientId, frontendUrl, oauth2) => {
30381
+ return new Promise(async (resolve) => {
30323
30382
  const origin = `${window.location.protocol}//${window.location.host}`;
30383
+ if (oauth2) {
30384
+ const codeVerifier = generateRandomString(32);
30385
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
30386
+ localStorage.setItem("code_verifier", codeVerifier);
30387
+ const redirectUri = encodeURIComponent(`${origin}/admin`);
30388
+ window.location.href = `${frontendUrl}/oauth-signin?redirect_uri=${redirectUri}&code_challenge=${codeChallenge}&client_id=${clientId}`;
30389
+ resolve(void 0);
30390
+ return;
30391
+ }
30324
30392
  const authTab = popupWindow(
30325
30393
  `${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`,
30326
30394
  "_blank",
@@ -30401,6 +30469,7 @@ class TinaCloudAuthProvider extends AbstractAuthProvider {
30401
30469
  this.frontendUrl = frontendUrl;
30402
30470
  this.clientId = clientId;
30403
30471
  this.identityApiUrl = identityApiUrl;
30472
+ this.oauth2 = options.oauth2 || false;
30404
30473
  switch (tokenStorage) {
30405
30474
  case "LOCAL_STORAGE":
30406
30475
  this.getToken = async function() {
@@ -30446,9 +30515,52 @@ class TinaCloudAuthProvider extends AbstractAuthProvider {
30446
30515
  }
30447
30516
  }
30448
30517
  async authenticate() {
30449
- const token = await authenticate(this.clientId, this.frontendUrl);
30450
- this.setToken(token);
30451
- return token;
30518
+ const params = new URLSearchParams(window.location.search);
30519
+ console.log({ params });
30520
+ const code = params.get("code");
30521
+ const state = params.get("state");
30522
+ const codeVerifier = localStorage.getItem("code_verifier");
30523
+ console.log({
30524
+ code,
30525
+ state,
30526
+ codeVerifier
30527
+ });
30528
+ if (code && state && codeVerifier) {
30529
+ const origin = `${window.location.protocol}//${window.location.host}`;
30530
+ const redirectUri = encodeURIComponent(`${origin}/admin`);
30531
+ const tokenUrl = `${this.identityApiUrl}/oauth2/${this.clientId}/token`;
30532
+ console.log("Token URL:", tokenUrl);
30533
+ await fetch(tokenUrl, {
30534
+ method: "POST",
30535
+ headers: {
30536
+ "Content-Type": "application/x-www-form-urlencoded"
30537
+ },
30538
+ body: new URLSearchParams({
30539
+ grant_type: "authorization_code",
30540
+ code,
30541
+ redirect_uri: redirectUri,
30542
+ client_id: this.clientId,
30543
+ code_verifier: localStorage.getItem("code_verifier")
30544
+ })
30545
+ }).then((response) => response.json()).then((data) => {
30546
+ console.log("Token exchange response:", data);
30547
+ this.setToken(data);
30548
+ }).catch((error) => {
30549
+ console.error("Error during token exchange:", error);
30550
+ });
30551
+ } else {
30552
+ console.log("calling authenticate");
30553
+ const token = await authenticate(
30554
+ this.clientId,
30555
+ this.frontendUrl,
30556
+ this.oauth2
30557
+ );
30558
+ console.log("Token:", token);
30559
+ if (token) {
30560
+ this.setToken(token);
30561
+ }
30562
+ }
30563
+ return this.getToken();
30452
30564
  }
30453
30565
  async getUser() {
30454
30566
  if (!this.clientId) {
@@ -30557,7 +30669,7 @@ const IndexStatusResponse = z.object({
30557
30669
  });
30558
30670
  class Client {
30559
30671
  constructor({ tokenStorage = "MEMORY", ...options }) {
30560
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
30672
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
30561
30673
  this.events = new EventBus();
30562
30674
  this.protectedBranches = [];
30563
30675
  this.usingEditorialWorkflow = false;
@@ -30638,7 +30750,8 @@ mutation addPendingDocumentMutation(
30638
30750
  identityApiUrl: this.identityApiUrl,
30639
30751
  getTokenFn: options.getTokenFn,
30640
30752
  tokenStorage,
30641
- frontendUrl: this.frontendUrl
30753
+ frontendUrl: this.frontendUrl,
30754
+ oauth2: (_w = (_v = options.schema) == null ? void 0 : _v.config) == null ? void 0 : _w.oauth2
30642
30755
  });
30643
30756
  }
30644
30757
  get isLocalMode() {
@@ -30650,6 +30763,7 @@ mutation addPendingDocumentMutation(
30650
30763
  setBranch(branchName) {
30651
30764
  var _a, _b, _c, _d;
30652
30765
  const encodedBranch = encodeURIComponent(branchName);
30766
+ document.cookie = `x-branch=${encodedBranch}; path=/; max-age=3600`;
30653
30767
  this.branch = encodedBranch;
30654
30768
  this.assetsApiUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.assetsApiUrlOverride) || "https://assets.tinajs.io";
30655
30769
  this.frontendUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.frontendUrlOverride) || "https://app.tina.io";
@@ -30692,7 +30806,7 @@ mutation addPendingDocumentMutation(
30692
30806
  branch: ${this.branch}.`;
30693
30807
  if (this.branch !== "main") {
30694
30808
  errorMessage = `${errorMessage}
30695
- Note: This error can occur if the branch does not exist on GitHub or on Tina Cloud`;
30809
+ Note: This error can occur if the branch does not exist on GitHub or on TinaCloud`;
30696
30810
  }
30697
30811
  }
30698
30812
  throw new Error(errorMessage);
@@ -30828,7 +30942,7 @@ mutation addPendingDocumentMutation(
30828
30942
  unknownCount++;
30829
30943
  if (unknownCount > 5) {
30830
30944
  throw new Error(
30831
- "AsyncPoller: status unknown for too long, please check indexing progress the Tina Cloud dashboard"
30945
+ "AsyncPoller: status unknown for too long, please check indexing progress the TinaCloud dashboard"
30832
30946
  );
30833
30947
  }
30834
30948
  }
@@ -31464,7 +31578,52 @@ const AuthWallInner = ({
31464
31578
  const [showChildren, setShowChildren] = useState(false);
31465
31579
  const [authProps, setAuthProps] = useState({ username: "", password: "" });
31466
31580
  const [authenticated, setAuthenticated] = useState(false);
31581
+ const [code, setCode] = useState(null);
31582
+ const [state, setState] = useState(null);
31583
+ const [retrievingToken, setRetrievingToken] = useState(false);
31584
+ useEffect(() => {
31585
+ if (typeof window !== "undefined") {
31586
+ const queryParams = new URLSearchParams(window.location.search);
31587
+ setCode(queryParams.get("code"));
31588
+ setState(queryParams.get("state"));
31589
+ }
31590
+ }, []);
31591
+ useEffect(() => {
31592
+ const codeVerifier = localStorage.getItem("code_verifier");
31593
+ if (codeVerifier && code && state) {
31594
+ setRetrievingToken(true);
31595
+ const origin = `${window.location.protocol}//${window.location.host}`;
31596
+ const redirectUri = encodeURIComponent(`${origin}/admin`);
31597
+ const tokenUrl = `${client.identityApiUrl}/oauth2/${client.clientId}/token`;
31598
+ console.log("Token URL:", tokenUrl);
31599
+ fetch(tokenUrl, {
31600
+ method: "POST",
31601
+ headers: {
31602
+ "Content-Type": "application/x-www-form-urlencoded"
31603
+ },
31604
+ body: new URLSearchParams({
31605
+ grant_type: "authorization_code",
31606
+ code,
31607
+ redirect_uri: redirectUri,
31608
+ client_id: client.clientId,
31609
+ code_verifier: localStorage.getItem("code_verifier")
31610
+ })
31611
+ }).then((response) => response.json()).then((data) => {
31612
+ console.log("Token exchange response:", data);
31613
+ setRetrievingToken(false);
31614
+ localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(data));
31615
+ setAuthenticated(true);
31616
+ }).catch((error) => {
31617
+ console.error("Error during token exchange:", error);
31618
+ setRetrievingToken(false);
31619
+ });
31620
+ }
31621
+ }, [code, state]);
31467
31622
  React__default.useEffect(() => {
31623
+ if (retrievingToken) {
31624
+ console.log("Retrieving token...");
31625
+ return;
31626
+ }
31468
31627
  let mounted = true;
31469
31628
  client.authProvider.isAuthenticated().then((isAuthenticated) => {
31470
31629
  if (!mounted)
@@ -31509,7 +31668,7 @@ const AuthWallInner = ({
31509
31668
  return () => {
31510
31669
  mounted = false;
31511
31670
  };
31512
- }, [authenticated]);
31671
+ }, [authenticated, retrievingToken]);
31513
31672
  const onAuthenticated = async () => {
31514
31673
  setAuthenticated(true);
31515
31674
  setActiveModal(null);
@@ -31539,7 +31698,7 @@ const AuthWallInner = ({
31539
31698
  });
31540
31699
  }
31541
31700
  };
31542
- let modalTitle = "Tina Cloud";
31701
+ let modalTitle = "TinaCloud";
31543
31702
  if (activeModal === "authenticate" && loginStrategy === "Redirect" && !isTinaCloud) {
31544
31703
  modalTitle = "Enter into edit mode";
31545
31704
  } else if (activeModal === "authenticate" && loginStrategy === "UsernamePassword") {
@@ -31555,7 +31714,7 @@ const AuthWallInner = ({
31555
31714
  ModalBuilder,
31556
31715
  {
31557
31716
  title: modalTitle,
31558
- message: isTinaCloud ? "Your site uses Tina Cloud to track changes. To make edits, you must log in." : "To save edits, enter into edit mode. On save, changes will saved to the local filesystem.",
31717
+ message: isTinaCloud ? "Your site uses TinaCloud to track changes. To make edits, you must log in." : "To save edits, enter into edit mode. On save, changes will saved to the local filesystem.",
31559
31718
  close,
31560
31719
  actions: [
31561
31720
  ...otherModalActions,
@@ -31658,7 +31817,6 @@ const TinaCloudProvider = (props) => {
31658
31817
  "tinacms-current-branch",
31659
31818
  baseBranch
31660
31819
  );
31661
- console.log({ currentBranch });
31662
31820
  useTinaAuthRedirect();
31663
31821
  const cms = React__default.useMemo(
31664
31822
  () => props.cms || new TinaCMS({
@@ -31778,10 +31936,7 @@ const TinaCloudProvider = (props) => {
31778
31936
  cms.flags.set("branch-switcher", true);
31779
31937
  client.usingEditorialWorkflow = true;
31780
31938
  client.protectedBranches = project.protectedBranches;
31781
- console.log("currentBranch", currentBranch);
31782
- console.log(project.metadata[currentBranch]);
31783
31939
  if (!project.metadata[currentBranch]) {
31784
- console.log("resetting to default branch", project.defaultBranch);
31785
31940
  setCurrentBranch(project.defaultBranch || "main");
31786
31941
  }
31787
31942
  }
@@ -32282,6 +32437,14 @@ This will work when developing locally but NOT when deployed to production.
32282
32437
  }
32283
32438
  return client.request(query, { variables });
32284
32439
  };
32440
+ const GetCMS = ({ children }) => {
32441
+ try {
32442
+ const cms = useCMS$1();
32443
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(cms));
32444
+ } catch (e) {
32445
+ return null;
32446
+ }
32447
+ };
32285
32448
  const Layout = ({ children }) => {
32286
32449
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
32287
32450
  "div",
@@ -32493,47 +32656,6 @@ const SidebarCloudLink = ({ config }) => {
32493
32656
  }
32494
32657
  return /* @__PURE__ */ React__default.createElement("span", { className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100" }, /* @__PURE__ */ React__default.createElement(config.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }), /* @__PURE__ */ React__default.createElement("a", { target: "_blank", href: config.link.href }, config.link.text));
32495
32658
  };
32496
- const GetCMS = ({ children }) => {
32497
- try {
32498
- const cms = useCMS$1();
32499
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(cms));
32500
- } catch (e) {
32501
- return null;
32502
- }
32503
- };
32504
- const PageWrapper = ({ children }) => {
32505
- var _a, _b;
32506
- const cms = useCMS$1();
32507
- const isLocalMode = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode;
32508
- const [branchingEnabled, setBranchingEnabled] = React__default.useState(
32509
- () => cms.flags.get("branch-switcher")
32510
- );
32511
- React__default.useEffect(() => {
32512
- cms.events.subscribe("flag:set", ({ key, value }) => {
32513
- if (key === "branch-switcher") {
32514
- setBranchingEnabled(value);
32515
- }
32516
- });
32517
- }, [cms.events]);
32518
- return /* @__PURE__ */ React__default.createElement("div", { className: "relative left-0 w-full h-full bg-gradient-to-b from-gray-50/50 to-gray-50 shadow-2xl overflow-y-auto transition-opacity duration-300 ease-out flex flex-col opacity-100" }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React__default.createElement(BranchBanner, null), children);
32519
- };
32520
- const PageHeader = ({
32521
- isLocalMode,
32522
- children
32523
- }) => {
32524
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, isLocalMode && /* @__PURE__ */ React__default.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React__default.createElement(BillingWarning, null), /* @__PURE__ */ React__default.createElement("div", { className: "pt-16 xl:pt-12 px-6 xl:px-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full mx-auto max-w-screen-xl" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex justify-between items-end" }, children))));
32525
- };
32526
- const PageBody = ({ children }) => /* @__PURE__ */ React__default.createElement("div", { className: "py-8 px-6 xl:px-12" }, children);
32527
- const PageBodyNarrow = ({ children }) => /* @__PURE__ */ React__default.createElement("div", { className: "py-10 px-6 xl:px-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full mx-auto max-w-screen-xl" }, children));
32528
- const DashboardPage = () => {
32529
- return /* @__PURE__ */ React__default.createElement(GetCMS, null, (cms) => {
32530
- var _a, _b;
32531
- return /* @__PURE__ */ React__default.createElement(PageWrapper, null, /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(PageHeader, { isLocalMode: (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-2xl font-sans text-gray-700" }, "Welcome to Tina!")), /* @__PURE__ */ React__default.createElement(PageBodyNarrow, null, "This is your dashboard for editing or creating content. Select a collection on the left to begin.")));
32532
- });
32533
- };
32534
- function RiHome2Line(props) {
32535
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M19 21H5C4.44772 21 4 20.5523 4 20V11L1 11L11.3273 1.6115C11.7087 1.26475 12.2913 1.26475 12.6727 1.6115L23 11L20 11V20C20 20.5523 19.5523 21 19 21ZM6 19H18V9.15745L12 3.7029L6 9.15745V19Z" }, "child": [] }] })(props);
32536
- }
32537
32659
  const LoadingPage = () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
32538
32660
  "div",
32539
32661
  {
@@ -32643,203 +32765,33 @@ const LoadingPage = () => /* @__PURE__ */ React__default.createElement(React__de
32643
32765
  )
32644
32766
  )
32645
32767
  ));
32646
- const FullscreenError = ({
32647
- title = "Error",
32648
- errorMessage = "It looks like something went wrong."
32649
- }) => {
32650
- return /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col justify-center items-center h-screen bg-gray-100" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-red-500 text-4xl mb-6 flex items-center" }, /* @__PURE__ */ React__default.createElement(BiError, { className: "w-12 h-auto fill-current text-red-400 opacity-70 mr-1" }), " ", title), /* @__PURE__ */ React__default.createElement("p", { className: "text-gray-700 text-xl mb-8" }, errorMessage), /* @__PURE__ */ React__default.createElement(Button$1, { variant: "danger", onClick: () => window.location.reload() }, /* @__PURE__ */ React__default.createElement(BiSync, { className: "w-7 h-auto fill-current opacity-70 mr-1" }), " Reload"));
32651
- };
32652
- const useGetCollection = (cms, collectionName, includeDocuments = true, folder, after = "", sortKey, filterArgs) => {
32653
- const api = new TinaAdminApi(cms);
32654
- const schema = cms.api.tina.schema;
32655
- const collectionExtra = schema.getCollection(collectionName);
32656
- const [collection, setCollection] = useState(void 0);
32657
- const [loading, setLoading] = useState(true);
32658
- const [error, setError] = useState(void 0);
32659
- const [resetState, setResetSate] = useState(0);
32660
- useEffect(() => {
32661
- let cancelled = false;
32662
- const fetchCollection = async () => {
32663
- var _a;
32664
- if (await api.isAuthenticated() && !folder.loading && !cancelled) {
32665
- const { name, order } = JSON.parse(sortKey || "{}");
32666
- const validSortKey = ((_a = collectionExtra.fields) == null ? void 0 : _a.map((x) => x.name).includes(name)) ? name : void 0;
32667
- try {
32668
- const collection2 = await api.fetchCollection(
32669
- collectionName,
32670
- includeDocuments,
32671
- (filterArgs == null ? void 0 : filterArgs.filterField) ? "" : folder.fullyQualifiedName,
32672
- after,
32673
- validSortKey,
32674
- order,
32675
- filterArgs
32676
- );
32677
- setCollection(collection2);
32678
- } catch (error2) {
32679
- cms.alerts.error(
32680
- `[${error2.name}] GetCollection failed: ${error2.message}`
32681
- );
32682
- console.error(error2);
32683
- setCollection(void 0);
32684
- setError(error2);
32685
- }
32686
- setLoading(false);
32687
- }
32688
- };
32689
- if (cancelled)
32690
- return;
32691
- setLoading(true);
32692
- fetchCollection();
32693
- return () => {
32694
- cancelled = true;
32695
- };
32696
- }, [
32697
- cms,
32698
- collectionName,
32699
- folder.loading,
32700
- folder.fullyQualifiedName,
32701
- resetState,
32702
- after,
32703
- sortKey
32704
- ]);
32705
- const reFetchCollection = () => setResetSate((x) => x + 1);
32706
- return { collection, loading, error, reFetchCollection, collectionExtra };
32707
- };
32708
- const useSearchCollection = (cms, collectionName, includeDocuments = true, folder, after = "", search) => {
32709
- const api = new TinaAdminApi(cms);
32710
- const schema = cms.api.tina.schema;
32711
- const collectionExtra = schema.getCollection(collectionName);
32712
- const [collection, setCollection] = useState(void 0);
32713
- const [loading, setLoading] = useState(true);
32714
- const [error, setError] = useState(void 0);
32715
- const [resetState, setResetSate] = useState(0);
32716
- useEffect(() => {
32717
- let cancelled = false;
32718
- const searchCollection = async () => {
32719
- if (await api.isAuthenticated() && !folder.loading && !cancelled) {
32720
- try {
32721
- const response = await cms.api.search.query(
32722
- `${search} AND _collection:${collectionName}`,
32723
- {
32724
- limit: 15,
32725
- cursor: after
32726
- }
32727
- );
32728
- const docs = await Promise.allSettled(
32729
- response.results.map((result) => {
32730
- const [collection2, relativePath2] = result._id.split(":");
32731
- return api.fetchDocument(collection2, relativePath2, false);
32732
- })
32733
- );
32734
- const edges = docs.filter((p) => {
32735
- var _a;
32736
- return p.status === "fulfilled" && !!((_a = p.value) == null ? void 0 : _a.document);
32737
- }).map((result) => ({ node: result.value.document }));
32738
- const c = await api.fetchCollection(collectionName, false, "");
32739
- setCollection({
32740
- format: collection.format,
32741
- label: collection.label,
32742
- name: collectionName,
32743
- templates: collection.templates,
32744
- documents: {
32745
- pageInfo: {
32746
- hasNextPage: !!response.nextCursor,
32747
- hasPreviousPage: !!response.prevCursor,
32748
- startCursor: "",
32749
- endCursor: response.nextCursor || ""
32750
- },
32751
- edges
32752
- }
32753
- });
32754
- } catch (error2) {
32755
- cms.alerts.error(
32756
- `[${error2.name}] GetCollection failed: ${error2.message}`
32757
- );
32758
- console.error(error2);
32759
- setCollection(void 0);
32760
- setError(error2);
32761
- }
32762
- setLoading(false);
32768
+ function RiHome2Line(props) {
32769
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M19 21H5C4.44772 21 4 20.5523 4 20V11L1 11L11.3273 1.6115C11.7087 1.26475 12.2913 1.26475 12.6727 1.6115L23 11L20 11V20C20 20.5523 19.5523 21 19 21ZM6 19H18V9.15745L12 3.7029L6 9.15745V19Z" }, "child": [] }] })(props);
32770
+ }
32771
+ const PageWrapper = ({ children }) => {
32772
+ var _a, _b;
32773
+ const cms = useCMS$1();
32774
+ const isLocalMode = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode;
32775
+ const [branchingEnabled, setBranchingEnabled] = React__default.useState(
32776
+ () => cms.flags.get("branch-switcher")
32777
+ );
32778
+ React__default.useEffect(() => {
32779
+ cms.events.subscribe("flag:set", ({ key, value }) => {
32780
+ if (key === "branch-switcher") {
32781
+ setBranchingEnabled(value);
32763
32782
  }
32764
- };
32765
- if (cancelled)
32766
- return;
32767
- setLoading(true);
32768
- searchCollection();
32769
- return () => {
32770
- cancelled = true;
32771
- };
32772
- }, [
32773
- cms,
32774
- collectionName,
32775
- folder.loading,
32776
- folder.fullyQualifiedName,
32777
- resetState,
32778
- after,
32779
- search
32780
- ]);
32781
- const reFetchCollection = () => setResetSate((x) => x + 1);
32782
- return { collection, loading, error, reFetchCollection, collectionExtra };
32783
+ });
32784
+ }, [cms.events]);
32785
+ return /* @__PURE__ */ React__default.createElement("div", { className: "relative left-0 w-full h-full bg-gradient-to-b from-gray-50/50 to-gray-50 shadow-2xl overflow-y-auto transition-opacity duration-300 ease-out flex flex-col opacity-100" }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React__default.createElement(BranchBanner, null), children);
32783
32786
  };
32784
- const GetCollection = ({
32785
- cms,
32786
- collectionName,
32787
- folder,
32788
- includeDocuments = true,
32789
- startCursor,
32790
- sortKey,
32791
- children,
32792
- filterArgs,
32793
- search
32787
+ const PageHeader = ({
32788
+ isLocalMode,
32789
+ children
32794
32790
  }) => {
32795
- const navigate = useNavigate();
32796
- const { collection, loading, error, reFetchCollection, collectionExtra } = search ? useSearchCollection(
32797
- cms,
32798
- collectionName,
32799
- includeDocuments,
32800
- folder,
32801
- startCursor || "",
32802
- search
32803
- ) : useGetCollection(
32804
- cms,
32805
- collectionName,
32806
- includeDocuments,
32807
- folder,
32808
- startCursor || "",
32809
- sortKey,
32810
- filterArgs
32811
- ) || {};
32812
- useEffect(() => {
32813
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
32814
- if (loading)
32815
- return;
32816
- const collectionDefinition = cms.api.tina.schema.getCollection(
32817
- collection.name
32818
- );
32819
- const allowCreate = ((_b = (_a = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _a.allowedActions) == null ? void 0 : _b.create) ?? true;
32820
- const allowDelete = ((_d = (_c = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _c.allowedActions) == null ? void 0 : _d.delete) ?? true;
32821
- const collectionResponse = collection;
32822
- if (!allowCreate && !allowDelete && // Check there is only one document
32823
- ((_f = (_e = collectionResponse.documents) == null ? void 0 : _e.edges) == null ? void 0 : _f.length) === 1 && // Check to make sure the file is not a folder
32824
- ((_i = (_h = (_g = collectionResponse.documents) == null ? void 0 : _g.edges[0]) == null ? void 0 : _h.node) == null ? void 0 : _i.__typename) !== "Folder") {
32825
- const doc = collectionResponse.documents.edges[0].node;
32826
- handleNavigate(
32827
- navigate,
32828
- cms,
32829
- collectionResponse,
32830
- collectionDefinition,
32831
- doc
32832
- );
32833
- }
32834
- }, [(collection == null ? void 0 : collection.name) || "", loading]);
32835
- if (error) {
32836
- return /* @__PURE__ */ React__default.createElement(FullscreenError, null);
32837
- }
32838
- if (loading) {
32839
- return /* @__PURE__ */ React__default.createElement(LoadingPage, null);
32840
- }
32841
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
32791
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, isLocalMode && /* @__PURE__ */ React__default.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React__default.createElement(BillingWarning, null), /* @__PURE__ */ React__default.createElement("div", { className: "pt-16 xl:pt-12 px-6 xl:px-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full mx-auto max-w-screen-xl" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex justify-between items-end" }, children))));
32842
32792
  };
32793
+ const PageBody = ({ children }) => /* @__PURE__ */ React__default.createElement("div", { className: "py-8 px-6 xl:px-12" }, children);
32794
+ const PageBodyNarrow = ({ children }) => /* @__PURE__ */ React__default.createElement("div", { className: "py-10 px-6 xl:px-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full mx-auto max-w-screen-xl" }, children));
32843
32795
  const folderRegex = /^.*\/~\/*(.*)$/;
32844
32796
  const parentFolder = (folder) => {
32845
32797
  return {
@@ -33717,6 +33669,231 @@ const RenameModal = ({
33717
33669
  "Rename"
33718
33670
  ))));
33719
33671
  };
33672
+ const FullscreenError = ({
33673
+ title = "Error",
33674
+ errorMessage = "It looks like something went wrong."
33675
+ }) => {
33676
+ return /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col justify-center items-center h-screen bg-gray-100" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-red-500 text-4xl mb-6 flex items-center" }, /* @__PURE__ */ React__default.createElement(BiError, { className: "w-12 h-auto fill-current text-red-400 opacity-70 mr-1" }), " ", title), /* @__PURE__ */ React__default.createElement("p", { className: "text-gray-700 text-xl mb-8" }, errorMessage), /* @__PURE__ */ React__default.createElement(Button$1, { variant: "danger", onClick: () => window.location.reload() }, /* @__PURE__ */ React__default.createElement(BiSync, { className: "w-7 h-auto fill-current opacity-70 mr-1" }), " Reload"));
33677
+ };
33678
+ const isValidSortKey = (sortKey, collection) => {
33679
+ if (collection.fields) {
33680
+ const sortKeys = collection.fields.map((x) => x.name);
33681
+ return sortKeys.includes(sortKey);
33682
+ } else if (collection.templates) {
33683
+ const collectionMap = {};
33684
+ const conflictedFields = /* @__PURE__ */ new Set();
33685
+ for (const template of collection.templates) {
33686
+ for (const field of template.fields) {
33687
+ if (collectionMap[field.name]) {
33688
+ if (collectionMap[field.name].type !== field.type) {
33689
+ conflictedFields.add(field.name);
33690
+ }
33691
+ } else {
33692
+ collectionMap[field.name] = field;
33693
+ }
33694
+ }
33695
+ }
33696
+ for (const key in conflictedFields) {
33697
+ delete collectionMap[key];
33698
+ }
33699
+ for (const key in collectionMap) {
33700
+ if (key === sortKey) {
33701
+ return true;
33702
+ }
33703
+ }
33704
+ return false;
33705
+ }
33706
+ };
33707
+ const useGetCollection = (cms, collectionName, includeDocuments = true, folder, after = "", sortKey, filterArgs) => {
33708
+ const api = new TinaAdminApi(cms);
33709
+ const schema = cms.api.tina.schema;
33710
+ const collectionExtra = schema.getCollection(collectionName);
33711
+ const [collection, setCollection] = useState(void 0);
33712
+ const [loading, setLoading] = useState(true);
33713
+ const [error, setError] = useState(void 0);
33714
+ const [resetState, setResetSate] = useState(0);
33715
+ useEffect(() => {
33716
+ let cancelled = false;
33717
+ const fetchCollection = async () => {
33718
+ if (await api.isAuthenticated() && !folder.loading && !cancelled) {
33719
+ const { name, order } = JSON.parse(sortKey || "{}");
33720
+ const validSortKey = isValidSortKey(name, collectionExtra) ? name : void 0;
33721
+ try {
33722
+ const collection2 = await api.fetchCollection(
33723
+ collectionName,
33724
+ includeDocuments,
33725
+ (filterArgs == null ? void 0 : filterArgs.filterField) ? "" : folder.fullyQualifiedName,
33726
+ after,
33727
+ validSortKey,
33728
+ order,
33729
+ filterArgs
33730
+ );
33731
+ setCollection(collection2);
33732
+ } catch (error2) {
33733
+ cms.alerts.error(
33734
+ `[${error2.name}] GetCollection failed: ${error2.message}`
33735
+ );
33736
+ console.error(error2);
33737
+ setCollection(void 0);
33738
+ setError(error2);
33739
+ }
33740
+ setLoading(false);
33741
+ }
33742
+ };
33743
+ if (cancelled)
33744
+ return;
33745
+ setLoading(true);
33746
+ fetchCollection();
33747
+ return () => {
33748
+ cancelled = true;
33749
+ };
33750
+ }, [
33751
+ cms,
33752
+ collectionName,
33753
+ folder.loading,
33754
+ folder.fullyQualifiedName,
33755
+ resetState,
33756
+ after,
33757
+ sortKey
33758
+ ]);
33759
+ const reFetchCollection = () => setResetSate((x) => x + 1);
33760
+ return { collection, loading, error, reFetchCollection, collectionExtra };
33761
+ };
33762
+ const useSearchCollection = (cms, collectionName, includeDocuments = true, folder, after = "", search) => {
33763
+ const api = new TinaAdminApi(cms);
33764
+ const schema = cms.api.tina.schema;
33765
+ const collectionExtra = schema.getCollection(collectionName);
33766
+ const [collection, setCollection] = useState(void 0);
33767
+ const [loading, setLoading] = useState(true);
33768
+ const [error, setError] = useState(void 0);
33769
+ const [resetState, setResetSate] = useState(0);
33770
+ useEffect(() => {
33771
+ let cancelled = false;
33772
+ const searchCollection = async () => {
33773
+ if (await api.isAuthenticated() && !folder.loading && !cancelled) {
33774
+ try {
33775
+ const response = await cms.api.search.query(
33776
+ `${search} AND _collection:${collectionName}`,
33777
+ {
33778
+ limit: 15,
33779
+ cursor: after
33780
+ }
33781
+ );
33782
+ const docs = await Promise.allSettled(
33783
+ response.results.map((result) => {
33784
+ const [collection2, relativePath2] = result._id.split(":");
33785
+ return api.fetchDocument(collection2, relativePath2, false);
33786
+ })
33787
+ );
33788
+ const edges = docs.filter((p) => {
33789
+ var _a;
33790
+ return p.status === "fulfilled" && !!((_a = p.value) == null ? void 0 : _a.document);
33791
+ }).map((result) => ({ node: result.value.document }));
33792
+ const c = await api.fetchCollection(collectionName, false, "");
33793
+ setCollection({
33794
+ format: collection.format,
33795
+ label: collection.label,
33796
+ name: collectionName,
33797
+ templates: collection.templates,
33798
+ documents: {
33799
+ pageInfo: {
33800
+ hasNextPage: !!response.nextCursor,
33801
+ hasPreviousPage: !!response.prevCursor,
33802
+ startCursor: "",
33803
+ endCursor: response.nextCursor || ""
33804
+ },
33805
+ edges
33806
+ }
33807
+ });
33808
+ } catch (error2) {
33809
+ cms.alerts.error(
33810
+ `[${error2.name}] GetCollection failed: ${error2.message}`
33811
+ );
33812
+ console.error(error2);
33813
+ setCollection(void 0);
33814
+ setError(error2);
33815
+ }
33816
+ setLoading(false);
33817
+ }
33818
+ };
33819
+ if (cancelled)
33820
+ return;
33821
+ setLoading(true);
33822
+ searchCollection();
33823
+ return () => {
33824
+ cancelled = true;
33825
+ };
33826
+ }, [
33827
+ cms,
33828
+ collectionName,
33829
+ folder.loading,
33830
+ folder.fullyQualifiedName,
33831
+ resetState,
33832
+ after,
33833
+ search
33834
+ ]);
33835
+ const reFetchCollection = () => setResetSate((x) => x + 1);
33836
+ return { collection, loading, error, reFetchCollection, collectionExtra };
33837
+ };
33838
+ const GetCollection = ({
33839
+ cms,
33840
+ collectionName,
33841
+ folder,
33842
+ includeDocuments = true,
33843
+ startCursor,
33844
+ sortKey,
33845
+ children,
33846
+ filterArgs,
33847
+ search
33848
+ }) => {
33849
+ const navigate = useNavigate();
33850
+ const { collection, loading, error, reFetchCollection, collectionExtra } = search ? useSearchCollection(
33851
+ cms,
33852
+ collectionName,
33853
+ includeDocuments,
33854
+ folder,
33855
+ startCursor || "",
33856
+ search
33857
+ ) : useGetCollection(
33858
+ cms,
33859
+ collectionName,
33860
+ includeDocuments,
33861
+ folder,
33862
+ startCursor || "",
33863
+ sortKey,
33864
+ filterArgs
33865
+ ) || {};
33866
+ useEffect(() => {
33867
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
33868
+ if (loading)
33869
+ return;
33870
+ const collectionDefinition = cms.api.tina.schema.getCollection(
33871
+ collection.name
33872
+ );
33873
+ const allowCreate = ((_b = (_a = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _a.allowedActions) == null ? void 0 : _b.create) ?? true;
33874
+ const allowDelete = ((_d = (_c = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _c.allowedActions) == null ? void 0 : _d.delete) ?? true;
33875
+ const collectionResponse = collection;
33876
+ if (!allowCreate && !allowDelete && // Check there is only one document
33877
+ ((_f = (_e = collectionResponse.documents) == null ? void 0 : _e.edges) == null ? void 0 : _f.length) === 1 && // Check to make sure the file is not a folder
33878
+ ((_i = (_h = (_g = collectionResponse.documents) == null ? void 0 : _g.edges[0]) == null ? void 0 : _h.node) == null ? void 0 : _i.__typename) !== "Folder") {
33879
+ const doc = collectionResponse.documents.edges[0].node;
33880
+ handleNavigate(
33881
+ navigate,
33882
+ cms,
33883
+ collectionResponse,
33884
+ collectionDefinition,
33885
+ doc
33886
+ );
33887
+ }
33888
+ }, [(collection == null ? void 0 : collection.name) || "", loading]);
33889
+ if (error) {
33890
+ return /* @__PURE__ */ React__default.createElement(FullscreenError, null);
33891
+ }
33892
+ if (loading) {
33893
+ return /* @__PURE__ */ React__default.createElement(LoadingPage, null);
33894
+ }
33895
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
33896
+ };
33720
33897
  const ErrorDialog = (props) => {
33721
33898
  return /* @__PURE__ */ React__default.createElement(
33722
33899
  "div",
@@ -34260,6 +34437,12 @@ const RenderForm = ({
34260
34437
  ), /* @__PURE__ */ React__default.createElement("span", { className: "opacity-30 text-sm leading-tight whitespace-nowrap flex-0" }, "/"), /* @__PURE__ */ React__default.createElement("span", { className: "flex-1 w-full text-sm leading-tight whitespace-nowrap truncate" }, `${filename}.${collection.format}`), /* @__PURE__ */ React__default.createElement(FormStatus, { pristine: formIsPristine }))
34261
34438
  ), activeForm && /* @__PURE__ */ React__default.createElement(FormBuilder, { form: activeForm, onPristineChange: setFormIsPristine }));
34262
34439
  };
34440
+ const DashboardPage = () => {
34441
+ return /* @__PURE__ */ React__default.createElement(GetCMS, null, (cms) => {
34442
+ var _a, _b;
34443
+ return /* @__PURE__ */ React__default.createElement(PageWrapper, null, /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(PageHeader, { isLocalMode: (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-2xl font-sans text-gray-700" }, "Welcome to Tina!")), /* @__PURE__ */ React__default.createElement(PageBodyNarrow, null, "This is your dashboard for editing or creating content. Select a collection on the left to begin.")));
34444
+ });
34445
+ };
34263
34446
  const ScreenPage = () => {
34264
34447
  const { screenName } = useParams();
34265
34448
  return /* @__PURE__ */ React__default.createElement(GetCMS, null, (cms) => {
@@ -34278,6 +34461,71 @@ const ScreenPage = () => {
34278
34461
  } })));
34279
34462
  });
34280
34463
  };
34464
+ function AuthCallback({
34465
+ clientId,
34466
+ identityApiUrl
34467
+ }) {
34468
+ console.log("AuthCallback", clientId, identityApiUrl);
34469
+ const [code, setCode] = React.useState(null);
34470
+ const [state, setState] = React.useState(null);
34471
+ const [tokenResponse, setTokenResponse] = React.useState(null);
34472
+ const [app, setApp] = React.useState(null);
34473
+ React.useEffect(() => {
34474
+ if (typeof window !== "undefined") {
34475
+ const queryParams = new URLSearchParams(window.location.search);
34476
+ setCode(queryParams.get("code"));
34477
+ setState(queryParams.get("state"));
34478
+ }
34479
+ }, []);
34480
+ React.useEffect(() => {
34481
+ if (code && state) {
34482
+ if (localStorage.getItem("code_verifier")) {
34483
+ const origin = `${window.location.protocol}//${window.location.host}`;
34484
+ const redirectUri = encodeURIComponent(
34485
+ `${origin}/admin#/auth/callback`
34486
+ );
34487
+ fetch(`${identityApiUrl}/oauth2/${clientId}/token`, {
34488
+ method: "POST",
34489
+ headers: {
34490
+ "Content-Type": "application/x-www-form-urlencoded"
34491
+ },
34492
+ body: new URLSearchParams({
34493
+ grant_type: "authorization_code",
34494
+ code,
34495
+ redirect_uri: redirectUri,
34496
+ client_id: clientId || "",
34497
+ code_verifier: localStorage.getItem("code_verifier")
34498
+ })
34499
+ }).then((response) => response.json()).then((data) => {
34500
+ console.log("Token exchange response:", data);
34501
+ setTokenResponse(data);
34502
+ }).catch((error) => {
34503
+ console.error("Error during token exchange:", error);
34504
+ });
34505
+ }
34506
+ }
34507
+ }, [code, state]);
34508
+ React.useEffect(() => {
34509
+ localStorage.setItem(
34510
+ AUTH_TOKEN_KEY,
34511
+ JSON.stringify(tokenResponse, null, 2)
34512
+ );
34513
+ }, [tokenResponse]);
34514
+ React.useEffect(() => {
34515
+ fetch(`${identityApiUrl}/v2/apps/${clientId}`, {
34516
+ method: "GET",
34517
+ headers: {
34518
+ "Content-Type": "application/x-www-form-urlencoded",
34519
+ Authorization: "Bearer " + (tokenResponse == null ? void 0 : tokenResponse.access_token)
34520
+ }
34521
+ }).then((response) => response.json()).then((data) => {
34522
+ setApp(data);
34523
+ }).catch((error) => {
34524
+ console.error("Error fetching apps:", error);
34525
+ });
34526
+ }, [tokenResponse]);
34527
+ return /* @__PURE__ */ React.createElement("div", null, code && /* @__PURE__ */ React.createElement("div", null, "Code: ", /* @__PURE__ */ React.createElement("pre", null, code), /* @__PURE__ */ React.createElement("br", null)), state && /* @__PURE__ */ React.createElement("div", null, "State: ", /* @__PURE__ */ React.createElement("pre", null, state), /* @__PURE__ */ React.createElement("br", null)), tokenResponse && /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", null, "Token Response:"), /* @__PURE__ */ React.createElement("pre", null, tokenResponse.access_token), /* @__PURE__ */ React.createElement("br", null)), /* @__PURE__ */ React.createElement("div", null, app && /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", null, "Project Name: ", app.name), /* @__PURE__ */ React.createElement("p", null, "Project ID: ", /* @__PURE__ */ React.createElement("pre", null, app.id)))));
34528
+ }
34281
34529
  const IndexingPage = () => {
34282
34530
  const cms = useCMS$1();
34283
34531
  const tinaApi = cms.api.tina;
@@ -34342,7 +34590,7 @@ const IndexingPage = () => {
34342
34590
  } catch {
34343
34591
  cms.alerts.error("Branch indexing failed.");
34344
34592
  setErrorMessage(
34345
- 'Branch indexing failed, please check the Tina Cloud dashboard for more information. To try again chick "re-index" on the branch in the dashboard.'
34593
+ 'Branch indexing failed, please check the TinaCloud dashboard for more information. To try again chick "re-index" on the branch in the dashboard.'
34346
34594
  );
34347
34595
  setState("error");
34348
34596
  }
@@ -34510,7 +34758,7 @@ const CheckSchema = ({
34510
34758
  );
34511
34759
  }
34512
34760
  }).catch((e) => {
34513
- if (e.message.includes("has not been indexed by Tina Cloud")) {
34761
+ if (e.message.includes("has not been indexed by TinaCloud")) {
34514
34762
  setSchemaMissingError(true);
34515
34763
  } else {
34516
34764
  cms.alerts.error(`Unexpected error checking schema: ${e}`);
@@ -34625,6 +34873,18 @@ const TinaAdmin = ({
34625
34873
  path: "screens/:screenName",
34626
34874
  element: /* @__PURE__ */ React__default.createElement(DefaultWrapper, { cms }, /* @__PURE__ */ React__default.createElement(ScreenPage, null))
34627
34875
  }
34876
+ ), /* @__PURE__ */ React__default.createElement(
34877
+ Route,
34878
+ {
34879
+ path: "auth/callback",
34880
+ element: /* @__PURE__ */ React__default.createElement(DefaultWrapper, { cms }, /* @__PURE__ */ React__default.createElement(
34881
+ AuthCallback,
34882
+ {
34883
+ clientId: tinaClient.clientId,
34884
+ identityApiUrl: tinaClient.identityApiUrl
34885
+ }
34886
+ ))
34887
+ }
34628
34888
  ), /* @__PURE__ */ React__default.createElement(
34629
34889
  Route,
34630
34890
  {