@smartive/graphql-magic 15.0.0 → 15.0.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 +6 -1
- package/README.md +1 -36
- package/dist/bin/gqm.cjs +41 -4
- package/docs/README.md +41 -0
- package/docs/babel.config.js +3 -0
- package/docs/docs/tutorial.md +425 -0
- package/docs/docusaurus.config.ts +110 -0
- package/docs/package-lock.json +14680 -0
- package/docs/package.json +47 -0
- package/docs/sidebars.ts +31 -0
- package/docs/src/css/custom.css +30 -0
- package/docs/src/pages/index.module.css +23 -0
- package/docs/src/pages/index.tsx +39 -0
- package/docs/src/pages/markdown-page.md +7 -0
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +1 -0
- package/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- package/docs/static/img/undraw_docusaurus_react.svg +170 -0
- package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- package/docs/tsconfig.json +7 -0
- package/package.json +1 -1
- package/src/bin/gqm/settings.ts +6 -5
- package/src/bin/gqm/templates.ts +1 -11
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
## [15.0.1](https://github.com/smartive/graphql-magic/compare/v15.0.0...v15.0.1) (2024-04-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Stuff ([#152](https://github.com/smartive/graphql-magic/issues/152)) ([be06252](https://github.com/smartive/graphql-magic/commit/be0625222485da5ddb22b0d9feaf3ac7fdccd1a6))
|
package/README.md
CHANGED
|
@@ -2,42 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Welcome to graphql-magic!
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
### Prerequisites
|
|
8
|
-
|
|
9
|
-
* Next.js
|
|
10
|
-
* TypeScript
|
|
11
|
-
* Knex.js
|
|
12
|
-
* Postgresql
|
|
13
|
-
|
|
14
|
-
### Setup
|
|
15
|
-
|
|
16
|
-
Dependencies:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
npm i @smartive/graphql-magic
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Setup:
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
npx gqm setup
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Generate all the things:
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
npx gqm generate
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Generate a migration:
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
npx gqm generate-migration
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
To be continued...
|
|
5
|
+
See the [docs](https://)
|
|
41
6
|
|
|
42
7
|
## Development
|
|
43
8
|
|
package/dist/bin/gqm.cjs
CHANGED
|
@@ -1656,6 +1656,42 @@ export const GET_ME = gql\`
|
|
|
1656
1656
|
}
|
|
1657
1657
|
\`;
|
|
1658
1658
|
`;
|
|
1659
|
+
var EXECUTE = `
|
|
1660
|
+
import knexConfig from "@/knexfile";
|
|
1661
|
+
import { Context, User, execute } from "@smartive/graphql-magic";
|
|
1662
|
+
import { randomUUID } from "crypto";
|
|
1663
|
+
import { knex } from 'knex';
|
|
1664
|
+
import { DateTime } from "luxon";
|
|
1665
|
+
import { models } from "../config/models";
|
|
1666
|
+
|
|
1667
|
+
export const executeGraphql = async <T, V = undefined>(
|
|
1668
|
+
body: {
|
|
1669
|
+
query: string;
|
|
1670
|
+
operationName?: string;
|
|
1671
|
+
variables?: V;
|
|
1672
|
+
options?: { email?: string };
|
|
1673
|
+
}): Promise<{ data: T }> => {
|
|
1674
|
+
const db = knex(knexConfig);
|
|
1675
|
+
let user: User | undefined;
|
|
1676
|
+
// TODO: get user
|
|
1677
|
+
|
|
1678
|
+
const result = await execute({
|
|
1679
|
+
req: null as unknown as Context['req'],
|
|
1680
|
+
body,
|
|
1681
|
+
knex: db as unknown as Context['knex'],
|
|
1682
|
+
locale: 'en',
|
|
1683
|
+
locales: ['en'],
|
|
1684
|
+
user,
|
|
1685
|
+
models: models,
|
|
1686
|
+
permissions: { ADMIN: true, UNAUTHENTICATED: true },
|
|
1687
|
+
now: DateTime.local(),
|
|
1688
|
+
});
|
|
1689
|
+
await db.destroy();
|
|
1690
|
+
|
|
1691
|
+
// https://github.com/vercel/next.js/issues/47447#issuecomment-1500371732
|
|
1692
|
+
return JSON.parse(JSON.stringify(result)) as { data: T };
|
|
1693
|
+
}
|
|
1694
|
+
`;
|
|
1659
1695
|
|
|
1660
1696
|
// src/bin/gqm/settings.ts
|
|
1661
1697
|
var SETTINGS_PATH = ".gqmrc.json";
|
|
@@ -1696,10 +1732,11 @@ var DEFAULTS = {
|
|
|
1696
1732
|
}
|
|
1697
1733
|
},
|
|
1698
1734
|
graphqlQueriesPath: {
|
|
1699
|
-
question: "Where to
|
|
1700
|
-
defaultValue: "src/graphql
|
|
1735
|
+
question: "Where to put graphql code?",
|
|
1736
|
+
defaultValue: "src/graphql",
|
|
1701
1737
|
init: (path) => {
|
|
1702
|
-
ensureFileExists(`${path}/get-me.ts`, GET_ME);
|
|
1738
|
+
ensureFileExists(`${path}/client/queries/get-me.ts`, GET_ME);
|
|
1739
|
+
ensureFileExists(`${path}/execute.ts`, EXECUTE);
|
|
1703
1740
|
}
|
|
1704
1741
|
},
|
|
1705
1742
|
gqlModule: {
|
|
@@ -1766,7 +1803,7 @@ var ensureFileExists = (filePath, content) => {
|
|
|
1766
1803
|
}
|
|
1767
1804
|
};
|
|
1768
1805
|
var ensureFileContains = (filePath, content, fallback) => {
|
|
1769
|
-
ensureFileExists(filePath,
|
|
1806
|
+
ensureFileExists(filePath, "");
|
|
1770
1807
|
const fileContent = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
1771
1808
|
if (!fileContent.includes(content)) {
|
|
1772
1809
|
(0, import_fs.writeFileSync)(filePath, fileContent + (fallback ?? content));
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Website
|
|
2
|
+
|
|
3
|
+
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ yarn
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Local Development
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ yarn start
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
|
18
|
+
|
|
19
|
+
### Build
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
$ yarn build
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
|
26
|
+
|
|
27
|
+
### Deployment
|
|
28
|
+
|
|
29
|
+
Using SSH:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
$ USE_SSH=true yarn deploy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Not using SSH:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
$ GIT_USER=<Your GitHub username> yarn deploy
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 1
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tutorial
|
|
6
|
+
|
|
7
|
+
Let's create a blog with `graphql-magic`!
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
### Code base
|
|
12
|
+
|
|
13
|
+
First create a next.js website:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npx create-next-app@latest magic-blog --ts --app --tailwind --eslint --src
|
|
17
|
+
cd magic-blog
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For some styling install `preline` and dependencies:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
npm i preline @tailwindcss/forms
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Add `@tailwindcss/forms` to `tailwind.config.ts`:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
plugins: [
|
|
30
|
+
require('@tailwindcss/forms'),
|
|
31
|
+
],
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Replace `app/globals.css`:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
TODO
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Replace `app/layout.tsx`:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
export default function RootLayout({
|
|
44
|
+
children,
|
|
45
|
+
}: Readonly<{
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
}>) {
|
|
48
|
+
return (
|
|
49
|
+
<html>
|
|
50
|
+
<body>{children}</body>
|
|
51
|
+
</html>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Replace `app/page.tsx`:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
export default function Page() {
|
|
60
|
+
return <div>
|
|
61
|
+
<h1>Magic Blog</h1>
|
|
62
|
+
</div>
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Add this setting to `next.config.mjs`:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
const nextConfig = {
|
|
70
|
+
experimental: {
|
|
71
|
+
serverComponentsExternalPackages: ['knex'],
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Install `@smartive/graphql-magic`:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
npm install @smartive/graphql-magic
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Temporary:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
npm i @graphql-codegen/typescript-compatibility
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run the gqm cli:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
npx gqm generate
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Start the website:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
npm run dev
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Database setup
|
|
101
|
+
|
|
102
|
+
Adapt the database `.env` variables to connect to a postgresql instance, or create a new one.
|
|
103
|
+
For example, to create a local instance with docker and docker-compose, create the following `docker-compose.yml`:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
version: '3.4'
|
|
107
|
+
services:
|
|
108
|
+
postgres:
|
|
109
|
+
image: postgres:13-alpine
|
|
110
|
+
shm_size: 1gb
|
|
111
|
+
environment:
|
|
112
|
+
POSTGRES_DB: postgres
|
|
113
|
+
POSTGRES_USER: postgres
|
|
114
|
+
POSTGRES_PASSWORD: password
|
|
115
|
+
POSTGRES_HOST_AUTH_METHOD: trust
|
|
116
|
+
TZ: 'Europe/Zurich'
|
|
117
|
+
ports:
|
|
118
|
+
- '5432:5432'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then start it with `docker-compose up`.
|
|
122
|
+
|
|
123
|
+
Generate the first migration:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
npx gqm generate-migration
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Enter "setup" as migration name. Or you could first create a `feat/setup` git branch, then it would use that name automatically.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
Run the migration
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
npx env-cmd knex migrate:up
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Auth setup
|
|
139
|
+
|
|
140
|
+
Set up a way for users to authenticate with your app.
|
|
141
|
+
For example, follow [this tutorial](https://auth0.com/docs/quickstart/webapp/nextjs/01-login) to set up auth0.
|
|
142
|
+
|
|
143
|
+
Assuming you used auth0, here's a bare-bones version of what `src/app/page.tsx` could look like:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
import { getSession } from '@auth0/nextjs-auth0';
|
|
147
|
+
|
|
148
|
+
export default async function Page() {
|
|
149
|
+
const session = await getSession();
|
|
150
|
+
|
|
151
|
+
return <div>
|
|
152
|
+
<h1>Welcome to my Blog</h1>
|
|
153
|
+
{session ? <a href="/api/auth/logout">Logout</a> : <a href="/api/auth/login">Login</a>}
|
|
154
|
+
</div>
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
It should now be possible for you to log in and out again.
|
|
159
|
+
|
|
160
|
+
### Account setup
|
|
161
|
+
|
|
162
|
+
Now, we need to ensure that the user is stored in the database.
|
|
163
|
+
|
|
164
|
+
First extend the user model in `src/config/models.ts` with the following fields:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
fields: [
|
|
168
|
+
{
|
|
169
|
+
name: 'authId',
|
|
170
|
+
type: 'String',
|
|
171
|
+
nonNull: true,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'username',
|
|
175
|
+
type: 'String',
|
|
176
|
+
nonNull: true
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The models have changed, generate the new types:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
npx gqm generate
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Generate the new migration:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
npx gqm generate-migration
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Edit the generated migration, then run it
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
npx env-cmd knex migrate:up
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Now let's implement the `// TODO: get user` part in the `src/graphql/execute.ts` file
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
const session = await getSession();
|
|
203
|
+
if (session) {
|
|
204
|
+
let dbUser = await db('User').where({ authId: session.user.sid }).first();
|
|
205
|
+
if (!user) {
|
|
206
|
+
await db('User').insert({
|
|
207
|
+
id: randomUUID(),
|
|
208
|
+
authId: session.user.sid,
|
|
209
|
+
username: session.user.nickname
|
|
210
|
+
})
|
|
211
|
+
dbUser = await db('User').where({ authId: session.user.sid }).first();
|
|
212
|
+
}
|
|
213
|
+
user = {
|
|
214
|
+
...dbUser!,
|
|
215
|
+
role: 'ADMIN'
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Extend `src/graphql/client/queries/get-me.ts` to also fetch the user's username:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
import { gql } from '@smartive/graphql-magic';
|
|
224
|
+
|
|
225
|
+
export const GET_ME = gql`
|
|
226
|
+
query GetMe {
|
|
227
|
+
me {
|
|
228
|
+
id
|
|
229
|
+
username
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
`;
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Generate the new types:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
npx gqm generate
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Now, let's modify `src/app/page.tsx` so that it fetches the user from the database:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
import { GetMeQuery } from "../generated/client";
|
|
245
|
+
import { GET_ME } from "../graphql/client/queries/get-me";
|
|
246
|
+
import { executeGraphql } from "../graphql/execute";
|
|
247
|
+
|
|
248
|
+
export default async function Page() {
|
|
249
|
+
const { data: { me }} = await executeGraphql<GetMeQuery>({ query: GET_ME });
|
|
250
|
+
|
|
251
|
+
return <div>
|
|
252
|
+
<h1>Welcome to my Blog</h1>
|
|
253
|
+
{me ? <div>Hello {me.username}! <a href="/api/auth/logout">Logout</a></div> : <a href="/api/auth/login">Login</a>}
|
|
254
|
+
</div>
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Content!
|
|
259
|
+
|
|
260
|
+
Let's create a blog by adding new models in `src/config/models.ts`:
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
{
|
|
264
|
+
kind: 'entity',
|
|
265
|
+
name: 'Post',
|
|
266
|
+
listQueriable: true,
|
|
267
|
+
creatable: true,
|
|
268
|
+
updatable: true,
|
|
269
|
+
deletable: true,
|
|
270
|
+
fields: [
|
|
271
|
+
{
|
|
272
|
+
name: 'title',
|
|
273
|
+
type: 'String',
|
|
274
|
+
nonNull: true,
|
|
275
|
+
creatable: true,
|
|
276
|
+
updatable: true,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'content',
|
|
280
|
+
type: 'String',
|
|
281
|
+
nonNull: true,
|
|
282
|
+
creatable: true,
|
|
283
|
+
updatable: true,
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
kind: 'entity',
|
|
289
|
+
name: 'Comment',
|
|
290
|
+
creatable: true,
|
|
291
|
+
updatable: true,
|
|
292
|
+
deletable: true,
|
|
293
|
+
fields: [
|
|
294
|
+
{
|
|
295
|
+
kind: 'relation',
|
|
296
|
+
name: 'post',
|
|
297
|
+
type: 'Post',
|
|
298
|
+
nonNull: true,
|
|
299
|
+
creatable: true,
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'content',
|
|
303
|
+
type: 'String',
|
|
304
|
+
nonNull: true,
|
|
305
|
+
creatable: true,
|
|
306
|
+
updatable: true,
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Generate and run the new migrations and generate the new models:
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
npx gqm generate-migration
|
|
315
|
+
npx env-cmd knex migrate:up
|
|
316
|
+
npx gqm generate
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
new get-posts
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
import { gql } from '@smartive/graphql-magic';
|
|
323
|
+
|
|
324
|
+
export const GET_POSTS = gql`
|
|
325
|
+
query GetPosts {
|
|
326
|
+
posts {
|
|
327
|
+
id
|
|
328
|
+
title
|
|
329
|
+
content
|
|
330
|
+
createdBy {
|
|
331
|
+
username
|
|
332
|
+
}
|
|
333
|
+
comments {
|
|
334
|
+
id
|
|
335
|
+
createdBy {
|
|
336
|
+
username
|
|
337
|
+
}
|
|
338
|
+
content
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
`;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
{me && <CreatePost/> }
|
|
347
|
+
<Posts/>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
async function CreatePost() {
|
|
351
|
+
async function createPost(formData: FormData) {
|
|
352
|
+
'use server'
|
|
353
|
+
await executeGraphql<CreatePostMutationMutation, CreatePostMutationMutationVariables>({
|
|
354
|
+
query: CREATE_POST,
|
|
355
|
+
variables: {
|
|
356
|
+
data: {
|
|
357
|
+
title: formData.get('title') as string,
|
|
358
|
+
content: formData.get('content') as string
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
revalidatePath('/')
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return <form action={createPost}>
|
|
366
|
+
<h2>New Post</h2>
|
|
367
|
+
<div>
|
|
368
|
+
<span>Title</span>
|
|
369
|
+
<input name="title" />
|
|
370
|
+
</div>
|
|
371
|
+
<div>
|
|
372
|
+
<span>Content</span>
|
|
373
|
+
<textarea rows={5} name="content" />
|
|
374
|
+
</div>
|
|
375
|
+
<div>
|
|
376
|
+
<button type="submit">Create</button>
|
|
377
|
+
</div>
|
|
378
|
+
</form>
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async function Posts() {
|
|
382
|
+
const { data: { posts } } = await executeGraphql<GetPostsQuery>({ query: GET_POSTS })
|
|
383
|
+
|
|
384
|
+
return <div>
|
|
385
|
+
{posts.map(post => <div key={post.id}>
|
|
386
|
+
<article>
|
|
387
|
+
<h3>{post.title}</h3>
|
|
388
|
+
<div>{post.createdBy.username}</div>
|
|
389
|
+
<div>{post.content}</div>
|
|
390
|
+
{post.comments.map(comment => (<div key={comment.id}>
|
|
391
|
+
<div>{comment.createdBy.username}</div>
|
|
392
|
+
<p>{comment.content}</p> by {comment.createdBy.username}
|
|
393
|
+
</div>)
|
|
394
|
+
)}
|
|
395
|
+
<CreateComment postId={post.id} />
|
|
396
|
+
</article>
|
|
397
|
+
</div>)}
|
|
398
|
+
</div>
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function CreateComment({ postId }: { postId: string }) {
|
|
402
|
+
async function createComment(formData: FormData) {
|
|
403
|
+
'use server'
|
|
404
|
+
|
|
405
|
+
const res = await executeGraphql<CreateCommentMutationMutation, CreateCommentMutationMutationVariables>({
|
|
406
|
+
query: CREATE_COMMENT,
|
|
407
|
+
variables: {
|
|
408
|
+
data: {
|
|
409
|
+
postId,
|
|
410
|
+
content: formData.get('content') as string
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
})
|
|
414
|
+
console.log(res)
|
|
415
|
+
revalidatePath('/')
|
|
416
|
+
}
|
|
417
|
+
return <form action={createComment}>
|
|
418
|
+
<div>
|
|
419
|
+
<textarea name="content" placeholder="Leave a comment..." />
|
|
420
|
+
</div>
|
|
421
|
+
<div>
|
|
422
|
+
<button type="submit">Send</button>
|
|
423
|
+
</div>
|
|
424
|
+
</form>
|
|
425
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type * as Preset from '@docusaurus/preset-classic';
|
|
2
|
+
import type { Config } from '@docusaurus/types';
|
|
3
|
+
import { themes as prismThemes } from 'prism-react-renderer';
|
|
4
|
+
|
|
5
|
+
const config: Config = {
|
|
6
|
+
title: 'graphql-magic',
|
|
7
|
+
tagline: 'Model-first GraphQL API generator',
|
|
8
|
+
favicon: 'img/favicon.ico',
|
|
9
|
+
|
|
10
|
+
// Set the production url of your site here
|
|
11
|
+
url: 'https://your-docusaurus-site.example.com',
|
|
12
|
+
// Set the /<baseUrl>/ pathname under which your site is served
|
|
13
|
+
// For GitHub pages deployment, it is often '/<projectName>/'
|
|
14
|
+
baseUrl: '/',
|
|
15
|
+
|
|
16
|
+
// GitHub pages deployment config.
|
|
17
|
+
// If you aren't using GitHub pages, you don't need these.
|
|
18
|
+
organizationName: 'smartive', // Usually your GitHub org/user name.
|
|
19
|
+
projectName: 'graphql-magic', // Usually your repo name.
|
|
20
|
+
|
|
21
|
+
onBrokenLinks: 'throw',
|
|
22
|
+
onBrokenMarkdownLinks: 'warn',
|
|
23
|
+
|
|
24
|
+
i18n: {
|
|
25
|
+
defaultLocale: 'en',
|
|
26
|
+
locales: ['en'],
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
presets: [
|
|
30
|
+
[
|
|
31
|
+
'classic',
|
|
32
|
+
{
|
|
33
|
+
docs: {
|
|
34
|
+
sidebarPath: './sidebars.ts',
|
|
35
|
+
},
|
|
36
|
+
theme: {
|
|
37
|
+
customCss: './src/css/custom.css',
|
|
38
|
+
},
|
|
39
|
+
} satisfies Preset.Options,
|
|
40
|
+
],
|
|
41
|
+
],
|
|
42
|
+
|
|
43
|
+
themeConfig: {
|
|
44
|
+
// Replace with your project's social card
|
|
45
|
+
image: 'img/docusaurus-social-card.jpg',
|
|
46
|
+
navbar: {
|
|
47
|
+
title: 'graphql-magic',
|
|
48
|
+
logo: {
|
|
49
|
+
alt: 'graphql-magic Logo',
|
|
50
|
+
src: 'img/logo.svg',
|
|
51
|
+
},
|
|
52
|
+
items: [
|
|
53
|
+
{
|
|
54
|
+
type: 'docSidebar',
|
|
55
|
+
sidebarId: 'sidebar',
|
|
56
|
+
position: 'left',
|
|
57
|
+
label: 'Docs',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
href: 'https://github.com/smartive/graphql-magic',
|
|
61
|
+
label: 'GitHub',
|
|
62
|
+
position: 'right',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
footer: {
|
|
67
|
+
style: 'dark',
|
|
68
|
+
links: [
|
|
69
|
+
{
|
|
70
|
+
title: 'Docs',
|
|
71
|
+
items: [
|
|
72
|
+
{
|
|
73
|
+
label: 'Docs',
|
|
74
|
+
to: '/docs/intro',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: 'Community',
|
|
80
|
+
items: [
|
|
81
|
+
{
|
|
82
|
+
label: 'Linkedin',
|
|
83
|
+
href: 'https://www.linkedin.com/company/smartive-ch',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
title: 'More',
|
|
89
|
+
items: [
|
|
90
|
+
{
|
|
91
|
+
label: 'Blog',
|
|
92
|
+
to: 'https://smartive.ch/blog',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
label: 'GitHub',
|
|
96
|
+
href: 'https://github.com/smartive/graphql-magic',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
copyright: `Copyright © ${new Date().getFullYear()} smartive. Built with Docusaurus.`,
|
|
102
|
+
},
|
|
103
|
+
prism: {
|
|
104
|
+
theme: prismThemes.github,
|
|
105
|
+
darkTheme: prismThemes.dracula,
|
|
106
|
+
},
|
|
107
|
+
} satisfies Preset.ThemeConfig,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export default config;
|