tinacms 0.57.3 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -397,6 +397,7 @@ var __objRest = (source, exclude) => {
397
397
  class Client {
398
398
  constructor(_a) {
399
399
  var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
400
+ this.events = new toolkit.EventBus();
400
401
  this.addPendingContent = async (props) => {
401
402
  const mutation = `#graphql
402
403
  mutation addPendingDocumentMutation(
@@ -437,8 +438,7 @@ mutation addPendingDocumentMutation(
437
438
  };
438
439
  this.options = options;
439
440
  this.setBranch(options.branch);
440
- this.events = new toolkit.EventBus();
441
- this.events.subscribe("branch-switcher:change-branch", ({ branchName }) => {
441
+ this.events.subscribe("branch:change", ({ branchName }) => {
442
442
  this.setBranch(branchName);
443
443
  });
444
444
  this.clientId = options.clientId;
@@ -489,8 +489,8 @@ mutation addPendingDocumentMutation(
489
489
  const encodedBranch = encodeURIComponent(branchName);
490
490
  this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
491
491
  this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
492
- const contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
493
- this.contentApiUrl = this.options.customContentApiUrl || `${contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
492
+ this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
493
+ this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
494
494
  }
495
495
  async requestWithForm(query, { variables }) {
496
496
  const schema = await this.getSchema();
@@ -555,28 +555,24 @@ mutation addPendingDocumentMutation(
555
555
  return null;
556
556
  }
557
557
  }
558
- async listBranches({ owner, repo }) {
559
- const url = `${this.contentApiUrl}/list_branches?owner=${owner}&repo=${repo}`;
560
- try {
561
- const res = await this.fetchWithToken(url, {
562
- method: "GET"
563
- });
564
- return JSON.stringify(res);
565
- } catch (e) {
566
- console.error("There was an issue fetching the branch list.", e);
567
- return null;
568
- }
558
+ async listBranches() {
559
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
560
+ const res = await this.fetchWithToken(url, {
561
+ method: "GET"
562
+ });
563
+ return res.json();
569
564
  }
570
- async createBranch({ owner, repo, baseBranch, branchName }) {
571
- const url = `${this.contentApiUrl}/create_branch`;
565
+ async createBranch({ baseBranch, branchName }) {
566
+ const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
572
567
  try {
573
568
  const res = await this.fetchWithToken(url, {
574
569
  method: "POST",
575
570
  body: {
576
- owner,
577
- repo,
578
571
  baseBranch,
579
572
  branchName
573
+ },
574
+ headers: {
575
+ "Content-Type": "application/json"
580
576
  }
581
577
  });
582
578
  return JSON.stringify(res);
@@ -758,63 +754,165 @@ mutation addPendingDocumentMutation(
758
754
  }), showChildren ? children : loginScreen ? loginScreen : null);
759
755
  };
760
756
  const TinaCloudProvider = (props) => {
757
+ const baseBranch = props.branch || "main";
758
+ const [currentBranch, setCurrentBranch] = toolkit.useLocalStorage("tinacms-current-branch", baseBranch);
761
759
  useTinaAuthRedirect();
762
760
  const cms = React__default["default"].useMemo(() => props.cms || new toolkit.TinaCMS({
763
761
  enabled: true,
764
762
  sidebar: true
765
763
  }), [props.cms]);
766
764
  if (!cms.api.tina) {
767
- cms.api.tina = createClient(props);
765
+ cms.registerApi("tina", createClient(props));
768
766
  }
769
767
  const setupMedia = async () => {
768
+ var _a;
770
769
  if (props.mediaStore) {
771
- cms.media.store = new (await props.mediaStore)(cms.api.tina);
770
+ if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
771
+ cms.media.store = new props.mediaStore(cms.api.tina);
772
+ } else {
773
+ const MediaClass = await props.mediaStore();
774
+ cms.media.store = new MediaClass(cms.api.tina);
775
+ }
772
776
  }
773
777
  };
774
778
  const handleListBranches = async () => {
775
779
  const { owner, repo } = props;
776
780
  const branches = await cms.api.tina.listBranches({ owner, repo });
777
- return branches.map((branch) => branch.name);
781
+ if (!Array.isArray(branches)) {
782
+ return [];
783
+ }
784
+ return branches;
778
785
  };
779
786
  const handleCreateBranch = async (data) => {
780
787
  const newBranch = await cms.api.tina.createBranch(data);
781
788
  return newBranch;
782
789
  };
783
790
  setupMedia();
784
- const branchingEnabled = cms.flags.get("branch-switcher");
791
+ const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
792
+ React__default["default"].useEffect(() => {
793
+ cms.events.subscribe("flag:set", ({ key, value }) => {
794
+ if (key === "branch-switcher") {
795
+ setBranchingEnabled(value);
796
+ }
797
+ });
798
+ }, [cms.events]);
785
799
  React__default["default"].useEffect(() => {
786
800
  let branchSwitcher;
787
801
  if (branchingEnabled) {
788
802
  branchSwitcher = new toolkit.BranchSwitcherPlugin({
789
- cms,
790
- owner: props.owner,
791
- repo: props.repo,
792
- baseBranch: props.branch || "main",
793
- currentBranch: props.branch || "main",
794
803
  listBranches: handleListBranches,
795
- createBranch: handleCreateBranch,
796
- setCurrentBranch: () => console.log(props.branch)
804
+ createBranch: handleCreateBranch
797
805
  });
798
806
  cms.plugins.add(branchSwitcher);
799
807
  }
800
808
  return () => {
801
- if (!branchingEnabled) {
802
- if (branchSwitcher) {
803
- cms.plugins.remove(branchSwitcher);
804
- }
809
+ if (branchingEnabled && branchSwitcher) {
810
+ cms.plugins.remove(branchSwitcher);
805
811
  }
806
812
  };
807
813
  }, [branchingEnabled, props.branch]);
808
- if (props.cmsCallback) {
809
- props.cmsCallback(cms);
810
- }
811
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
814
+ React__default["default"].useEffect(() => {
815
+ if (props.cmsCallback) {
816
+ props.cmsCallback(cms);
817
+ }
818
+ }, []);
819
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchDataProvider, {
820
+ currentBranch,
821
+ setCurrentBranch: (b) => {
822
+ setCurrentBranch(b);
823
+ }
824
+ }, /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
812
825
  cms
813
826
  }, /* @__PURE__ */ React__default["default"].createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
814
827
  cms
815
- })));
828
+ }))));
816
829
  };
817
830
  const TinaCloudAuthWall = TinaCloudProvider;
831
+ var DefaultContext = {
832
+ color: void 0,
833
+ size: void 0,
834
+ className: void 0,
835
+ style: void 0,
836
+ attr: void 0
837
+ };
838
+ var IconContext = React__default["default"].createContext && React__default["default"].createContext(DefaultContext);
839
+ var __assign = function() {
840
+ __assign = Object.assign || function(t) {
841
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
842
+ s = arguments[i];
843
+ for (var p in s)
844
+ if (Object.prototype.hasOwnProperty.call(s, p))
845
+ t[p] = s[p];
846
+ }
847
+ return t;
848
+ };
849
+ return __assign.apply(this, arguments);
850
+ };
851
+ var __rest = function(s, e) {
852
+ var t = {};
853
+ for (var p in s)
854
+ if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
855
+ t[p] = s[p];
856
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
857
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
858
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
859
+ t[p[i]] = s[p[i]];
860
+ }
861
+ return t;
862
+ };
863
+ function Tree2Element(tree) {
864
+ return tree && tree.map(function(node, i) {
865
+ return React__default["default"].createElement(node.tag, __assign({
866
+ key: i
867
+ }, node.attr), Tree2Element(node.child));
868
+ });
869
+ }
870
+ function GenIcon(data) {
871
+ return function(props) {
872
+ return React__default["default"].createElement(IconBase, __assign({
873
+ attr: __assign({}, data.attr)
874
+ }, props), Tree2Element(data.child));
875
+ };
876
+ }
877
+ function IconBase(props) {
878
+ var elem = function(conf) {
879
+ var attr = props.attr, size = props.size, title = props.title, svgProps = __rest(props, ["attr", "size", "title"]);
880
+ var computedSize = size || conf.size || "1em";
881
+ var className;
882
+ if (conf.className)
883
+ className = conf.className;
884
+ if (props.className)
885
+ className = (className ? className + " " : "") + props.className;
886
+ return React__default["default"].createElement("svg", __assign({
887
+ stroke: "currentColor",
888
+ fill: "currentColor",
889
+ strokeWidth: "0"
890
+ }, conf.attr, attr, svgProps, {
891
+ className,
892
+ style: __assign(__assign({
893
+ color: props.color || conf.color
894
+ }, conf.style), props.style),
895
+ height: computedSize,
896
+ width: computedSize,
897
+ xmlns: "http://www.w3.org/2000/svg"
898
+ }), title && React__default["default"].createElement("title", null, title), props.children);
899
+ };
900
+ return IconContext !== void 0 ? React__default["default"].createElement(IconContext.Consumer, null, function(conf) {
901
+ return elem(conf);
902
+ }) : elem(DefaultContext);
903
+ }
904
+ function BiEdit(props) {
905
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m7 17.013 4.413-.015 9.632-9.54c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.756-.756-2.075-.752-2.825-.003L7 12.583v4.43zM18.045 4.458l1.589 1.583-1.597 1.582-1.586-1.585 1.594-1.58zM9 13.417l6.03-5.973 1.586 1.586-6.029 5.971L9 15.006v-1.589z" } }, { "tag": "path", "attr": { "d": "M5 21h14c1.103 0 2-.897 2-2v-8.668l-2 2V19H8.158c-.026 0-.053.01-.079.01-.033 0-.066-.009-.1-.01H5V5h6.847l2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2z" } }] })(props);
906
+ }
907
+ function BiExit(props) {
908
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M19.002 3h-14c-1.103 0-2 .897-2 2v4h2V5h14v14h-14v-4h-2v4c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2V5c0-1.103-.898-2-2-2z" } }, { "tag": "path", "attr": { "d": "m11 16 5-4-5-4v3.001H3v2h8z" } }] })(props);
909
+ }
910
+ function BiLinkExternal(props) {
911
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 3 3.293 3.293-7 7 1.414 1.414 7-7L21 11V3z" } }, { "tag": "path", "attr": { "d": "M19 19H5V5h7l-2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2v-5l-2-2v7z" } }] })(props);
912
+ }
913
+ function BiLogIn(props) {
914
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 16 5-4-5-4v3H4v2h9z" } }, { "tag": "path", "attr": { "d": "M20 3h-9c-1.103 0-2 .897-2 2v4h2V5h9v14h-9v-4H9v4c0 1.103.897 2 2 2h9c1.103 0 2-.897 2-2V5c0-1.103-.897-2-2-2z" } }] })(props);
915
+ }
818
916
  function useGraphqlForms({
819
917
  query,
820
918
  variables,
@@ -828,7 +926,7 @@ mutation addPendingDocumentMutation(
828
926
  const [pendingReset, setPendingReset] = React__default["default"].useState(null);
829
927
  const [isLoading, setIsLoading] = React__default["default"].useState(true);
830
928
  const [newUpdate, setNewUpdate] = React__default["default"].useState(null);
831
- React__default["default"].useState([]);
929
+ const { currentBranch } = toolkit.useBranchData();
832
930
  const updateData = async () => {
833
931
  var _a;
834
932
  if (newUpdate) {
@@ -877,12 +975,15 @@ mutation addPendingDocumentMutation(
877
975
  }
878
976
  }, [pendingReset]);
879
977
  React__default["default"].useEffect(() => {
978
+ const formIds = [];
880
979
  setIsLoading(true);
881
980
  cms.api.tina.requestWithForm(query, { variables }).then((payload) => {
981
+ cms.plugins.remove(new toolkit.FormMetaPlugin({ name: "tina-admin-link" }));
882
982
  setData(payload);
883
983
  setInitialData(payload);
884
984
  setIsLoading(false);
885
985
  Object.entries(payload).map(([queryName, result]) => {
986
+ formIds.push(queryName);
886
987
  const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
887
988
  values: yup2.object().required(),
888
989
  form: yup2.object().required()
@@ -894,6 +995,32 @@ mutation addPendingDocumentMutation(
894
995
  values: yup2.object().required(),
895
996
  form: yup2.object().required()
896
997
  }), `Unable to build form shape for fields at ${queryName}`);
998
+ if (cms.flags.get("tina-admin")) {
999
+ const TinaAdminLink = new toolkit.FormMetaPlugin({
1000
+ name: "tina-admin-link",
1001
+ Component: () => /* @__PURE__ */ React__default["default"].createElement("a", {
1002
+ href: `/admin/collections/${result._internalSys.collection.name}/${result._internalSys.filename}`,
1003
+ style: {
1004
+ display: "flex",
1005
+ alignItems: "center",
1006
+ padding: "10px 20px",
1007
+ borderTop: "1px solid var(--tina-color-grey-2)",
1008
+ textTransform: "uppercase",
1009
+ fontSize: "11px",
1010
+ fontWeight: 500,
1011
+ background: "var(--tina-color-grey-0)"
1012
+ }
1013
+ }, /* @__PURE__ */ React__default["default"].createElement(BiLinkExternal, {
1014
+ style: {
1015
+ height: "1.25em",
1016
+ width: "auto",
1017
+ opacity: "0.8",
1018
+ marginRight: "8px"
1019
+ }
1020
+ }), " ", "Edit in Tina Admin")
1021
+ });
1022
+ cms.plugins.add(TinaAdminLink);
1023
+ }
897
1024
  const formConfig = {
898
1025
  id: queryName,
899
1026
  label: result.form.label,
@@ -1002,7 +1129,15 @@ mutation addPendingDocumentMutation(
1002
1129
  console.error(e);
1003
1130
  setIsLoading(false);
1004
1131
  });
1005
- }, [queryString, JSON.stringify(variables)]);
1132
+ return () => {
1133
+ formIds.forEach((name) => {
1134
+ const formPlugin = cms.forms.find(name);
1135
+ if (formPlugin) {
1136
+ cms.forms.remove(formPlugin);
1137
+ }
1138
+ });
1139
+ };
1140
+ }, [queryString, JSON.stringify(variables), currentBranch]);
1006
1141
  return [data, isLoading];
1007
1142
  }
1008
1143
  const transformDocumentIntoMutationRequestPayload = (document2, instructions) => {
@@ -1061,9 +1196,9 @@ mutation addPendingDocumentMutation(
1061
1196
  cms.forms.add(form);
1062
1197
  return form;
1063
1198
  };
1064
- const createGlobalForm = (formConfig) => {
1199
+ const createGlobalForm = (formConfig, options) => {
1065
1200
  const form = new toolkit.Form(formConfig);
1066
- cms.plugins.add(new toolkit.GlobalFormPlugin(form));
1201
+ cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
1067
1202
  return form;
1068
1203
  };
1069
1204
  return { createForm, createGlobalForm };
@@ -1475,81 +1610,12 @@ This will work when developing locally but NOT when deployed to production.
1475
1610
  }
1476
1611
  return client.request(query, { variables });
1477
1612
  };
1478
- function gql(strings) {
1479
- return strings[0];
1480
- }
1481
- var DefaultContext = {
1482
- color: void 0,
1483
- size: void 0,
1484
- className: void 0,
1485
- style: void 0,
1486
- attr: void 0
1487
- };
1488
- var IconContext = React__default["default"].createContext && React__default["default"].createContext(DefaultContext);
1489
- var __assign = function() {
1490
- __assign = Object.assign || function(t) {
1491
- for (var s, i = 1, n = arguments.length; i < n; i++) {
1492
- s = arguments[i];
1493
- for (var p in s)
1494
- if (Object.prototype.hasOwnProperty.call(s, p))
1495
- t[p] = s[p];
1496
- }
1497
- return t;
1498
- };
1499
- return __assign.apply(this, arguments);
1500
- };
1501
- var __rest = function(s, e) {
1502
- var t = {};
1503
- for (var p in s)
1504
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
1505
- t[p] = s[p];
1506
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
1507
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
1508
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
1509
- t[p[i]] = s[p[i]];
1510
- }
1511
- return t;
1512
- };
1513
- function Tree2Element(tree) {
1514
- return tree && tree.map(function(node, i) {
1515
- return React__default["default"].createElement(node.tag, __assign({
1516
- key: i
1517
- }, node.attr), Tree2Element(node.child));
1613
+ function gql(strings, ...args) {
1614
+ let str = "";
1615
+ strings.forEach((string, i) => {
1616
+ str += string + (args[i] || "");
1518
1617
  });
1519
- }
1520
- function GenIcon(data) {
1521
- return function(props) {
1522
- return React__default["default"].createElement(IconBase, __assign({
1523
- attr: __assign({}, data.attr)
1524
- }, props), Tree2Element(data.child));
1525
- };
1526
- }
1527
- function IconBase(props) {
1528
- var elem = function(conf) {
1529
- var attr = props.attr, size = props.size, title = props.title, svgProps = __rest(props, ["attr", "size", "title"]);
1530
- var computedSize = size || conf.size || "1em";
1531
- var className;
1532
- if (conf.className)
1533
- className = conf.className;
1534
- if (props.className)
1535
- className = (className ? className + " " : "") + props.className;
1536
- return React__default["default"].createElement("svg", __assign({
1537
- stroke: "currentColor",
1538
- fill: "currentColor",
1539
- strokeWidth: "0"
1540
- }, conf.attr, attr, svgProps, {
1541
- className,
1542
- style: __assign(__assign({
1543
- color: props.color || conf.color
1544
- }, conf.style), props.style),
1545
- height: computedSize,
1546
- width: computedSize,
1547
- xmlns: "http://www.w3.org/2000/svg"
1548
- }), title && React__default["default"].createElement("title", null, title), props.children);
1549
- };
1550
- return IconContext !== void 0 ? React__default["default"].createElement(IconContext.Consumer, null, function(conf) {
1551
- return elem(conf);
1552
- }) : elem(DefaultContext);
1618
+ return str;
1553
1619
  }
1554
1620
  function ImFilesEmpty(props) {
1555
1621
  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" } }, { "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" } }] })(props);
@@ -1596,15 +1662,6 @@ This will work when developing locally but NOT when deployed to production.
1596
1662
  return null;
1597
1663
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(collections));
1598
1664
  };
1599
- function BiEdit(props) {
1600
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m7 17.013 4.413-.015 9.632-9.54c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.756-.756-2.075-.752-2.825-.003L7 12.583v4.43zM18.045 4.458l1.589 1.583-1.597 1.582-1.586-1.585 1.594-1.58zM9 13.417l6.03-5.973 1.586 1.586-6.029 5.971L9 15.006v-1.589z" } }, { "tag": "path", "attr": { "d": "M5 21h14c1.103 0 2-.897 2-2v-8.668l-2 2V19H8.158c-.026 0-.053.01-.079.01-.033 0-.066-.009-.1-.01H5V5h6.847l2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2z" } }] })(props);
1601
- }
1602
- function BiExit(props) {
1603
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M19.002 3h-14c-1.103 0-2 .897-2 2v4h2V5h14v14h-14v-4h-2v4c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2V5c0-1.103-.898-2-2-2z" } }, { "tag": "path", "attr": { "d": "m11 16 5-4-5-4v3.001H3v2h8z" } }] })(props);
1604
- }
1605
- function BiLogIn(props) {
1606
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 16 5-4-5-4v3H4v2h9z" } }, { "tag": "path", "attr": { "d": "M20 3h-9c-1.103 0-2 .897-2 2v4h2V5h9v14h-9v-4H9v4c0 1.103.897 2 2 2h9c1.103 0 2-.897 2-2V5c0-1.103-.897-2-2-2z" } }] })(props);
1607
- }
1608
1665
  function MdOutlineArrowBack(props) {
1609
1666
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0V0z" } }, { "tag": "path", "attr": { "d": "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" } }] })(props);
1610
1667
  }
@@ -1677,12 +1734,14 @@ This will work when developing locally but NOT when deployed to production.
1677
1734
  name
1678
1735
  label
1679
1736
  format
1737
+ templates
1680
1738
  documents @include(if: $includeDocuments) {
1681
1739
  totalCount
1682
1740
  edges {
1683
1741
  node {
1684
1742
  ... on Document {
1685
1743
  sys {
1744
+ template
1686
1745
  breadcrumbs
1687
1746
  path
1688
1747
  basename
@@ -1714,59 +1773,119 @@ This will work when developing locally but NOT when deployed to production.
1714
1773
  }
1715
1774
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(collection));
1716
1775
  };
1776
+ const TemplateMenu = ({ templates }) => {
1777
+ return /* @__PURE__ */ React__default["default"].createElement(react.Menu, {
1778
+ as: "div",
1779
+ className: "relative inline-block text-left"
1780
+ }, ({ open }) => /* @__PURE__ */ React__default["default"].createElement("div", null, /* @__PURE__ */ React__default["default"].createElement("div", null, /* @__PURE__ */ React__default["default"].createElement(react.Menu.Button, {
1781
+ className: "inline-flex items-center px-8 py-2.5 shadow-sm border border-transparent text-sm leading-4 font-medium rounded-full text-white hover:opacity-80 focus:outline-none focus:shadow-outline-blue transition duration-150 ease-out",
1782
+ style: { background: "#0084FF" }
1783
+ }, "Create New", /* @__PURE__ */ React__default["default"].createElement("svg", {
1784
+ width: "20",
1785
+ height: "20",
1786
+ viewBox: "0 0 20 20",
1787
+ fill: "none",
1788
+ xmlns: "http://www.w3.org/2000/svg",
1789
+ className: `ml-1 flex-0 inline-block opacity-50 group-hover:opacity-80 transition-all duration-300 ease-in-out transform ${open ? `rotate-90 opacity-100` : `rotate-0`}`
1790
+ }, /* @__PURE__ */ React__default["default"].createElement("g", {
1791
+ opacity: "1.0"
1792
+ }, /* @__PURE__ */ React__default["default"].createElement("path", {
1793
+ d: "M7.91675 13.8086L9.16675 15.0586L14.2253 10L9.16675 4.9414L7.91675 6.1914L11.7253 10L7.91675 13.8086Z",
1794
+ fill: "currentColor"
1795
+ }))))), /* @__PURE__ */ React__default["default"].createElement(react.Transition, {
1796
+ as: React.Fragment,
1797
+ enter: "transition ease-out duration-100",
1798
+ enterFrom: "transform opacity-0 scale-95",
1799
+ enterTo: "transform opacity-100 scale-100",
1800
+ leave: "transition ease-in duration-75",
1801
+ leaveFrom: "transform opacity-100 scale-100",
1802
+ leaveTo: "transform opacity-0 scale-95"
1803
+ }, /* @__PURE__ */ React__default["default"].createElement(react.Menu.Items, {
1804
+ className: "origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
1805
+ }, /* @__PURE__ */ React__default["default"].createElement("div", {
1806
+ className: "py-1"
1807
+ }, templates.map((template) => /* @__PURE__ */ React__default["default"].createElement(react.Menu.Item, {
1808
+ key: `${template.label}-${template.name}`
1809
+ }, ({ active }) => /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1810
+ to: `${location.pathname}/${template.name}/new`,
1811
+ className: `w-full text-md px-4 py-2 tracking-wide flex items-center opacity-80 text-gray-600 ${active && "text-gray-800 opacity-100"}`
1812
+ }, template.label))))))));
1813
+ };
1717
1814
  const CollectionListPage = () => {
1718
- const location = reactRouterDom.useLocation();
1815
+ const location2 = reactRouterDom.useLocation();
1719
1816
  const { collectionName } = reactRouterDom.useParams();
1720
- return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
1721
- cms,
1722
- collectionName,
1723
- includeDocuments: true
1724
- }, (collection) => {
1725
- const totalCount = collection.documents.totalCount;
1726
- const documents = collection.documents.edges;
1727
- return /* @__PURE__ */ React__default["default"].createElement("div", {
1728
- className: "px-6 py-14 h-screen overflow-y-auto flex justify-center"
1729
- }, /* @__PURE__ */ React__default["default"].createElement("div", {
1730
- className: "max-w-screen-md w-full"
1731
- }, /* @__PURE__ */ React__default["default"].createElement("div", {
1732
- className: "w-full flex justify-between items-end"
1733
- }, /* @__PURE__ */ React__default["default"].createElement("h3", {
1734
- className: "text-3xl"
1735
- }, collection.label), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1736
- to: `${location.pathname}/new`,
1737
- className: "inline-flex items-center px-8 py-3 shadow-sm border border-transparent text-sm leading-4 font-medium rounded-full text-white hover:opacity-80 focus:outline-none focus:shadow-outline-blue transition duration-150 ease-out",
1738
- style: { background: "#0084FF" }
1739
- }, "Create New")), totalCount > 0 && /* @__PURE__ */ React__default["default"].createElement("div", {
1740
- className: "mt-8 shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"
1741
- }, /* @__PURE__ */ React__default["default"].createElement("table", {
1742
- className: "min-w-full"
1743
- }, /* @__PURE__ */ React__default["default"].createElement("tbody", {
1744
- className: "bg-white divide-y divide-gray-150"
1745
- }, documents.map((document2) => /* @__PURE__ */ React__default["default"].createElement("tr", {
1746
- key: document2.node.sys.relativePath
1747
- }, /* @__PURE__ */ React__default["default"].createElement("td", {
1748
- className: "px-6 py-2 whitespace-nowrap"
1749
- }, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1750
- to: `${location.pathname}/${document2.node.sys.filename}`,
1751
- className: "text-blue-600 hover:text-blue-400 flex items-center gap-3"
1752
- }, /* @__PURE__ */ React__default["default"].createElement(BiEdit, {
1753
- className: "inline-block h-6 w-auto opacity-70"
1754
- }), " ", /* @__PURE__ */ React__default["default"].createElement("span", null, /* @__PURE__ */ React__default["default"].createElement("span", {
1755
- className: "block text-xs text-gray-400 mb-1 uppercase"
1756
- }, "Filename"), /* @__PURE__ */ React__default["default"].createElement("span", {
1757
- className: "h-5 leading-5 block whitespace-nowrap"
1758
- }, document2.node.sys.filename)))), /* @__PURE__ */ React__default["default"].createElement("td", {
1759
- className: "px-6 py-4 whitespace-nowrap"
1760
- }, /* @__PURE__ */ React__default["default"].createElement("span", {
1761
- className: "block text-xs text-gray-400 mb-1 uppercase"
1762
- }, "Extension"), /* @__PURE__ */ React__default["default"].createElement("span", {
1763
- className: "h-5 leading-5 block text-sm font-medium text-gray-900"
1764
- }, document2.node.sys.extension)))))))));
1765
- }));
1817
+ return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => {
1818
+ const plugins = cms.plugins.all("tina-admin");
1819
+ const routeMapping = plugins.find(({ name }) => name === "route-mapping");
1820
+ return /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
1821
+ cms,
1822
+ collectionName,
1823
+ includeDocuments: true
1824
+ }, (collection) => {
1825
+ const totalCount = collection.documents.totalCount;
1826
+ const documents = collection.documents.edges;
1827
+ return /* @__PURE__ */ React__default["default"].createElement("div", {
1828
+ className: "px-6 py-14 h-screen overflow-y-auto flex justify-center"
1829
+ }, /* @__PURE__ */ React__default["default"].createElement("div", {
1830
+ className: "max-w-screen-md w-full"
1831
+ }, /* @__PURE__ */ React__default["default"].createElement("div", {
1832
+ className: "w-full flex justify-between items-end"
1833
+ }, /* @__PURE__ */ React__default["default"].createElement("h3", {
1834
+ className: "text-3xl"
1835
+ }, collection.label), !collection.templates && /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1836
+ to: `${location2.pathname}/new`,
1837
+ className: "inline-flex items-center px-8 py-3 shadow-sm border border-transparent text-sm leading-4 font-medium rounded-full text-white hover:opacity-80 focus:outline-none focus:shadow-outline-blue transition duration-150 ease-out",
1838
+ style: { background: "#0084FF" }
1839
+ }, "Create New"), collection.templates && /* @__PURE__ */ React__default["default"].createElement(TemplateMenu, {
1840
+ templates: collection.templates
1841
+ })), totalCount > 0 && /* @__PURE__ */ React__default["default"].createElement("div", {
1842
+ className: "mt-8 shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"
1843
+ }, /* @__PURE__ */ React__default["default"].createElement("table", {
1844
+ className: "min-w-full"
1845
+ }, /* @__PURE__ */ React__default["default"].createElement("tbody", {
1846
+ className: "bg-white divide-y divide-gray-150"
1847
+ }, documents.map((document2) => {
1848
+ const livesiteRoute = routeMapping ? routeMapping.mapper(collection, document2.node) : void 0;
1849
+ return /* @__PURE__ */ React__default["default"].createElement("tr", {
1850
+ key: document2.node.sys.relativePath
1851
+ }, /* @__PURE__ */ React__default["default"].createElement("td", {
1852
+ className: "px-5 py-3 whitespace-nowrap"
1853
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
1854
+ className: "block text-xs mb-0.5 text-gray-400 uppercase"
1855
+ }, "Filename"), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1856
+ to: `${location2.pathname}/${document2.node.sys.filename}`,
1857
+ className: "h-5 leading-5 block"
1858
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
1859
+ className: "leading-5 font-medium text-base overflow-ellipsis overflow-hidden whitespace-nowrap text-gray-700"
1860
+ }, document2.node.sys.filename), /* @__PURE__ */ React__default["default"].createElement("span", {
1861
+ className: "leading-5 text-base font-medium text-gray-300"
1862
+ }, document2.node.sys.extension))), /* @__PURE__ */ React__default["default"].createElement("td", {
1863
+ className: "px-5 py-3 whitespace-nowrap"
1864
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
1865
+ className: "block text-xs mb-0.5 text-gray-400 uppercase"
1866
+ }, "Template"), /* @__PURE__ */ React__default["default"].createElement("span", {
1867
+ className: "h-5 block leading-5 font-regular text-base overflow-ellipsis overflow-hidden whitespace-nowrap text-gray-500"
1868
+ }, document2.node.sys.template)), /* @__PURE__ */ React__default["default"].createElement("td", {
1869
+ className: "px-5 py-3 whitespace-nowrap flex gap-3 items-center justify-end"
1870
+ }, livesiteRoute && /* @__PURE__ */ React__default["default"].createElement("a", {
1871
+ href: livesiteRoute,
1872
+ className: "flex gap-1.5 items-center px-4 py-1.5 rounded-full transition-all ease-out duration-150 text-gray-500 hover:text-blue-500"
1873
+ }, /* @__PURE__ */ React__default["default"].createElement(BiLinkExternal, {
1874
+ className: "inline-block h-5 w-auto opacity-70"
1875
+ }), " ", "View"), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
1876
+ to: `${location2.pathname}/${document2.node.sys.filename}`,
1877
+ className: "flex gap-1.5 items-center px-4 py-1.5 rounded-full border border-gray-150 transition-all ease-out duration-150 text-gray-700 hover:bg-gray-50 hover:text-blue-500"
1878
+ }, /* @__PURE__ */ React__default["default"].createElement(BiEdit, {
1879
+ className: "inline-block h-5 w-auto opacity-70"
1880
+ }), " ", "Edit")));
1881
+ }))))));
1882
+ });
1883
+ });
1766
1884
  };
1767
- const useGetDocumentFields = (cms, collectionName) => {
1885
+ const useGetDocumentFields = (cms, collectionName, templateName) => {
1768
1886
  const [info, setInfo] = React.useState({
1769
1887
  collection: void 0,
1888
+ template: void 0,
1770
1889
  fields: void 0,
1771
1890
  mutationInfo: void 0
1772
1891
  });
@@ -1775,10 +1894,18 @@ This will work when developing locally but NOT when deployed to production.
1775
1894
  const response = await cms.api.tina.request(`query { getDocumentFields }`, {});
1776
1895
  const documentFields = response.getDocumentFields;
1777
1896
  const collection = documentFields[collectionName].collection;
1778
- const fields = documentFields[collectionName].fields;
1779
1897
  const mutationInfo = documentFields[collectionName].mutationInfo;
1898
+ let fields = void 0;
1899
+ let template = void 0;
1900
+ if (templateName && documentFields[collectionName].templates && documentFields[collectionName].templates[templateName]) {
1901
+ template = documentFields[collectionName].templates[templateName].template;
1902
+ fields = documentFields[collectionName].templates[templateName].fields;
1903
+ } else {
1904
+ fields = documentFields[collectionName].fields;
1905
+ }
1780
1906
  setInfo({
1781
1907
  collection,
1908
+ template,
1782
1909
  fields,
1783
1910
  mutationInfo
1784
1911
  });
@@ -1790,20 +1917,21 @@ This will work when developing locally but NOT when deployed to production.
1790
1917
  const GetDocumentFields = ({
1791
1918
  cms,
1792
1919
  collectionName,
1920
+ templateName,
1793
1921
  children
1794
1922
  }) => {
1795
- const { collection, fields, mutationInfo } = useGetDocumentFields(cms, collectionName);
1796
- if (!collection || !fields || !mutationInfo) {
1923
+ const { collection, template, fields, mutationInfo } = useGetDocumentFields(cms, collectionName, templateName);
1924
+ if (!collection) {
1797
1925
  return null;
1798
1926
  }
1799
- return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(collection, fields, mutationInfo));
1927
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children({ collection, template, fields, mutationInfo }));
1800
1928
  };
1801
- const createDocument = async (cms, collection, mutationInfo, values) => {
1929
+ const createDocument = async (cms, collection, template, mutationInfo, values) => {
1802
1930
  const _a = values, { relativePath } = _a, leftover = __objRest(_a, ["relativePath"]);
1803
1931
  const { includeCollection, includeTemplate } = mutationInfo;
1804
- const params = transformDocumentIntoMutationRequestPayload(__spreadValues({
1932
+ const params = transformDocumentIntoMutationRequestPayload(__spreadValues(__spreadValues({
1805
1933
  _collection: collection.name
1806
- }, leftover), {
1934
+ }, template && { _template: template.name }), leftover), {
1807
1935
  includeCollection,
1808
1936
  includeTemplate
1809
1937
  });
@@ -1822,12 +1950,13 @@ This will work when developing locally but NOT when deployed to production.
1822
1950
  });
1823
1951
  };
1824
1952
  const CollectionCreatePage = () => {
1825
- const { collectionName } = reactRouterDom.useParams();
1953
+ const { collectionName, templateName } = reactRouterDom.useParams();
1826
1954
  const history = reactRouterDom.useHistory();
1827
1955
  return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetDocumentFields, {
1828
1956
  cms,
1829
- collectionName
1830
- }, (collection, fields, mutationInfo) => {
1957
+ collectionName,
1958
+ templateName
1959
+ }, ({ collection, template, fields, mutationInfo }) => {
1831
1960
  const form = new toolkit.Form({
1832
1961
  id: "create-form",
1833
1962
  label: "form",
@@ -1842,16 +1971,17 @@ This will work when developing locally but NOT when deployed to production.
1842
1971
  ...fields
1843
1972
  ],
1844
1973
  onSubmit: async (values) => {
1845
- await createDocument(cms, collection, mutationInfo, values);
1974
+ await createDocument(cms, collection, template, mutationInfo, values);
1846
1975
  history.push(`/admin/collections/${collection.name}`);
1847
1976
  }
1848
1977
  });
1978
+ const formLabel = template ? `${collection.label} - Create New ${template.label}` : `${collection.label} - Create New`;
1849
1979
  return /* @__PURE__ */ React__default["default"].createElement("div", {
1850
1980
  className: "w-full h-screen"
1851
1981
  }, /* @__PURE__ */ React__default["default"].createElement("div", {
1852
1982
  className: "flex flex-col items-center w-full flex-1"
1853
1983
  }, /* @__PURE__ */ React__default["default"].createElement(toolkit.FullscreenFormBuilder, {
1854
- label: collection.label + " - Create New",
1984
+ label: formLabel,
1855
1985
  form
1856
1986
  })));
1857
1987
  }));
@@ -1887,15 +2017,15 @@ This will work when developing locally but NOT when deployed to production.
1887
2017
  }
1888
2018
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(document2));
1889
2019
  };
1890
- const updateDocument = async (cms, collection, document2, relativePath, values) => {
1891
- const { includeCollection, includeTemplate } = document2.form.mutationInfo;
2020
+ const updateDocument = async (cms, relativePath, collection, mutationInfo, values) => {
2021
+ const { includeCollection, includeTemplate } = mutationInfo;
1892
2022
  const params = transformDocumentIntoMutationRequestPayload(values, {
1893
2023
  includeCollection,
1894
2024
  includeTemplate
1895
2025
  });
1896
2026
  await cms.api.tina.request(`mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1897
- updateDocument(
1898
- collection: $collection,
2027
+ updateDocument(
2028
+ collection: $collection,
1899
2029
  relativePath: $relativePath,
1900
2030
  params: $params
1901
2031
  ){__typename}
@@ -1910,11 +2040,10 @@ This will work when developing locally but NOT when deployed to production.
1910
2040
  const CollectionUpdatePage = () => {
1911
2041
  const { collectionName, filename } = reactRouterDom.useParams();
1912
2042
  const history = reactRouterDom.useHistory();
1913
- return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
2043
+ return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetDocumentFields, {
1914
2044
  cms,
1915
- collectionName,
1916
- includeDocuments: false
1917
- }, (collection) => {
2045
+ collectionName
2046
+ }, ({ collection, mutationInfo }) => {
1918
2047
  const relativePath = `${filename}.${collection.format}`;
1919
2048
  return /* @__PURE__ */ React__default["default"].createElement(GetDocument, {
1920
2049
  cms,
@@ -1927,7 +2056,7 @@ This will work when developing locally but NOT when deployed to production.
1927
2056
  fields: document2.form.fields,
1928
2057
  initialValues: document2.values,
1929
2058
  onSubmit: async (values) => {
1930
- await updateDocument(cms, collection, document2, relativePath, values);
2059
+ await updateDocument(cms, relativePath, collection, mutationInfo, values);
1931
2060
  history.push(`/admin/collections/${collection.name}`);
1932
2061
  }
1933
2062
  });
@@ -2047,6 +2176,8 @@ This will work when developing locally but NOT when deployed to production.
2047
2176
  className: "flex-1"
2048
2177
  }, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Switch, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2049
2178
  path: `/admin/collections/:collectionName/new`
2179
+ }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null)), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2180
+ path: `/admin/collections/:collectionName/:templateName/new`
2050
2181
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null)), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2051
2182
  path: `/admin/collections/:collectionName/:filename`
2052
2183
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionUpdatePage, null)), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
@@ -2055,10 +2186,18 @@ This will work when developing locally but NOT when deployed to production.
2055
2186
  path: `/admin`
2056
2187
  }, /* @__PURE__ */ React__default["default"].createElement(DashboardPage, null)))))))));
2057
2188
  };
2189
+ class RouteMappingPlugin {
2190
+ constructor(mapper) {
2191
+ this.__type = "tina-admin";
2192
+ this.name = "route-mapping";
2193
+ this.mapper = mapper;
2194
+ }
2195
+ }
2058
2196
  exports2.AuthWallInner = AuthWallInner;
2059
2197
  exports2.Client = Client;
2060
2198
  exports2.DEFAULT_LOCAL_TINA_GQL_SERVER_URL = DEFAULT_LOCAL_TINA_GQL_SERVER_URL;
2061
2199
  exports2.LocalClient = LocalClient;
2200
+ exports2.RouteMappingPlugin = RouteMappingPlugin;
2062
2201
  exports2.TinaAdmin = TinaAdmin;
2063
2202
  exports2.TinaCMSProvider2 = TinaCMSProvider2;
2064
2203
  exports2.TinaCloudAuthWall = TinaCloudAuthWall;