tinacms 0.60.0 → 0.61.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # tinacms
2
2
 
3
+ ## 0.61.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [2c7718636]
8
+ - @tinacms/toolkit@0.56.4
9
+
10
+ ## 0.61.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 229feda1d: add .nvmrc file for setting preferred node version
15
+
16
+ ## 0.60.3
17
+
18
+ ### Patch Changes
19
+
20
+ - 4adaf15af: Fix types which weren't included in previous patch
21
+
22
+ ## 0.60.2
23
+
24
+ ### Patch Changes
25
+
26
+ - 816271d03: Ensure login/logout pages work when admin flag is disabled
27
+
28
+ ## 0.60.1
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies [4700d7ae4]
33
+ - @tinacms/toolkit@0.56.3
34
+
3
35
  ## 0.60.0
4
36
 
5
37
  ### Minor Changes
package/README.md CHANGED
@@ -1,289 +1,4 @@
1
- > Heads up - if you haven't already done so, read through the [CLI documentation](https://tina.io/docs/tina-cloud/cli/) to make sure you have a GraphQL server running locally.
1
+ # TinaCMS
2
+ > The Fastest Way to Edit Next.js Content
2
3
 
3
- For a real-world example of how this is being used checkout the [Tina Cloud Starter](https://github.com/tinacms/tina-cloud-starter).
4
-
5
- ## Getting started
6
-
7
- Npm:
8
-
9
- ```bash
10
- npm install --save-dev tinacms
11
- ```
12
-
13
- Yarn:
14
-
15
- ```bash
16
- yarn add --dev tinacms
17
- ```
18
-
19
- ## The TinaCMS API Client
20
-
21
- This package exports a class which acts as [TinaCMS external API](https://tina.io/docs/apis/) for the Tina Content API. This is a headless GraphQL API that's serverd via Tina Cloud or locally from within the Tina CLI.
22
-
23
- ```ts
24
- import { Client, LocalClient } from "tinacms";
25
- const client = new Client({
26
- organizationId: "the ID you get from Tina Cloud",
27
- clientId: "the client ID you get from Tina Cloud",
28
- branch: "main",
29
- tokenStorage: "LOCAL_STORAGE" | "MEMORY" | "CUSTOM",
30
- });
31
-
32
- // For a simpler setup while working locally you can instantiate the LocalClient as a convenience
33
- const client = new LocalClient();
34
- ```
35
-
36
- The `Client` does a few things:
37
-
38
- - Manages auth with Tina Cloud
39
- - Provides a `request` function for working with the GraphQL API
40
-
41
- Start by initializing the `LocalClient` - which automatically connects with your locally-running GraphQL server. From there, you can make GraphQL requests:
42
-
43
- ### `client.request`
44
-
45
- ```ts
46
- const client = new LocalClient();
47
-
48
- await client.request(
49
- (gql) => gql`#graphql
50
- query BlogPostQuery($relativePath: String!) {
51
- {
52
- getPostsDocument(relativePath: "") {
53
- data {
54
- title
55
- }
56
- }
57
- }
58
- }
59
- `,
60
- { variables: { relativePath: "hello-world.md" } }
61
- );
62
- ```
63
-
64
- > This API currently doesn't support filtering and sorting "list" queries. We have plans to tackle that in upcoming cycles.
65
-
66
- ## `useGraphQLForms`
67
-
68
- While GraphQL is a great tool, using it with Tina can be difficult. GraphQL can query across multiple nodes, but since each document would require its own Tina form it could be difficult to sync the data with your query with all of the forms you'd need to build. The Tina GraphQL server knows all about your content schema so we're actually able to build forms automatically by inspecting your query. To see this in action, pass your query into the `useGraphqlForms` hook:
69
-
70
- ```tsx
71
- import { useGraphqlForms } from 'tinacms'
72
-
73
- const query = gql => gql`#graphql
74
- query BlogPostQuery($relativePath: String!) {
75
- {
76
- getPostsDocument(relativePath: $relativePath) {
77
- data {
78
- title
79
- }
80
- }
81
- }
82
- }
83
- `
84
-
85
- const MyPage = (props) => {
86
- const [payload, isLoading] = useGraphqlForms<PostQueryResponseType>({
87
- query,
88
- variables: { relativePath: `${props.filename}.md` },
89
- });
90
-
91
- isLoading ? <div>Loading...</div> : <MyComponent {...payload}>
92
- }
93
- ```
94
-
95
- If Tina is enabled you can see a form for the `getPostsDocument` request. If you query for multiple documents, you should see multiple forms:
96
-
97
- ```tsx
98
- const query = (gql) => gql`#graphql
99
- query BlogPostQuery($relativePath: String!) {
100
- {
101
- # this generates a Tina Form
102
- getSiteNavsDocument(relativePath: "site-nav.md") {
103
- data {
104
- items {
105
- title
106
- link
107
- }
108
- }
109
- }
110
- # this generates a separate Tina Form
111
- getPostsDocument(relativePath: $relativePath) {
112
- data {
113
- title
114
- }
115
- }
116
- }
117
- }
118
- `;
119
- ```
120
-
121
- ### Formify
122
-
123
- If you'd like to control the output of those forms, tap into the `formify` callback:
124
-
125
- ##### Form customization:
126
-
127
- ```tsx
128
- import { useGraphqlForms } from "tinacms";
129
- import { useCMS } from "tinacms";
130
-
131
- const [payload, isLoading] = useGraphqlForms({
132
- query,
133
- formify: ({ formConfig, createForm, createGlobalForm, skip }) => {
134
- if (formConfig.id === "getSiteNavsDocument") {
135
- return createGlobalForm(formConfig);
136
- }
137
-
138
- return createForm(formConfig);
139
- },
140
- variables: { relativePath: `${props.filename}.md` },
141
- });
142
-
143
- // or to skip the nav from creating a form altogether:
144
- const [payload, isLoading] = useGraphqlForms({
145
- query,
146
- formify: ({ formConfig, createForm, skip }) => {
147
- if (formConfig.id === "getSiteNavsDocument") {
148
- return skip();
149
- }
150
-
151
- return createForm(formConfig);
152
- },
153
- variables: { relativePath: `${props.filename}.md` },
154
- });
155
- ```
156
-
157
- ##### Field customization:
158
-
159
- Since your forms are built automatically, `formify` can also be used to customize fields:
160
-
161
- ```tsx
162
- const [payload, isLoading] = useGraphqlForms({
163
- query,
164
- formify: ({ formConfig, createForm, skip }) => {
165
- return createForm({
166
- ...formConfig,
167
- fields: formConfig.fields.map((field) => {
168
- if (field.name === "title") {
169
- // replace `text` with `textarea`
170
- field.component = "textarea";
171
- }
172
- return field;
173
- }),
174
- });
175
- },
176
- variables: { relativePath: `${props.filename}.md` },
177
- });
178
- ```
179
-
180
- ## `useDocumentCreatorPlugin`
181
-
182
- This hook allows your editors to safely create new pages. Note that you'll be responsible for redirecting the user after a new document has been created. To use this:
183
-
184
- ```tsx
185
- import { useDocumentCreatorPlugin } from "tinacms";
186
-
187
- // args is of type:
188
- // {
189
- // collection: {
190
- // slug: string;
191
- // };
192
- // relativePath: string;
193
- // breadcrumbs: string[];
194
- // path: string;
195
- // }
196
- useDocumentCreatorPlugin((args) => window.location.assign(buildMyRouter(args)));
197
- ```
198
-
199
- ### Customizing the content creator options
200
-
201
- To prevent editors from creating documents from certain collections, provide a filter function:
202
-
203
- ```tsx
204
- // options are of type:
205
- // {
206
- // label: string;
207
- // value: string;
208
- // }[]
209
- useDocumentCreatorPlugin(null, (options) =>
210
- options.filter((option) => option.name !== "post")
211
- );
212
- ```
213
-
214
- ## Authentication with Tina Cloud
215
-
216
- While this package comes with low-level APIs for authentication with Tina Cloud, the easiest way to get started is to use the `TinaCloudAuthWall` component, which prevents children from rendering until a valid session has been established with Tina Cloud.
217
-
218
- ### `TinaCloudAuthWall`
219
-
220
- ```tsx
221
- import { TinaCloudAuthWall, Client } from "tinacms";
222
-
223
- const TinaWrapper = ({ children }) => {
224
- const cms = React.useMemo(() => {
225
- return new TinaCMS({
226
- apis: {
227
- tina: new Client({
228
- // config
229
- })
230
- },
231
- ...
232
- });
233
- }, []);
234
-
235
- return <TinaCloudAuthWall cms={cms}>{children}</TinaCloudAuthWall>;
236
- };
237
- ```
238
-
239
- Props for TinaCloudAuthWall
240
-
241
- | Prop | Description |
242
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
243
- | `cms` | An instance of a [CMS](http://localhost:3000/docs/cms/#cms-configuration) |
244
- | `getModalActions` (optional) | A function that returns a list of actions / buttons that will be rendered to the model. Each button has name, action, and can be primary or not. The name is the text that will be displayed. The action is a function that will be run when the button is clicked. See example below for more details |
245
-
246
- ```tsx
247
- return (
248
- <TinaCloudAuthWall
249
- cms={cms}
250
- getModalActions={({ closeModal }) => {
251
- return [
252
- {
253
- action: async () => {
254
- // use your own state to get in and out of edit mode
255
- closeModal();
256
- },
257
- name: "close",
258
- primary: false,
259
- },
260
- ];
261
- }}
262
- >
263
- <Component {...pageProps} />
264
- </TinaCloudAuthWall>
265
- );
266
- ```
267
-
268
- > Note: when using the LocalClient, TinaCloudAuthWall won't display a login screen, there is no authentication for the local GraphQL server.
269
-
270
- ### Authenticating without TinaCloudAuthWall
271
-
272
- You can also authenticate with the `Client` directly:
273
-
274
- ```ts
275
- const client = new Client({
276
- // config
277
- });
278
-
279
- const EditSiteButton = () => {
280
- const cms = useCMS();
281
- const onClick = async () => {
282
- await client.authenticate().then((token) => {
283
- cms.enable();
284
- });
285
- };
286
-
287
- return <button onClick={onClick}>Edit This Site</button>;
288
- };
289
- ```
4
+ [Checkout the docs](https://tina.io/docs/setup-overview/) for information on how to get started
package/dist/index.es.js CHANGED
@@ -2204,6 +2204,14 @@ const useEmbedTailwind = () => {
2204
2204
  }
2205
2205
  }, []);
2206
2206
  };
2207
+ const Redirect = () => {
2208
+ React.useEffect(() => {
2209
+ if (window) {
2210
+ window.location.assign("/");
2211
+ }
2212
+ }, []);
2213
+ return null;
2214
+ };
2207
2215
  const TinaAdmin = () => {
2208
2216
  useEmbedTailwind();
2209
2217
  const isSSR = typeof window === "undefined";
@@ -2241,11 +2249,11 @@ const TinaAdmin = () => {
2241
2249
  }))))));
2242
2250
  } else {
2243
2251
  return /* @__PURE__ */ React.createElement(Layout, null, /* @__PURE__ */ React.createElement(BrowserRouter, null, /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
2244
- path: "/admin/logout"
2245
- }, /* @__PURE__ */ React.createElement(LogoutPage, null)), /* @__PURE__ */ React.createElement(Route, {
2246
- path: "/admin"
2247
- }, () => {
2248
- window.location.href = "/";
2252
+ path: "/admin/logout",
2253
+ element: /* @__PURE__ */ React.createElement(LogoutPage, null)
2254
+ }), /* @__PURE__ */ React.createElement(Route, {
2255
+ path: "/admin",
2256
+ element: /* @__PURE__ */ React.createElement(Redirect, null)
2249
2257
  }))));
2250
2258
  }
2251
2259
  });
package/dist/index.js CHANGED
@@ -2224,6 +2224,14 @@ This will work when developing locally but NOT when deployed to production.
2224
2224
  }
2225
2225
  }, []);
2226
2226
  };
2227
+ const Redirect = () => {
2228
+ React__default["default"].useEffect(() => {
2229
+ if (window) {
2230
+ window.location.assign("/");
2231
+ }
2232
+ }, []);
2233
+ return null;
2234
+ };
2227
2235
  const TinaAdmin = () => {
2228
2236
  useEmbedTailwind();
2229
2237
  const isSSR = typeof window === "undefined";
@@ -2261,11 +2269,11 @@ This will work when developing locally but NOT when deployed to production.
2261
2269
  }))))));
2262
2270
  } else {
2263
2271
  return /* @__PURE__ */ React__default["default"].createElement(Layout, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.BrowserRouter, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Routes, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2264
- path: "/admin/logout"
2265
- }, /* @__PURE__ */ React__default["default"].createElement(LogoutPage, null)), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2266
- path: "/admin"
2267
- }, () => {
2268
- window.location.href = "/";
2272
+ path: "/admin/logout",
2273
+ element: /* @__PURE__ */ React__default["default"].createElement(LogoutPage, null)
2274
+ }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
2275
+ path: "/admin",
2276
+ element: /* @__PURE__ */ React__default["default"].createElement(Redirect, null)
2269
2277
  }))));
2270
2278
  }
2271
2279
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinacms",
3
- "version": "0.60.0",
3
+ "version": "0.61.1",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist"
@@ -22,7 +22,7 @@
22
22
  "@headlessui/react": "^1.4.1",
23
23
  "@heroicons/react": "^1.0.4",
24
24
  "@tinacms/sharedctx": "0.0.1",
25
- "@tinacms/toolkit": "0.56.2",
25
+ "@tinacms/toolkit": "0.56.4",
26
26
  "crypto-js": "^4.0.0",
27
27
  "final-form": "4.20.1",
28
28
  "graphql": "^15.1.0",