tinacms 0.60.3 → 0.64.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/CHANGELOG.md +78 -0
- package/README.md +3 -288
- package/dist/client/index.d.ts +1 -0
- package/dist/index.es.js +104 -97
- package/dist/index.js +105 -98
- package/dist/style.css +1344 -0
- package/dist/tina-cms.d.ts +27 -4
- package/package.json +11 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,83 @@
|
|
|
1
1
|
# tinacms
|
|
2
2
|
|
|
3
|
+
## 0.64.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4a3990c7e: Cloudinary media store now serves images over `https` by default. This can now be configured though the handler provided.
|
|
8
|
+
|
|
9
|
+
To revert to the old behavior:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
export default createMediaHandler(
|
|
13
|
+
{
|
|
14
|
+
// ...
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
useHttps: false,
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The default for `useHttps` is `true`
|
|
23
|
+
|
|
24
|
+
## 0.63.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- 3897ec5d9: Replace `branch`, `clientId`, `isLocalClient` props with single `apiURL`. When working locally, this should be `http://localhost:4001/graphql`. For Tina Cloud, use `https://content.tinajs.io/content/<my-client-id>/github/<my-branch>`
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// _app.tsx
|
|
32
|
+
// ...
|
|
33
|
+
<TinaCMS apiURL={process.env.NEXT_PUBLIC_TINA_API_URL} {...pageProps}>
|
|
34
|
+
{livePageProps => <Component {...livePageProps} />}
|
|
35
|
+
</TinaCMS>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
DEPRECATION NOTICE: `branch`, `clientId`, `isLocalClient` props will be deprecated in the future
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- 96e4a77e2: Fixed types
|
|
43
|
+
- b5c22503a: Changes messaging on login page for TinaAdmin when in local-mode
|
|
44
|
+
- Updated dependencies [60f939f34]
|
|
45
|
+
- @tinacms/toolkit@0.56.6
|
|
46
|
+
|
|
47
|
+
## 0.62.0
|
|
48
|
+
|
|
49
|
+
### Minor Changes
|
|
50
|
+
|
|
51
|
+
- 70da62fe8: deprecated the use of `getStaticPropsForTina`
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- 0afa75df1: 2342 - [TinaAdmin] Truncates the `filename` column for the Document List View
|
|
56
|
+
- 7dafce89d: Fixed issue where content creator was invalid
|
|
57
|
+
- 3de8c6165: Enabled branch creation in branch switcher
|
|
58
|
+
- fee183f8f: add "switch to default branch" recover option to error boundary
|
|
59
|
+
- 5c070a83f: feat: Add UI banner for when in localMode
|
|
60
|
+
- Updated dependencies [ddf81a4fd]
|
|
61
|
+
- Updated dependencies [20260a82d]
|
|
62
|
+
- Updated dependencies [0370147fb]
|
|
63
|
+
- Updated dependencies [3de8c6165]
|
|
64
|
+
- Updated dependencies [2eaad97bf]
|
|
65
|
+
- Updated dependencies [5c070a83f]
|
|
66
|
+
- @tinacms/toolkit@0.56.5
|
|
67
|
+
|
|
68
|
+
## 0.61.1
|
|
69
|
+
|
|
70
|
+
### Patch Changes
|
|
71
|
+
|
|
72
|
+
- Updated dependencies [2c7718636]
|
|
73
|
+
- @tinacms/toolkit@0.56.4
|
|
74
|
+
|
|
75
|
+
## 0.61.0
|
|
76
|
+
|
|
77
|
+
### Minor Changes
|
|
78
|
+
|
|
79
|
+
- 229feda1d: add .nvmrc file for setting preferred node version
|
|
80
|
+
|
|
3
81
|
## 0.60.3
|
|
4
82
|
|
|
5
83
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,289 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# TinaCMS
|
|
2
|
+
> The Fastest Way to Edit Next.js Content
|
|
2
3
|
|
|
3
|
-
|
|
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/client/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export declare class Client {
|
|
|
42
42
|
private options;
|
|
43
43
|
events: EventBus;
|
|
44
44
|
constructor({ tokenStorage, ...options }: ServerOptions);
|
|
45
|
+
get isLocalMode(): boolean;
|
|
45
46
|
setBranch(branchName: string): void;
|
|
46
47
|
addPendingContent: (props: any) => Promise<unknown>;
|
|
47
48
|
getSchema: () => Promise<GraphQLSchema>;
|