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.es.js CHANGED
@@ -32,9 +32,9 @@ var __objRest = (source, exclude) => {
32
32
  import { TypeInfo, visit, visitWithTypeInfo, getNamedType, GraphQLObjectType, isLeafType, GraphQLUnionType, isScalarType, getIntrospectionQuery, buildClientSchema, print } from "graphql";
33
33
  import set from "lodash.set";
34
34
  import gql$1 from "graphql-tag";
35
- import { EventBus, StyleReset, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, TinaCMS, BranchSwitcherPlugin, TinaProvider, useCMS, Form, GlobalFormPlugin, FullscreenFormBuilder } from "@tinacms/toolkit";
35
+ import { EventBus, StyleReset, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, useCMS, useBranchData, FormMetaPlugin, Form, GlobalFormPlugin, FullscreenFormBuilder } from "@tinacms/toolkit";
36
36
  export * from "@tinacms/toolkit";
37
- import React, { useState, useCallback, useEffect } from "react";
37
+ import React, { useState, useCallback, useEffect, Fragment } from "react";
38
38
  import styled from "styled-components";
39
39
  import * as yup from "yup";
40
40
  import { getIn, setIn } from "final-form";
@@ -376,6 +376,7 @@ function assertIsUnionType(type) {
376
376
  class Client {
377
377
  constructor(_a) {
378
378
  var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
379
+ this.events = new EventBus();
379
380
  this.addPendingContent = async (props) => {
380
381
  const mutation = `#graphql
381
382
  mutation addPendingDocumentMutation(
@@ -416,8 +417,7 @@ mutation addPendingDocumentMutation(
416
417
  };
417
418
  this.options = options;
418
419
  this.setBranch(options.branch);
419
- this.events = new EventBus();
420
- this.events.subscribe("branch-switcher:change-branch", ({ branchName }) => {
420
+ this.events.subscribe("branch:change", ({ branchName }) => {
421
421
  this.setBranch(branchName);
422
422
  });
423
423
  this.clientId = options.clientId;
@@ -468,8 +468,8 @@ mutation addPendingDocumentMutation(
468
468
  const encodedBranch = encodeURIComponent(branchName);
469
469
  this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
470
470
  this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
471
- const contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
472
- this.contentApiUrl = this.options.customContentApiUrl || `${contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
471
+ this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
472
+ this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
473
473
  }
474
474
  async requestWithForm(query, { variables }) {
475
475
  const schema = await this.getSchema();
@@ -534,28 +534,24 @@ mutation addPendingDocumentMutation(
534
534
  return null;
535
535
  }
536
536
  }
537
- async listBranches({ owner, repo }) {
538
- const url = `${this.contentApiUrl}/list_branches?owner=${owner}&repo=${repo}`;
539
- try {
540
- const res = await this.fetchWithToken(url, {
541
- method: "GET"
542
- });
543
- return JSON.stringify(res);
544
- } catch (e) {
545
- console.error("There was an issue fetching the branch list.", e);
546
- return null;
547
- }
537
+ async listBranches() {
538
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
539
+ const res = await this.fetchWithToken(url, {
540
+ method: "GET"
541
+ });
542
+ return res.json();
548
543
  }
549
- async createBranch({ owner, repo, baseBranch, branchName }) {
550
- const url = `${this.contentApiUrl}/create_branch`;
544
+ async createBranch({ baseBranch, branchName }) {
545
+ const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
551
546
  try {
552
547
  const res = await this.fetchWithToken(url, {
553
548
  method: "POST",
554
549
  body: {
555
- owner,
556
- repo,
557
550
  baseBranch,
558
551
  branchName
552
+ },
553
+ headers: {
554
+ "Content-Type": "application/json"
559
555
  }
560
556
  });
561
557
  return JSON.stringify(res);
@@ -737,63 +733,165 @@ const AuthWallInner = ({
737
733
  }), showChildren ? children : loginScreen ? loginScreen : null);
738
734
  };
739
735
  const TinaCloudProvider = (props) => {
736
+ const baseBranch = props.branch || "main";
737
+ const [currentBranch, setCurrentBranch] = useLocalStorage("tinacms-current-branch", baseBranch);
740
738
  useTinaAuthRedirect();
741
739
  const cms = React.useMemo(() => props.cms || new TinaCMS({
742
740
  enabled: true,
743
741
  sidebar: true
744
742
  }), [props.cms]);
745
743
  if (!cms.api.tina) {
746
- cms.api.tina = createClient(props);
744
+ cms.registerApi("tina", createClient(props));
747
745
  }
748
746
  const setupMedia = async () => {
747
+ var _a;
749
748
  if (props.mediaStore) {
750
- cms.media.store = new (await props.mediaStore)(cms.api.tina);
749
+ if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
750
+ cms.media.store = new props.mediaStore(cms.api.tina);
751
+ } else {
752
+ const MediaClass = await props.mediaStore();
753
+ cms.media.store = new MediaClass(cms.api.tina);
754
+ }
751
755
  }
752
756
  };
753
757
  const handleListBranches = async () => {
754
758
  const { owner, repo } = props;
755
759
  const branches = await cms.api.tina.listBranches({ owner, repo });
756
- return branches.map((branch) => branch.name);
760
+ if (!Array.isArray(branches)) {
761
+ return [];
762
+ }
763
+ return branches;
757
764
  };
758
765
  const handleCreateBranch = async (data) => {
759
766
  const newBranch = await cms.api.tina.createBranch(data);
760
767
  return newBranch;
761
768
  };
762
769
  setupMedia();
763
- const branchingEnabled = cms.flags.get("branch-switcher");
770
+ const [branchingEnabled, setBranchingEnabled] = React.useState(() => cms.flags.get("branch-switcher"));
771
+ React.useEffect(() => {
772
+ cms.events.subscribe("flag:set", ({ key, value }) => {
773
+ if (key === "branch-switcher") {
774
+ setBranchingEnabled(value);
775
+ }
776
+ });
777
+ }, [cms.events]);
764
778
  React.useEffect(() => {
765
779
  let branchSwitcher;
766
780
  if (branchingEnabled) {
767
781
  branchSwitcher = new BranchSwitcherPlugin({
768
- cms,
769
- owner: props.owner,
770
- repo: props.repo,
771
- baseBranch: props.branch || "main",
772
- currentBranch: props.branch || "main",
773
782
  listBranches: handleListBranches,
774
- createBranch: handleCreateBranch,
775
- setCurrentBranch: () => console.log(props.branch)
783
+ createBranch: handleCreateBranch
776
784
  });
777
785
  cms.plugins.add(branchSwitcher);
778
786
  }
779
787
  return () => {
780
- if (!branchingEnabled) {
781
- if (branchSwitcher) {
782
- cms.plugins.remove(branchSwitcher);
783
- }
788
+ if (branchingEnabled && branchSwitcher) {
789
+ cms.plugins.remove(branchSwitcher);
784
790
  }
785
791
  };
786
792
  }, [branchingEnabled, props.branch]);
787
- if (props.cmsCallback) {
788
- props.cmsCallback(cms);
789
- }
790
- return /* @__PURE__ */ React.createElement(TinaProvider, {
793
+ React.useEffect(() => {
794
+ if (props.cmsCallback) {
795
+ props.cmsCallback(cms);
796
+ }
797
+ }, []);
798
+ return /* @__PURE__ */ React.createElement(BranchDataProvider, {
799
+ currentBranch,
800
+ setCurrentBranch: (b) => {
801
+ setCurrentBranch(b);
802
+ }
803
+ }, /* @__PURE__ */ React.createElement(TinaProvider, {
791
804
  cms
792
805
  }, /* @__PURE__ */ React.createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
793
806
  cms
794
- })));
807
+ }))));
795
808
  };
796
809
  const TinaCloudAuthWall = TinaCloudProvider;
810
+ var DefaultContext = {
811
+ color: void 0,
812
+ size: void 0,
813
+ className: void 0,
814
+ style: void 0,
815
+ attr: void 0
816
+ };
817
+ var IconContext = React.createContext && React.createContext(DefaultContext);
818
+ var __assign = function() {
819
+ __assign = Object.assign || function(t) {
820
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
821
+ s = arguments[i];
822
+ for (var p in s)
823
+ if (Object.prototype.hasOwnProperty.call(s, p))
824
+ t[p] = s[p];
825
+ }
826
+ return t;
827
+ };
828
+ return __assign.apply(this, arguments);
829
+ };
830
+ var __rest = function(s, e) {
831
+ var t = {};
832
+ for (var p in s)
833
+ if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
834
+ t[p] = s[p];
835
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
836
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
837
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
838
+ t[p[i]] = s[p[i]];
839
+ }
840
+ return t;
841
+ };
842
+ function Tree2Element(tree) {
843
+ return tree && tree.map(function(node, i) {
844
+ return React.createElement(node.tag, __assign({
845
+ key: i
846
+ }, node.attr), Tree2Element(node.child));
847
+ });
848
+ }
849
+ function GenIcon(data) {
850
+ return function(props) {
851
+ return React.createElement(IconBase, __assign({
852
+ attr: __assign({}, data.attr)
853
+ }, props), Tree2Element(data.child));
854
+ };
855
+ }
856
+ function IconBase(props) {
857
+ var elem = function(conf) {
858
+ var attr = props.attr, size = props.size, title = props.title, svgProps = __rest(props, ["attr", "size", "title"]);
859
+ var computedSize = size || conf.size || "1em";
860
+ var className;
861
+ if (conf.className)
862
+ className = conf.className;
863
+ if (props.className)
864
+ className = (className ? className + " " : "") + props.className;
865
+ return React.createElement("svg", __assign({
866
+ stroke: "currentColor",
867
+ fill: "currentColor",
868
+ strokeWidth: "0"
869
+ }, conf.attr, attr, svgProps, {
870
+ className,
871
+ style: __assign(__assign({
872
+ color: props.color || conf.color
873
+ }, conf.style), props.style),
874
+ height: computedSize,
875
+ width: computedSize,
876
+ xmlns: "http://www.w3.org/2000/svg"
877
+ }), title && React.createElement("title", null, title), props.children);
878
+ };
879
+ return IconContext !== void 0 ? React.createElement(IconContext.Consumer, null, function(conf) {
880
+ return elem(conf);
881
+ }) : elem(DefaultContext);
882
+ }
883
+ function BiEdit(props) {
884
+ 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);
885
+ }
886
+ function BiExit(props) {
887
+ 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);
888
+ }
889
+ function BiLinkExternal(props) {
890
+ 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);
891
+ }
892
+ function BiLogIn(props) {
893
+ 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);
894
+ }
797
895
  function useGraphqlForms({
798
896
  query,
799
897
  variables,
@@ -807,7 +905,7 @@ function useGraphqlForms({
807
905
  const [pendingReset, setPendingReset] = React.useState(null);
808
906
  const [isLoading, setIsLoading] = React.useState(true);
809
907
  const [newUpdate, setNewUpdate] = React.useState(null);
810
- React.useState([]);
908
+ const { currentBranch } = useBranchData();
811
909
  const updateData = async () => {
812
910
  var _a;
813
911
  if (newUpdate) {
@@ -856,12 +954,15 @@ function useGraphqlForms({
856
954
  }
857
955
  }, [pendingReset]);
858
956
  React.useEffect(() => {
957
+ const formIds = [];
859
958
  setIsLoading(true);
860
959
  cms.api.tina.requestWithForm(query, { variables }).then((payload) => {
960
+ cms.plugins.remove(new FormMetaPlugin({ name: "tina-admin-link" }));
861
961
  setData(payload);
862
962
  setInitialData(payload);
863
963
  setIsLoading(false);
864
964
  Object.entries(payload).map(([queryName, result]) => {
965
+ formIds.push(queryName);
865
966
  const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
866
967
  values: yup2.object().required(),
867
968
  form: yup2.object().required()
@@ -873,6 +974,32 @@ function useGraphqlForms({
873
974
  values: yup2.object().required(),
874
975
  form: yup2.object().required()
875
976
  }), `Unable to build form shape for fields at ${queryName}`);
977
+ if (cms.flags.get("tina-admin")) {
978
+ const TinaAdminLink = new FormMetaPlugin({
979
+ name: "tina-admin-link",
980
+ Component: () => /* @__PURE__ */ React.createElement("a", {
981
+ href: `/admin/collections/${result._internalSys.collection.name}/${result._internalSys.filename}`,
982
+ style: {
983
+ display: "flex",
984
+ alignItems: "center",
985
+ padding: "10px 20px",
986
+ borderTop: "1px solid var(--tina-color-grey-2)",
987
+ textTransform: "uppercase",
988
+ fontSize: "11px",
989
+ fontWeight: 500,
990
+ background: "var(--tina-color-grey-0)"
991
+ }
992
+ }, /* @__PURE__ */ React.createElement(BiLinkExternal, {
993
+ style: {
994
+ height: "1.25em",
995
+ width: "auto",
996
+ opacity: "0.8",
997
+ marginRight: "8px"
998
+ }
999
+ }), " ", "Edit in Tina Admin")
1000
+ });
1001
+ cms.plugins.add(TinaAdminLink);
1002
+ }
876
1003
  const formConfig = {
877
1004
  id: queryName,
878
1005
  label: result.form.label,
@@ -981,7 +1108,15 @@ function useGraphqlForms({
981
1108
  console.error(e);
982
1109
  setIsLoading(false);
983
1110
  });
984
- }, [queryString, JSON.stringify(variables)]);
1111
+ return () => {
1112
+ formIds.forEach((name) => {
1113
+ const formPlugin = cms.forms.find(name);
1114
+ if (formPlugin) {
1115
+ cms.forms.remove(formPlugin);
1116
+ }
1117
+ });
1118
+ };
1119
+ }, [queryString, JSON.stringify(variables), currentBranch]);
985
1120
  return [data, isLoading];
986
1121
  }
987
1122
  const transformDocumentIntoMutationRequestPayload = (document2, instructions) => {
@@ -1040,9 +1175,9 @@ const generateFormCreators = (cms) => {
1040
1175
  cms.forms.add(form);
1041
1176
  return form;
1042
1177
  };
1043
- const createGlobalForm = (formConfig) => {
1178
+ const createGlobalForm = (formConfig, options) => {
1044
1179
  const form = new Form(formConfig);
1045
- cms.plugins.add(new GlobalFormPlugin(form));
1180
+ cms.plugins.add(new GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
1046
1181
  return form;
1047
1182
  };
1048
1183
  return { createForm, createGlobalForm };
@@ -1454,81 +1589,12 @@ This will work when developing locally but NOT when deployed to production.
1454
1589
  }
1455
1590
  return client.request(query, { variables });
1456
1591
  };
1457
- function gql(strings) {
1458
- return strings[0];
1459
- }
1460
- var DefaultContext = {
1461
- color: void 0,
1462
- size: void 0,
1463
- className: void 0,
1464
- style: void 0,
1465
- attr: void 0
1466
- };
1467
- var IconContext = React.createContext && React.createContext(DefaultContext);
1468
- var __assign = function() {
1469
- __assign = Object.assign || function(t) {
1470
- for (var s, i = 1, n = arguments.length; i < n; i++) {
1471
- s = arguments[i];
1472
- for (var p in s)
1473
- if (Object.prototype.hasOwnProperty.call(s, p))
1474
- t[p] = s[p];
1475
- }
1476
- return t;
1477
- };
1478
- return __assign.apply(this, arguments);
1479
- };
1480
- var __rest = function(s, e) {
1481
- var t = {};
1482
- for (var p in s)
1483
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
1484
- t[p] = s[p];
1485
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
1486
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
1487
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
1488
- t[p[i]] = s[p[i]];
1489
- }
1490
- return t;
1491
- };
1492
- function Tree2Element(tree) {
1493
- return tree && tree.map(function(node, i) {
1494
- return React.createElement(node.tag, __assign({
1495
- key: i
1496
- }, node.attr), Tree2Element(node.child));
1592
+ function gql(strings, ...args) {
1593
+ let str = "";
1594
+ strings.forEach((string, i) => {
1595
+ str += string + (args[i] || "");
1497
1596
  });
1498
- }
1499
- function GenIcon(data) {
1500
- return function(props) {
1501
- return React.createElement(IconBase, __assign({
1502
- attr: __assign({}, data.attr)
1503
- }, props), Tree2Element(data.child));
1504
- };
1505
- }
1506
- function IconBase(props) {
1507
- var elem = function(conf) {
1508
- var attr = props.attr, size = props.size, title = props.title, svgProps = __rest(props, ["attr", "size", "title"]);
1509
- var computedSize = size || conf.size || "1em";
1510
- var className;
1511
- if (conf.className)
1512
- className = conf.className;
1513
- if (props.className)
1514
- className = (className ? className + " " : "") + props.className;
1515
- return React.createElement("svg", __assign({
1516
- stroke: "currentColor",
1517
- fill: "currentColor",
1518
- strokeWidth: "0"
1519
- }, conf.attr, attr, svgProps, {
1520
- className,
1521
- style: __assign(__assign({
1522
- color: props.color || conf.color
1523
- }, conf.style), props.style),
1524
- height: computedSize,
1525
- width: computedSize,
1526
- xmlns: "http://www.w3.org/2000/svg"
1527
- }), title && React.createElement("title", null, title), props.children);
1528
- };
1529
- return IconContext !== void 0 ? React.createElement(IconContext.Consumer, null, function(conf) {
1530
- return elem(conf);
1531
- }) : elem(DefaultContext);
1597
+ return str;
1532
1598
  }
1533
1599
  function ImFilesEmpty(props) {
1534
1600
  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);
@@ -1575,15 +1641,6 @@ const GetCollections = ({ cms, children }) => {
1575
1641
  return null;
1576
1642
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collections));
1577
1643
  };
1578
- function BiEdit(props) {
1579
- 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);
1580
- }
1581
- function BiExit(props) {
1582
- 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);
1583
- }
1584
- function BiLogIn(props) {
1585
- 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);
1586
- }
1587
1644
  function MdOutlineArrowBack(props) {
1588
1645
  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);
1589
1646
  }
@@ -1656,12 +1713,14 @@ const useGetCollection = (cms, collectionName, includeDocuments = true) => {
1656
1713
  name
1657
1714
  label
1658
1715
  format
1716
+ templates
1659
1717
  documents @include(if: $includeDocuments) {
1660
1718
  totalCount
1661
1719
  edges {
1662
1720
  node {
1663
1721
  ... on Document {
1664
1722
  sys {
1723
+ template
1665
1724
  breadcrumbs
1666
1725
  path
1667
1726
  basename
@@ -1693,59 +1752,119 @@ const GetCollection = ({
1693
1752
  }
1694
1753
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collection));
1695
1754
  };
1755
+ const TemplateMenu = ({ templates }) => {
1756
+ return /* @__PURE__ */ React.createElement(Menu, {
1757
+ as: "div",
1758
+ className: "relative inline-block text-left"
1759
+ }, ({ open }) => /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Menu.Button, {
1760
+ 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",
1761
+ style: { background: "#0084FF" }
1762
+ }, "Create New", /* @__PURE__ */ React.createElement("svg", {
1763
+ width: "20",
1764
+ height: "20",
1765
+ viewBox: "0 0 20 20",
1766
+ fill: "none",
1767
+ xmlns: "http://www.w3.org/2000/svg",
1768
+ 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`}`
1769
+ }, /* @__PURE__ */ React.createElement("g", {
1770
+ opacity: "1.0"
1771
+ }, /* @__PURE__ */ React.createElement("path", {
1772
+ d: "M7.91675 13.8086L9.16675 15.0586L14.2253 10L9.16675 4.9414L7.91675 6.1914L11.7253 10L7.91675 13.8086Z",
1773
+ fill: "currentColor"
1774
+ }))))), /* @__PURE__ */ React.createElement(Transition, {
1775
+ as: Fragment,
1776
+ enter: "transition ease-out duration-100",
1777
+ enterFrom: "transform opacity-0 scale-95",
1778
+ enterTo: "transform opacity-100 scale-100",
1779
+ leave: "transition ease-in duration-75",
1780
+ leaveFrom: "transform opacity-100 scale-100",
1781
+ leaveTo: "transform opacity-0 scale-95"
1782
+ }, /* @__PURE__ */ React.createElement(Menu.Items, {
1783
+ 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"
1784
+ }, /* @__PURE__ */ React.createElement("div", {
1785
+ className: "py-1"
1786
+ }, templates.map((template) => /* @__PURE__ */ React.createElement(Menu.Item, {
1787
+ key: `${template.label}-${template.name}`
1788
+ }, ({ active }) => /* @__PURE__ */ React.createElement(Link, {
1789
+ to: `${location.pathname}/${template.name}/new`,
1790
+ 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"}`
1791
+ }, template.label))))))));
1792
+ };
1696
1793
  const CollectionListPage = () => {
1697
- const location = useLocation();
1794
+ const location2 = useLocation();
1698
1795
  const { collectionName } = useParams();
1699
- return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetCollection, {
1700
- cms,
1701
- collectionName,
1702
- includeDocuments: true
1703
- }, (collection) => {
1704
- const totalCount = collection.documents.totalCount;
1705
- const documents = collection.documents.edges;
1706
- return /* @__PURE__ */ React.createElement("div", {
1707
- className: "px-6 py-14 h-screen overflow-y-auto flex justify-center"
1708
- }, /* @__PURE__ */ React.createElement("div", {
1709
- className: "max-w-screen-md w-full"
1710
- }, /* @__PURE__ */ React.createElement("div", {
1711
- className: "w-full flex justify-between items-end"
1712
- }, /* @__PURE__ */ React.createElement("h3", {
1713
- className: "text-3xl"
1714
- }, collection.label), /* @__PURE__ */ React.createElement(Link, {
1715
- to: `${location.pathname}/new`,
1716
- 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",
1717
- style: { background: "#0084FF" }
1718
- }, "Create New")), totalCount > 0 && /* @__PURE__ */ React.createElement("div", {
1719
- className: "mt-8 shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"
1720
- }, /* @__PURE__ */ React.createElement("table", {
1721
- className: "min-w-full"
1722
- }, /* @__PURE__ */ React.createElement("tbody", {
1723
- className: "bg-white divide-y divide-gray-150"
1724
- }, documents.map((document2) => /* @__PURE__ */ React.createElement("tr", {
1725
- key: document2.node.sys.relativePath
1726
- }, /* @__PURE__ */ React.createElement("td", {
1727
- className: "px-6 py-2 whitespace-nowrap"
1728
- }, /* @__PURE__ */ React.createElement(Link, {
1729
- to: `${location.pathname}/${document2.node.sys.filename}`,
1730
- className: "text-blue-600 hover:text-blue-400 flex items-center gap-3"
1731
- }, /* @__PURE__ */ React.createElement(BiEdit, {
1732
- className: "inline-block h-6 w-auto opacity-70"
1733
- }), " ", /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", {
1734
- className: "block text-xs text-gray-400 mb-1 uppercase"
1735
- }, "Filename"), /* @__PURE__ */ React.createElement("span", {
1736
- className: "h-5 leading-5 block whitespace-nowrap"
1737
- }, document2.node.sys.filename)))), /* @__PURE__ */ React.createElement("td", {
1738
- className: "px-6 py-4 whitespace-nowrap"
1739
- }, /* @__PURE__ */ React.createElement("span", {
1740
- className: "block text-xs text-gray-400 mb-1 uppercase"
1741
- }, "Extension"), /* @__PURE__ */ React.createElement("span", {
1742
- className: "h-5 leading-5 block text-sm font-medium text-gray-900"
1743
- }, document2.node.sys.extension)))))))));
1744
- }));
1796
+ return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => {
1797
+ const plugins = cms.plugins.all("tina-admin");
1798
+ const routeMapping = plugins.find(({ name }) => name === "route-mapping");
1799
+ return /* @__PURE__ */ React.createElement(GetCollection, {
1800
+ cms,
1801
+ collectionName,
1802
+ includeDocuments: true
1803
+ }, (collection) => {
1804
+ const totalCount = collection.documents.totalCount;
1805
+ const documents = collection.documents.edges;
1806
+ return /* @__PURE__ */ React.createElement("div", {
1807
+ className: "px-6 py-14 h-screen overflow-y-auto flex justify-center"
1808
+ }, /* @__PURE__ */ React.createElement("div", {
1809
+ className: "max-w-screen-md w-full"
1810
+ }, /* @__PURE__ */ React.createElement("div", {
1811
+ className: "w-full flex justify-between items-end"
1812
+ }, /* @__PURE__ */ React.createElement("h3", {
1813
+ className: "text-3xl"
1814
+ }, collection.label), !collection.templates && /* @__PURE__ */ React.createElement(Link, {
1815
+ to: `${location2.pathname}/new`,
1816
+ 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",
1817
+ style: { background: "#0084FF" }
1818
+ }, "Create New"), collection.templates && /* @__PURE__ */ React.createElement(TemplateMenu, {
1819
+ templates: collection.templates
1820
+ })), totalCount > 0 && /* @__PURE__ */ React.createElement("div", {
1821
+ className: "mt-8 shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"
1822
+ }, /* @__PURE__ */ React.createElement("table", {
1823
+ className: "min-w-full"
1824
+ }, /* @__PURE__ */ React.createElement("tbody", {
1825
+ className: "bg-white divide-y divide-gray-150"
1826
+ }, documents.map((document2) => {
1827
+ const livesiteRoute = routeMapping ? routeMapping.mapper(collection, document2.node) : void 0;
1828
+ return /* @__PURE__ */ React.createElement("tr", {
1829
+ key: document2.node.sys.relativePath
1830
+ }, /* @__PURE__ */ React.createElement("td", {
1831
+ className: "px-5 py-3 whitespace-nowrap"
1832
+ }, /* @__PURE__ */ React.createElement("span", {
1833
+ className: "block text-xs mb-0.5 text-gray-400 uppercase"
1834
+ }, "Filename"), /* @__PURE__ */ React.createElement(Link, {
1835
+ to: `${location2.pathname}/${document2.node.sys.filename}`,
1836
+ className: "h-5 leading-5 block"
1837
+ }, /* @__PURE__ */ React.createElement("span", {
1838
+ className: "leading-5 font-medium text-base overflow-ellipsis overflow-hidden whitespace-nowrap text-gray-700"
1839
+ }, document2.node.sys.filename), /* @__PURE__ */ React.createElement("span", {
1840
+ className: "leading-5 text-base font-medium text-gray-300"
1841
+ }, document2.node.sys.extension))), /* @__PURE__ */ React.createElement("td", {
1842
+ className: "px-5 py-3 whitespace-nowrap"
1843
+ }, /* @__PURE__ */ React.createElement("span", {
1844
+ className: "block text-xs mb-0.5 text-gray-400 uppercase"
1845
+ }, "Template"), /* @__PURE__ */ React.createElement("span", {
1846
+ className: "h-5 block leading-5 font-regular text-base overflow-ellipsis overflow-hidden whitespace-nowrap text-gray-500"
1847
+ }, document2.node.sys.template)), /* @__PURE__ */ React.createElement("td", {
1848
+ className: "px-5 py-3 whitespace-nowrap flex gap-3 items-center justify-end"
1849
+ }, livesiteRoute && /* @__PURE__ */ React.createElement("a", {
1850
+ href: livesiteRoute,
1851
+ 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"
1852
+ }, /* @__PURE__ */ React.createElement(BiLinkExternal, {
1853
+ className: "inline-block h-5 w-auto opacity-70"
1854
+ }), " ", "View"), /* @__PURE__ */ React.createElement(Link, {
1855
+ to: `${location2.pathname}/${document2.node.sys.filename}`,
1856
+ 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"
1857
+ }, /* @__PURE__ */ React.createElement(BiEdit, {
1858
+ className: "inline-block h-5 w-auto opacity-70"
1859
+ }), " ", "Edit")));
1860
+ }))))));
1861
+ });
1862
+ });
1745
1863
  };
1746
- const useGetDocumentFields = (cms, collectionName) => {
1864
+ const useGetDocumentFields = (cms, collectionName, templateName) => {
1747
1865
  const [info, setInfo] = useState({
1748
1866
  collection: void 0,
1867
+ template: void 0,
1749
1868
  fields: void 0,
1750
1869
  mutationInfo: void 0
1751
1870
  });
@@ -1754,10 +1873,18 @@ const useGetDocumentFields = (cms, collectionName) => {
1754
1873
  const response = await cms.api.tina.request(`query { getDocumentFields }`, {});
1755
1874
  const documentFields = response.getDocumentFields;
1756
1875
  const collection = documentFields[collectionName].collection;
1757
- const fields = documentFields[collectionName].fields;
1758
1876
  const mutationInfo = documentFields[collectionName].mutationInfo;
1877
+ let fields = void 0;
1878
+ let template = void 0;
1879
+ if (templateName && documentFields[collectionName].templates && documentFields[collectionName].templates[templateName]) {
1880
+ template = documentFields[collectionName].templates[templateName].template;
1881
+ fields = documentFields[collectionName].templates[templateName].fields;
1882
+ } else {
1883
+ fields = documentFields[collectionName].fields;
1884
+ }
1759
1885
  setInfo({
1760
1886
  collection,
1887
+ template,
1761
1888
  fields,
1762
1889
  mutationInfo
1763
1890
  });
@@ -1769,20 +1896,21 @@ const useGetDocumentFields = (cms, collectionName) => {
1769
1896
  const GetDocumentFields = ({
1770
1897
  cms,
1771
1898
  collectionName,
1899
+ templateName,
1772
1900
  children
1773
1901
  }) => {
1774
- const { collection, fields, mutationInfo } = useGetDocumentFields(cms, collectionName);
1775
- if (!collection || !fields || !mutationInfo) {
1902
+ const { collection, template, fields, mutationInfo } = useGetDocumentFields(cms, collectionName, templateName);
1903
+ if (!collection) {
1776
1904
  return null;
1777
1905
  }
1778
- return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collection, fields, mutationInfo));
1906
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children({ collection, template, fields, mutationInfo }));
1779
1907
  };
1780
- const createDocument = async (cms, collection, mutationInfo, values) => {
1908
+ const createDocument = async (cms, collection, template, mutationInfo, values) => {
1781
1909
  const _a = values, { relativePath } = _a, leftover = __objRest(_a, ["relativePath"]);
1782
1910
  const { includeCollection, includeTemplate } = mutationInfo;
1783
- const params = transformDocumentIntoMutationRequestPayload(__spreadValues({
1911
+ const params = transformDocumentIntoMutationRequestPayload(__spreadValues(__spreadValues({
1784
1912
  _collection: collection.name
1785
- }, leftover), {
1913
+ }, template && { _template: template.name }), leftover), {
1786
1914
  includeCollection,
1787
1915
  includeTemplate
1788
1916
  });
@@ -1801,12 +1929,13 @@ const createDocument = async (cms, collection, mutationInfo, values) => {
1801
1929
  });
1802
1930
  };
1803
1931
  const CollectionCreatePage = () => {
1804
- const { collectionName } = useParams();
1932
+ const { collectionName, templateName } = useParams();
1805
1933
  const history = useHistory();
1806
1934
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetDocumentFields, {
1807
1935
  cms,
1808
- collectionName
1809
- }, (collection, fields, mutationInfo) => {
1936
+ collectionName,
1937
+ templateName
1938
+ }, ({ collection, template, fields, mutationInfo }) => {
1810
1939
  const form = new Form({
1811
1940
  id: "create-form",
1812
1941
  label: "form",
@@ -1821,16 +1950,17 @@ const CollectionCreatePage = () => {
1821
1950
  ...fields
1822
1951
  ],
1823
1952
  onSubmit: async (values) => {
1824
- await createDocument(cms, collection, mutationInfo, values);
1953
+ await createDocument(cms, collection, template, mutationInfo, values);
1825
1954
  history.push(`/admin/collections/${collection.name}`);
1826
1955
  }
1827
1956
  });
1957
+ const formLabel = template ? `${collection.label} - Create New ${template.label}` : `${collection.label} - Create New`;
1828
1958
  return /* @__PURE__ */ React.createElement("div", {
1829
1959
  className: "w-full h-screen"
1830
1960
  }, /* @__PURE__ */ React.createElement("div", {
1831
1961
  className: "flex flex-col items-center w-full flex-1"
1832
1962
  }, /* @__PURE__ */ React.createElement(FullscreenFormBuilder, {
1833
- label: collection.label + " - Create New",
1963
+ label: formLabel,
1834
1964
  form
1835
1965
  })));
1836
1966
  }));
@@ -1866,15 +1996,15 @@ const GetDocument = ({
1866
1996
  }
1867
1997
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children(document2));
1868
1998
  };
1869
- const updateDocument = async (cms, collection, document2, relativePath, values) => {
1870
- const { includeCollection, includeTemplate } = document2.form.mutationInfo;
1999
+ const updateDocument = async (cms, relativePath, collection, mutationInfo, values) => {
2000
+ const { includeCollection, includeTemplate } = mutationInfo;
1871
2001
  const params = transformDocumentIntoMutationRequestPayload(values, {
1872
2002
  includeCollection,
1873
2003
  includeTemplate
1874
2004
  });
1875
2005
  await cms.api.tina.request(`mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1876
- updateDocument(
1877
- collection: $collection,
2006
+ updateDocument(
2007
+ collection: $collection,
1878
2008
  relativePath: $relativePath,
1879
2009
  params: $params
1880
2010
  ){__typename}
@@ -1889,11 +2019,10 @@ const updateDocument = async (cms, collection, document2, relativePath, values)
1889
2019
  const CollectionUpdatePage = () => {
1890
2020
  const { collectionName, filename } = useParams();
1891
2021
  const history = useHistory();
1892
- return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetCollection, {
2022
+ return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetDocumentFields, {
1893
2023
  cms,
1894
- collectionName,
1895
- includeDocuments: false
1896
- }, (collection) => {
2024
+ collectionName
2025
+ }, ({ collection, mutationInfo }) => {
1897
2026
  const relativePath = `${filename}.${collection.format}`;
1898
2027
  return /* @__PURE__ */ React.createElement(GetDocument, {
1899
2028
  cms,
@@ -1906,7 +2035,7 @@ const CollectionUpdatePage = () => {
1906
2035
  fields: document2.form.fields,
1907
2036
  initialValues: document2.values,
1908
2037
  onSubmit: async (values) => {
1909
- await updateDocument(cms, collection, document2, relativePath, values);
2038
+ await updateDocument(cms, relativePath, collection, mutationInfo, values);
1910
2039
  history.push(`/admin/collections/${collection.name}`);
1911
2040
  }
1912
2041
  });
@@ -2026,6 +2155,8 @@ const TinaAdmin = () => {
2026
2155
  className: "flex-1"
2027
2156
  }, /* @__PURE__ */ React.createElement(Switch, null, /* @__PURE__ */ React.createElement(Route, {
2028
2157
  path: `/admin/collections/:collectionName/new`
2158
+ }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null)), /* @__PURE__ */ React.createElement(Route, {
2159
+ path: `/admin/collections/:collectionName/:templateName/new`
2029
2160
  }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null)), /* @__PURE__ */ React.createElement(Route, {
2030
2161
  path: `/admin/collections/:collectionName/:filename`
2031
2162
  }, /* @__PURE__ */ React.createElement(CollectionUpdatePage, null)), /* @__PURE__ */ React.createElement(Route, {
@@ -2034,4 +2165,11 @@ const TinaAdmin = () => {
2034
2165
  path: `/admin`
2035
2166
  }, /* @__PURE__ */ React.createElement(DashboardPage, null)))))))));
2036
2167
  };
2037
- export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, TinaAdmin, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, assertShape, createClient, TinaCMSProvider2 as default, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useGraphqlForms, useTinaAuthRedirect };
2168
+ class RouteMappingPlugin {
2169
+ constructor(mapper) {
2170
+ this.__type = "tina-admin";
2171
+ this.name = "route-mapping";
2172
+ this.mapper = mapper;
2173
+ }
2174
+ }
2175
+ export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, RouteMappingPlugin, TinaAdmin, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, assertShape, createClient, TinaCMSProvider2 as default, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useGraphqlForms, useTinaAuthRedirect };