Compare commits

...

120 Commits

Author SHA1 Message Date
Szilárd Dóró
8a8c67db92 Merge pull request #399 from nhost/changeset-release/main
chore: update versions
2022-04-13 10:49:05 +02:00
github-actions[bot]
357ba89d53 chore: update versions 2022-04-13 08:11:16 +00:00
Szilárd Dóró
7e34805eb4 Merge pull request #392 from nhost/feat/docusaurus
Migration to Docusaurus
2022-04-13 10:10:08 +02:00
Szilárd Dóró
52782ee550 fixed Hooks documentation 2022-04-13 10:04:08 +02:00
Szilárd Dóró
089d7fb0a2 replaced old docs with the docusaurus version 2022-04-13 10:00:11 +02:00
Szilárd Dóró
9df131201e README update 2022-04-12 16:49:37 +02:00
Szilárd Dóró
067d8a692c lock file update 2022-04-12 16:09:49 +02:00
Szilárd Dóró
824060e7f6 Merge branch 'main' into feat/docusaurus 2022-04-12 16:08:31 +02:00
Szilárd Dóró
0fe7b8f0fb fixed category slugs 2022-04-12 16:00:12 +02:00
Szilárd Dóró
78f096a738 Merge pull request #398 from nhost/fix/get-nhost-session-typing-improvements
fix: getNhostSession typing improvements, missing TSDoc
2022-04-12 15:39:54 +02:00
Szilárd Dóró
4635a145c1 improved getNhostSession function's typing, added missing tsdoc
added @types/cookies package
2022-04-12 15:33:17 +02:00
Szilárd Dóró
1446a8f13b Merge pull request #395 from nhost/changeset-release/main
chore: update versions
2022-04-12 14:54:23 +02:00
Johan Eliasson
ff75998e93 Merge pull request #397 from nhost/contributors-readme-action-v-3ccBloq6
contributors readme action update
2022-04-12 14:36:51 +02:00
github-actions[bot]
9cc044ca9f contrib-readme-action has updated readme 2022-04-12 12:28:41 +00:00
Johan Eliasson
c65e44b8d6 Merge pull request #396 from nhost/test/messaging-gql-be
Messaging test
2022-04-12 14:28:24 +02:00
Johan Eliasson
9ec73b4c22 edit readme 2022-04-12 14:25:47 +02:00
Szilárd Dóró
e4eda9e967 migrated changes from https://github.com/nhost/nhost/pull/385
added CTA to header
2022-04-12 14:07:37 +02:00
github-actions[bot]
94b70e0ce9 chore: update versions 2022-04-12 12:04:21 +00:00
Pilou
d108dff4f4 Merge pull request #387 from nhost/fix/sync-auth-state
fix onTokenChanged
2022-04-12 13:03:38 +01:00
Szilárd Dóró
7a8e771a72 Merge pull request #385 from gdangelo/patch-1
Add a table to detail the data returned by `useUserData`
2022-04-12 13:48:31 +02:00
Szilárd Dóró
f8fb4bbedd Merge pull request #393 from nhost/contributors-readme-action-L56J6ymmkI
contributors readme action update
2022-04-12 13:06:10 +02:00
Szilárd Dóró
90e38b1cc5 fixed build warnings, added missing videos 2022-04-12 13:04:31 +02:00
Szilárd Dóró
9c04dad57c Merge branch 'main' into feat/docusaurus 2022-04-12 12:51:45 +02:00
github-actions[bot]
c6b1c33a8e contrib-readme-action has updated readme 2022-04-12 10:51:37 +00:00
Szilárd Dóró
65b36eff13 Merge pull request #391 from gdangelo/patch-2
Update example with the latest version of React Router, v6
2022-04-12 12:51:21 +02:00
Szilárd Dóró
cac6088016 fixed broken links, fixed typo in authentication hooks 2022-04-12 11:47:47 +02:00
Grégory D'Angelo
c192cb9503 refact: Remove additional props to simplify example 2022-04-12 11:44:36 +02:00
Grégory D'Angelo
94ff290264 fix: Return Outlet in ProtectedRoute component + add missing closing tag + add explanation 2022-04-12 11:40:03 +02:00
Szilárd Dóró
aff80db515 updated slugs in new documentation to match old docs 2022-04-12 11:02:52 +02:00
Szilárd Dóró
6e2c991b2e added sitemap support to new docs page 2022-04-12 10:32:11 +02:00
Grégory D'Angelo
78781ebfec Update example with the latest version of React Router, v6 2022-04-12 09:04:28 +02:00
Pierre-Louis Mercereau
63d6059981 fix: fix onTokenChanged bugs 2022-04-11 20:55:02 +01:00
Grégory D'Angelo
022d49fb25 Add a table to detail the data returned by useUserData 2022-04-11 19:06:30 +02:00
Szilárd Dóró
a8e6187360 fixed a 404 error on deployed page 2022-04-11 17:49:55 +02:00
Szilárd Dóró
276d6b10dd fixed a 404 error on deployed page 2022-04-11 17:42:55 +02:00
Szilárd Dóró
62461a2f20 moved get-started/cli documentation to get-started/cli-workflow to better mirror old structure 2022-04-11 17:33:41 +02:00
Szilárd Dóró
81ec16d77b moved documentation from root folder to get-started to better mirror old documentation structure 2022-04-11 17:31:10 +02:00
Szilárd Dóró
5a059c1e9e fixed broken documentation links, reverted broken link severity to error 2022-04-11 17:13:21 +02:00
Szilárd Dóró
28bbde6142 finalized old documentation migration 2022-04-11 17:06:13 +02:00
Szilárd Dóró
05f01e45ec finalized Reference page in new docs 2022-04-11 16:04:58 +02:00
Szilárd Dóró
b1bd405a5e Merge branch 'main' into feat/docusaurus 2022-04-11 15:34:05 +02:00
Szilárd Dóró
a295b5b1e6 finalized platform page migration 2022-04-11 15:21:39 +02:00
Szilárd Dóró
eece559771 changed broken link severity from error to warning temporarily 2022-04-11 13:37:17 +02:00
Szilárd Dóró
cd0e4d1908 added remaining social providers to the new docs, optimized preview SVGs 2022-04-11 11:14:02 +02:00
Johan Eliasson
7bf678df9f docs update 2022-04-11 06:54:42 +02:00
Pilou
3bd1aa4d53 Merge pull request #357 from nhost/changeset-release/main
chore: update versions
2022-04-10 08:51:47 +01:00
github-actions[bot]
f3cca4997b chore: update versions 2022-04-10 07:44:55 +00:00
Pilou
0fd7a487d6 Merge pull request #382 from nhost/fix/sync-auth-state
Keep authentication status and access token in sync
2022-04-10 08:44:15 +01:00
Pierre-Louis Mercereau
1bb032c1e7 chore: remove console.log and add explaination 2022-04-09 20:48:00 +01:00
Pierre-Louis Mercereau
2c97db68b5 fix: sync auth state with all the nhost sub-clients 2022-04-09 20:44:38 +01:00
Johan Eliasson
714f2872ee Merge pull request #380 from nhost/contributors-readme-action-nMk7JwQ8hY
contributors readme action update
2022-04-09 16:19:05 +02:00
github-actions[bot]
65fc26a0e8 contrib-readme-action has updated readme 2022-04-09 14:11:13 +00:00
Johan Eliasson
86a56f28c1 Merge pull request #379 from Savinvadim1312/patch-1
Fix a type in react documentation
2022-04-09 16:10:55 +02:00
Savin Vadim
6e8abe28d6 Fix a type in react documentation
Fix a typo in the `nhsot/react` documentation in the code example. 

The imported hook had a wrong name
2022-04-09 13:41:56 +01:00
Szilárd Dóró
39925ff5ca Merge pull request #376 from nhost/fix/documentation-react-router
React Router example upgraded to v6
2022-04-08 16:03:09 +02:00
Szilárd Dóró
583a77ed0d build fix and sitemap updates 2022-04-08 15:12:34 +02:00
Szilárd Dóró
e704831500 upgraded AuthGate example documentation to use react-router v6 2022-04-08 15:03:31 +02:00
Szilárd Dóró
a8f82e8133 improved navigation structure on Reference page 2022-04-08 09:10:25 +02:00
Johan Eliasson
95948dd5b9 Merge pull request #372 from nhost/contributors-readme-action-9bzNZt6pM9
contributors readme action update
2022-04-08 07:24:40 +02:00
github-actions[bot]
247b69c952 contrib-readme-action has updated readme 2022-04-08 05:24:23 +00:00
Johan Eliasson
7d15b76402 Merge pull request #359 from nhost/contributors-readme-action-txEVhnQt0i
contributors readme action update
2022-04-08 07:24:11 +02:00
github-actions[bot]
b1ae65fd72 contrib-readme-action has updated readme 2022-04-07 18:55:02 +00:00
Pilou
0063fd1840 Merge pull request #358 from Savinvadim1312/patch-1
Fix a typo in the React docs
2022-04-07 19:54:48 +01:00
Savin Vadim
743a7e6507 Fix a typo in the React docs
Changed from `clientStorageGetter` to `clientStorageSetter` on the line referencing the setter function
2022-04-07 19:43:30 +01:00
Szilárd Dóró
1687f7af04 improved sidebar structure of docs, added reference page 2022-04-07 20:35:54 +02:00
Pilou
078652861f Merge pull request #345 from nhost/fix/dont-remove-ts-comments
fix: don't remove comments so they are present in the built .d.ts
2022-04-07 19:27:39 +01:00
Pilou
39840cfd95 Merge pull request #347 from nhost/docs/update-examples
Update examples to bump versions & hooks syntax, and fix dead link in react-apollo readme
2022-04-07 19:26:49 +01:00
Szilárd Dóró
102c99e491 asset cleanup, redirect and docs route fixes 2022-04-07 17:49:31 +02:00
Szilárd Dóró
a3702a644e removed unnecessary files related to the default placeholder page 2022-04-07 16:51:24 +02:00
Szilárd Dóró
db65fea706 more branding related changes, redirect support 2022-04-07 16:48:40 +02:00
Szilárd Dóró
ffe9123b48 fixed build issues caused by broken links 2022-04-07 15:29:07 +02:00
Szilárd Dóró
f112ea2115 fixed text color in dark mode 2022-04-07 15:17:26 +02:00
Szilárd Dóró
4963153def basic docusaurus stylign improvements 2022-04-07 15:02:44 +02:00
Johan Eliasson
940a36a68f Merge pull request #352 from nhost/contributors-readme-action-YMeH8uC8qa
contributors readme action update
2022-04-07 13:23:41 +02:00
github-actions[bot]
77b109b3df contrib-readme-action has updated readme 2022-04-07 11:22:27 +00:00
Johan Eliasson
15907d65e6 Merge pull request #351 from nhost/contr-test-1
readme update
2022-04-07 13:22:12 +02:00
Johan Eliasson
7d7d16fa71 readme update 2022-04-07 13:21:56 +02:00
Johan Eliasson
3f39e48cbd Merge pull request #349 from nhost/contributors
contr init
2022-04-07 13:18:57 +02:00
Johan Eliasson
97ade32869 contr init 2022-04-07 13:18:22 +02:00
Pierre-Louis Mercereau
8583af8290 chore: changeset 2022-04-07 09:34:46 +02:00
Pierre-Louis Mercereau
a28193a6ba docs: correct link to documentation 2022-04-07 09:30:15 +02:00
Johan Eliasson
60d85e5a69 init structure updates 2022-04-06 15:46:12 +02:00
Pierre-Louis Mercereau
9d6c64430a chore: remove rsuite toaster workaround 2022-04-06 15:44:57 +02:00
Pierre-Louis Mercereau
519d1bf5cb chore: prettier and lint fix 2022-04-06 15:39:29 +02:00
Pierre-Louis Mercereau
5ffb0320b5 docs: update examples to bump versions and to match the recommended hooks syntax 2022-04-06 15:31:58 +02:00
Johan Eliasson
50d2413554 Update README.md 2022-04-06 15:19:50 +02:00
Szilárd Dóró
7d275aad90 initialized Docusaurus project 2022-04-06 15:12:08 +02:00
Pierre-Louis Mercereau
6607e73cc2 fix: don't remove comments so they are present in the built .d.ts 2022-04-06 15:07:37 +02:00
Pilou
b4bac161a5 Merge pull request #344 from timpratim/patch-2
Separated the commands for installation
2022-04-06 12:56:28 +02:00
Pratim
37d15377c8 Separated the commands for installation
Separated the commands for installation according to the package managers.
2022-04-06 15:33:45 +05:30
Pilou
8ee1df3be4 Merge pull request #343 from nhost/changeset-release/main
chore: update versions
2022-04-06 10:50:29 +02:00
Pilou
47ffca945e Update package.json 2022-04-06 10:46:11 +02:00
Pilou
d60f5e623c Update CHANGELOG.md 2022-04-06 10:45:41 +02:00
Pilou
6f80643ee0 Update package.json 2022-04-06 10:45:10 +02:00
Pilou
8d5084725d Update CHANGELOG.md 2022-04-06 10:44:56 +02:00
Pilou
693498dd09 Update CHANGELOG.md 2022-04-06 10:37:39 +02:00
Pilou
4d36a966ea Update CHANGELOG.md 2022-04-06 10:37:02 +02:00
Pilou
239a075f1d Update CHANGELOG.md 2022-04-06 10:36:37 +02:00
github-actions[bot]
931194812e chore: update versions 2022-04-06 08:33:17 +00:00
Pilou
c8f80c58f3 Merge pull request #335 from nhost/refactor/correct-react-hook-signature
React hook signature & add promises to hook action results
2022-04-06 10:32:33 +02:00
Pilou
7fdb5aee0a Merge pull request #334 from nhost/docs/bump-version-examples
docs: bump dependencies of react-apollo and nextjs examples
2022-04-05 20:52:12 +02:00
Pilou
1710808fef Merge pull request #321 from nhost/docs/correct-hljs
docs: pass language to react-syntax-highlighter
2022-04-05 20:52:00 +02:00
Pilou
696815d4a8 Merge pull request #311 from nhost/306-the-useuserdata-hook-does-not-return-the-emailverified-or-phonenumberverified-user-properties
Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type, and add missing providers types
2022-04-05 20:51:42 +02:00
Pilou
5cc9be00b6 Merge pull request #341 from nhost/changeset-release/main
chore: update versions
2022-04-05 16:14:26 +02:00
github-actions[bot]
28dae23a91 chore: update versions 2022-04-05 14:02:46 +00:00
Pilou
7819e20cf4 Merge pull request #340 from nhost/elitan-patch-1
Correct OAuth provider link
2022-04-05 16:01:42 +02:00
Johan Eliasson
6be3758668 Create ninety-eels-lick.md 2022-04-05 15:56:18 +02:00
Johan Eliasson
658c67faf4 Update hasura-auth-client.ts 2022-04-05 15:54:39 +02:00
Pierre-Louis Mercereau
e7f3a5f6e0 chore: ellaborate changesets 2022-04-05 10:50:55 +02:00
Pierre-Louis Mercereau
7135aee78b chore: add changeset 2022-04-05 10:42:44 +02:00
Pierre-Louis Mercereau
587eaff734 feat: add promise with the current context to hooks actions 2022-04-04 20:45:12 +02:00
Pierre-Louis Mercereau
7cf875f4b8 refactor: deprecate the use of values end as hook parameters 2022-04-04 16:56:46 +02:00
Pierre-Louis Mercereau
657cfb91c5 docs: update corresponding swagger api 2022-04-04 10:42:09 +02:00
Pierre-Louis Mercereau
103dd6e98e Merge branch 'main' into 306-the-useuserdata-hook-does-not-return-the-emailverified-or-phonenumberverified-user-properties 2022-04-04 10:40:05 +02:00
Pierre-Louis Mercereau
3c8caa680b docs: bump dependencies of react-apollo and nextjs examples
and remove workaround related to https://github.com/rsuite/rsuite/issues/2336
2022-04-03 23:45:06 +02:00
Pilou
1bcee357fe Merge pull request #325 from nhost/docs/auth-refresh-expiration
docs: change default refresh token expiration to 30 days
2022-04-03 22:32:21 +02:00
Pierre-Louis Mercereau
b729aa9290 ci: fix pnpm/npm/changeset 2022-04-03 22:26:58 +02:00
Pierre-Louis Mercereau
9b840f7c4a docs: change default refresh token expiration to 30 days 2022-04-01 21:15:40 +02:00
Pierre-Louis Mercereau
83d3c90f43 docs: pass language to react-syntax-highlighter 2022-03-31 21:57:40 +02:00
Pierre-Louis Mercereau
058956bdcb feat: update types 2022-03-31 12:27:47 +02:00
323 changed files with 9009 additions and 6835 deletions

View File

@@ -30,6 +30,9 @@ jobs:
with:
node-version: '17.8.0'
cache: 'pnpm'
- name: Pick the right npm version
# * See: https://github.com/pnpm/pnpm/issues/4348
run: npm install --global npm@8.4
- name: Install dependencies
run: pnpm install
- name: Create PR or Publish release
@@ -39,7 +42,7 @@ jobs:
version: pnpm run ci:version
commit: 'chore: update versions'
title: 'chore: update versions'
publish: pnpm run ci:publish
publish: pnpm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

15
.github/workflows/contributors.yaml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Add contributors
on:
push:
branches:
- main
jobs:
contrib-readme-job:
runs-on: ubuntu-latest
name: A job to automate contrib in readme
steps:
- name: Contribute List
uses: akhilmhdh/contributors-readme-action@v2.3.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

201
README.md
View File

@@ -1,8 +1,8 @@
<div align="center">
<img width="237" src="https://raw.githubusercontent.com/nhost/nhost/main/assets/logo.png"/>
![Nhost](https://imgur.com/fGo6E4d.png)
<br />
<br />
<div align="center">
# Nhost
<a href="https://docs.nhost.io/get-started">Quickstart</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
@@ -20,9 +20,9 @@
<hr />
</div>
**Nhost is a serverless backend for web and mobile apps** built with the following things in mind:
**Nhost is a open-source GraphQL backend,** built with the following things in mind:
- Open Source
- Open-Source
- Developer Productivity
- SQL
- GraphQL
@@ -110,7 +110,7 @@ First and foremost: **Star and watch this repository** to stay up-to-date.
Also, follow Nhost on [GitHub Discussions](https://github.com/nhost/nhost/discussions), our [Blog](https://nhost.io/blog), and on [Twitter](https://twitter.com/nhostio). You can chat with the team and other members on [Discord](https://discord.com/invite/9V7Qb2U) and follow our tutorials and other video material at [YouTube](https://www.youtube.com/channel/UCJ7irtvV9Y0EQMxpabb6ntg?view_as=subscriber).
## Nhost is Open Source
### Nhost is Open Source
This repository, and most of our other open source projects, are licensed under the MIT license.
@@ -122,6 +122,189 @@ Here are some ways of contributing to making Nhost better:
- Join our [Discord](https://discord.com/invite/9V7Qb2U) and connect with other members to share and learn from.
- Send a pull request to any of our [open source repositories](https://github.com/nhost) on Github. Check our [contribution guide](https://github.com/nhost/nhost/blob/main/CONTRIBUTING.md) for more details about how to contribute. We're looking forward to your contribution!
## Security
### Contributors
If you discover a security vulnerability within Nhost, please e-mail [security@nhost.io](mailto:security@nhost.io). All security vulnerabilities will be promptly addressed.
<!-- readme: contributors -start -->
<table>
<tr>
<td align="center">
<a href="https://github.com/plmercereau">
<img src="https://avatars.githubusercontent.com/u/24897252?v=4" width="100;" alt="plmercereau"/>
<br />
<sub><b>Pilou</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elitan">
<img src="https://avatars.githubusercontent.com/u/331818?v=4" width="100;" alt="elitan"/>
<br />
<sub><b>Johan Eliasson</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/szilarddoro">
<img src="https://avatars.githubusercontent.com/u/310881?v=4" width="100;" alt="szilarddoro"/>
<br />
<sub><b>Szilárd Dóró</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/nunopato">
<img src="https://avatars.githubusercontent.com/u/1523504?v=4" width="100;" alt="nunopato"/>
<br />
<sub><b>Nuno Pato</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/subatuba21">
<img src="https://avatars.githubusercontent.com/u/34824571?v=4" width="100;" alt="subatuba21"/>
<br />
<sub><b>Subha Das</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/guicurcio">
<img src="https://avatars.githubusercontent.com/u/20285232?v=4" width="100;" alt="guicurcio"/>
<br />
<sub><b>Guido Curcio</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/sebagudelo">
<img src="https://avatars.githubusercontent.com/u/43288271?v=4" width="100;" alt="sebagudelo"/>
<br />
<sub><b>Sebagudelo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mrinalwahal">
<img src="https://avatars.githubusercontent.com/u/9859731?v=4" width="100;" alt="mrinalwahal"/>
<br />
<sub><b>Mrinal Wahal</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/gdangelo">
<img src="https://avatars.githubusercontent.com/u/4352286?v=4" width="100;" alt="gdangelo"/>
<br />
<sub><b>Grégory D'Angelo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/FuzzyReason">
<img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/>
<br />
<sub><b>Vadim Smirnov</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/subhendukundu">
<img src="https://avatars.githubusercontent.com/u/20059141?v=4" width="100;" alt="subhendukundu"/>
<br />
<sub><b>Subhendu Kundu</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/chrtze">
<img src="https://avatars.githubusercontent.com/u/3797215?v=4" width="100;" alt="chrtze"/>
<br />
<sub><b>Christopher Möller</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/jerryjappinen">
<img src="https://avatars.githubusercontent.com/u/1101002?v=4" width="100;" alt="jerryjappinen"/>
<br />
<sub><b>Jerry Jäppinen</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mustafa-hanif">
<img src="https://avatars.githubusercontent.com/u/30019262?v=4" width="100;" alt="mustafa-hanif"/>
<br />
<sub><b>Mustafa Hanif</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Savinvadim1312">
<img src="https://avatars.githubusercontent.com/u/16936043?v=4" width="100;" alt="Savinvadim1312"/>
<br />
<sub><b>Savin Vadim</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ahmic">
<img src="https://avatars.githubusercontent.com/u/13452362?v=4" width="100;" alt="ahmic"/>
<br />
<sub><b>Amir Ahmic</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/akd-io">
<img src="https://avatars.githubusercontent.com/u/30059155?v=4" width="100;" alt="akd-io"/>
<br />
<sub><b>Anders Kjær Damgaard</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/rustyb">
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
<br />
<sub><b>Colin Broderick</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/dohomi">
<img src="https://avatars.githubusercontent.com/u/489221?v=4" width="100;" alt="dohomi"/>
<br />
<sub><b>Dominic Garms</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/alveshelio">
<img src="https://avatars.githubusercontent.com/u/8176422?v=4" width="100;" alt="alveshelio"/>
<br />
<sub><b>Helio Alves</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/nkhdo">
<img src="https://avatars.githubusercontent.com/u/26102306?v=4" width="100;" alt="nkhdo"/>
<br />
<sub><b>Hoang Do</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ghoshnirmalya">
<img src="https://avatars.githubusercontent.com/u/6391763?v=4" width="100;" alt="ghoshnirmalya"/>
<br />
<sub><b>Nirmalya Ghosh</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/timpratim">
<img src="https://avatars.githubusercontent.com/u/32492961?v=4" width="100;" alt="timpratim"/>
<br />
<sub><b>Pratim</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/quentin-decre">
<img src="https://avatars.githubusercontent.com/u/1137511?v=4" width="100;" alt="quentin-decre"/>
<br />
<sub><b>Quentin Decré</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/komninoschat">
<img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/>
<br />
<sub><b>Komninos</b></sub>
</a>
</td></tr>
</table>
<!-- readme: contributors -end -->

View File

@@ -1,17 +0,0 @@
{
"root": true,
"extends": ["next", "prettier"],
"rules": {
"@next/next/no-img-element": "off",
"import/no-default-export": "off",
"react/self-closing-comp": "warn",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/no-unescaped-entities": "off",
"react/prop-types": "off",
"jsx-a11y/anchor-is-valid": "off",
"no-console": "warn"
},
"parser": "@typescript-eslint/parser",
"settings": { "react": { "version": "detect" } }
}

22
docs/.gitignore vendored
View File

@@ -1,2 +1,20 @@
!lib
!.prettierignore
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -1,2 +0,0 @@
node_modules/
.next/

11
docs/.prettierrc.json Normal file
View File

@@ -0,0 +1,11 @@
{
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": false,
"endOfLine": "auto",
"semi": true
}

View File

@@ -1,6 +0,0 @@
# nhost-documentation
## null
### Patch Changes
- 03562af: Build in CommonJS and ESM instead of UMD and ESM as the UMD bundle generated by the default Vite lib build mode doesn't work with NodeJS

View File

@@ -1,48 +1,37 @@
# Nhost Documentation
# Nhost Docs
## Get started
This documentation describes how to build, start and test the documentation locally.
From the **root** of the `nhost/nhost` repository:
### Installation
```bash
pnpm run clean:all
pnpm i
cd docs
pnpm run dev
$ pnpm i
```
### Local Development
## Structure
The `order.ts` file contains the main order for the entire structure of `posts`. The keys are `categories` and the values are `subcategories` in which contains the order the posts.
```
export const orderTwo = {
'get-started': {
'quick-start': ['index', 'schema', 'javascript-client', 'permissions'],
authentication: ['index'],
'cli-workflow': ['index', 'workflow-setup', 'install-cli', 'local-changes', 'metadata-and-serverless-functions'],
upgrade: ['index']
},
platform: {
database: ['index', 'permissions', 'graphql'],
authentication: ['index', 'user-management', 'sign-in-methods', 'social-login', 'email-templates'],
storage: ['index'],
'serverless-functions': ['index', 'event-triggers'],
nhost: ['index', 'environment-variables', 'github-integration', 'local-development']
},
reference: {
sdk: ['index', 'graphql', 'authentication', 'storage', 'functions'],
react: ['index', 'hooks', 'protecting-routes', 'apollo'],
nextjs: ['index', 'configuration', 'protecting-routes', ],
cli: ['index'],
'hasura-auth': ['index', 'installation', 'configuration', 'environment-variables', 'schema', 'api-reference']
}
};
```bash
$ pnpm start
```
Metadata such as the `title` of the file that appears on the nav is on the frontmatter of each markdown file. The file name becomes the final url. Each top-level folder appears on the header as main navigation, each subfolder becomes a main subcategory of the nav and posts are included under each subcategory.
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
In order to create a new file you place it its proper subcategory and modify the category on the `order.ts` file such as `sdk: ["javascript-sdk", "react-auth", "react-apollo"],` -> `sdk: ["javascript-sdk", "react-auth", "vue"]`
### Build
Each subCategory e.g. `reference` or `tutorials` has an `index.mdx` file. If a new subcategory is added, a file has to be created for it.
```bash
$ pnpm build
```
This command generates static content into the `build` directory and can be served using any static contents hosting service.
### Serve
```bash
$ pnpm serve
```
This command serves the static content from the `build` directory.
### Contributing
All pull requests are greatly appreciated! See our [contributing guide](https://github.com/nhost/nhost/blob/main/CONTRIBUTING.md) to get started.

3
docs/babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

View File

@@ -1,81 +0,0 @@
import Text from '@/components/ui/Text'
import { motion } from 'framer-motion'
import { useRouter } from 'next/dist/client/router'
import React, { useState } from 'react'
import createKebabCase from '../utils/createKebabCase'
import Permalink from './icons/Permalink'
export interface AnchorLinkProps {
children?: any
id?: string
size?: 'tiny' | 'small' | 'normal' | 'large' | 'big' | 'heading'
className?: string
}
export default function AnchorLink({ children, id, size, className }: AnchorLinkProps) {
const {
query: { category, subcategory, post }
} = useRouter()
const [showPermaLink, setShowPermalink] = useState(false)
const isQuoted = typeof children !== 'string'
return (
<div
id={
id
? children.split('/')[1]
: createKebabCase(
`#${isQuoted ? (children.props ? children.props.children : children) : children}`
)
}
className={className}
onMouseOver={() => setShowPermalink(true)}
onMouseLeave={() => setShowPermalink(false)}
>
<span id={createKebabCase(`${children}`)} className={'flex flex-row relative'}>
{showPermaLink ? (
<motion.span
className="absolute self-center w-4 h-4 align-middle -left-5"
onClick={() => {
navigator.clipboard
.writeText(
`https://docs.nhost.io/${category}/${subcategory}/${post}/${
id
? id
: createKebabCase(
`#${
isQuoted
? children.props
? children.props.children
: children
: children
}`
)
}`
)
.catch((e) => {
// eslint-disable-next-line no-console
console.log(e)
})
}}
>
<Permalink className="w-4 h-4" />
</motion.span>
) : (
<></>
)}
<Text
variant="a"
href={createKebabCase(
`#${isQuoted ? (children.props ? children.props.children : children) : children}`
)}
color="greyscaleDark"
className="font-medium break-all"
>
{children}
</Text>
</span>
</div>
)
}

View File

@@ -1,36 +0,0 @@
import React from 'react'
import { useState } from 'react'
import Check from './icons/Check'
import Copy from './icons/Copy'
export default function Command({ children }) {
const [copied, setCopied] = useState(false)
return (
<div className="my-1 flex-row inline-flex self-center text-xs bg-gray-50 pl-2 pr-1.5 text-gray-900 font-mono leading-6 py-0.25 border border-gray-200 rounded-md">
<span className="text-verydark mr-1.5 self-center">$</span>
{children}
<button
className="ml-1.5 self-center inline-block cursor-pointer"
onClick={() => {
navigator.clipboard.writeText(children).catch((e) => {
// eslint-disable-next-line no-console
console.log(e)
})
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 1000)
}}
>
{/* <Tooltip text={"Copied!"}> */}
{copied ? (
<Check className="w-3.5 h-3.5 mr-0.5 text-greenDark transition-colors self-center" />
) : (
<Copy className="w-4 h-4 text-gray-500 transition-colors hover:text-gray-900" />
)}
{/* </Tooltip> */}
</button>
</div>
)
}

View File

@@ -1,7 +0,0 @@
export function Container({ children }) {
return (
<div className="mx-10 px-2 sm:px-10 md:px-20 lg:px-0 flex flex-row md:max-w-container pb-20 md:mx-auto mt-8 lg:space-x-20">
{children}
</div>
)
}

View File

@@ -1,47 +0,0 @@
import markdownStyles from '@/styles/markdown-styles.module.css'
import { DOCS_GITHUB_ENDPOINT } from '@/utils/constants'
import { MDXRemote } from 'next-mdx-remote'
import { useRouter } from 'next/dist/client/router'
import React from 'react'
import GithubIcon from './icons/GithubIcon'
import Button from './ui/Button/Button'
import Text from './ui/Text/Text'
function getGithubLink(category, subcategory, post) {
if (post) return `${DOCS_GITHUB_ENDPOINT}${category}/${subcategory}/${post}.mdx`
else if (subcategory) return `${DOCS_GITHUB_ENDPOINT}${category}/${subcategory}/index.mdx`
else {
return `${DOCS_GITHUB_ENDPOINT}${category}/index.mdx`
}
}
export function Content({ mdxSource, components, frontmatter }) {
const router = useRouter()
return (
<div className="flex flex-col w-full h-full mt-2">
<div className="flex flex-row mb-4 place-content-between">
<Text color="greyscaleDark" className="font-medium cursor-pointer" size="heading">
{frontmatter.title}
</Text>
<div className="self-center hidden md:block">
<Button
Component="a"
variant="secondary"
className="invisible md:visible"
href={getGithubLink(router.query.category, router.query.subcategory, router.query.post)}
target="_blank"
rel="noreferrer"
type={null}
>
Edit This Page
<GithubIcon className="w-3.5 h-3.5 ml-1.5 text-greyscaleDark self-center" />
</Button>
</div>
</div>
<div className={markdownStyles['markdown']}>
<MDXRemote {...mdxSource} components={components} lazy />
</div>
</div>
)
}

View File

@@ -1,21 +0,0 @@
import { withRouter } from 'next/router'
import Link from 'next/link'
import React, { Children } from 'react'
const CustomLink = ({ router, children, ...props }) => {
const child = Children.only(children)
let className = child.props.className || ''
const pathname = `/${router.query.category}/${router.query.post}`
if (pathname === props.href && props.activeClassName) {
className = `${className} ${props.activeClassName}`.trim()
}
delete props.activeClassName
// @ts-ignore
return <Link {...props}>{React.cloneElement(child, { className })}</Link>
}
export default withRouter(CustomLink)

View File

@@ -1,5 +0,0 @@
import React from 'react'
export default function Divider() {
return <div className="divider mt-6 mb-4 order-2" />
}

View File

@@ -1,162 +0,0 @@
import Button from '@/components/ui/Button'
import siteLinks from '@/data/siteLinks.json'
import Link from 'next/link'
import React from 'react'
import { useState } from 'react'
import { Newsletter } from './Newsletter'
// import Input from './ui/Input/Input';
export default function Footer() {
const [email, setEmail] = useState('')
return (
<div className="bg-verydark">
<div className="max-w-mxcontainer px-5 mx-auto">
<div className="flex flex-col pt-20">
{/* Logo and CTA */}
<div className="place-content-between flex flex-row">
<div className="">
<img
src="/logos/nhost-footer-logo.svg"
width={141.57}
height={48}
alt="Nhost white logo"
/>
</div>
<div className="flex flex-row self-center">
<Button
Component="a"
variant="secondary"
className="md:visible invisible mr-2 text-white cursor-pointer"
href="mailto:hello@nhost.io"
type={null}
>
Contact Us
</Button>
<Button
Component="a"
variant="primary"
href="https://app.nhost.io"
target="_blank"
rel="noreferrer"
className="cursor-pointer"
type={null}
>
<span className="md:block hidden">Sign up or Log in</span>
<span className="md:hidden">Sign up</span>
</Button>
</div>
</div>
{/* All links */}
{/* @FIX: space-x on the firSubscribest one. */}
<div className="font-display md:flex-row flex flex-col mt-12">
<div className="gap-14 md:grid-flow-col md:grid-cols-5 grid grid-flow-row grid-cols-1">
{siteLinks.siteLinks.map((siteLink, i) => {
return (
<FooterLinks
key={siteLink.text + i}
title={siteLink.text}
links={siteLink.links}
/>
)
})}
</div>
</div>
<Newsletter />
{/* <Newsletter email={email} setEmail={setEmail} /> */}
{/* Socials */}
{/* @FIX: mt is 103px */}
<div className="md:mx-0 place-content-between font-display md:flex-row flex flex-col pb-2 mx-auto mt-24">
<div className="pb-2">
<ul className="flex flex-row space-x-6">
<li className="items-center self-center align-middle">
<a href="https://github.com/nhost" target="_blank" rel="noreferrer">
<img src="/logos/Github.svg" width={25} height={25} alt="Nhost on GitHub" />
</a>
</li>
<li className="items-center self-center align-middle">
<a href="https://twitter.com/nhostio" target="_blank" rel="noreferrer">
<img src="/logos/Twitter.svg" width={25} height={25} alt="Nhost on Twitter" />
</a>
</li>
<li className="items-center self-center align-middle">
<a
href="https://www.linkedin.com/company/nhost/"
target="_blank"
rel="noreferrer"
>
<img src="/logos/Linkedin.svg" width={25} height={25} alt="Nhost in LinkedIn" />
</a>
</li>
<li className="items-center self-center align-middle">
<a href="https://discord.com/invite/9V7Qb2U" target="_blank" rel="noreferrer">
<img
src="/logos/Discord.svg"
width={25}
height={25}
alt="Nhost community on Discord"
/>
</a>
</li>
</ul>
</div>
<div className="md:pt-0 md:space-y-0 md:flex-row flex flex-col pt-2 space-y-4 text-xs font-medium text-white">
<a
className="translucent self-center"
href="https://nhost.io/privacy-policy"
target="_blank"
rel="noreferrer"
>
Privacy Policy
</a>
<a
className="md:pl-6 translucent self-center"
href="https://nhost.io/terms-of-service"
target="_blank"
rel="noreferrer"
>
Terms of Service
</a>
<a
className="md:pl-6 translucent self-center"
href="https://nhost.io"
target="_blank"
rel="noreferrer"
>
nhost.io 2022
</a>
</div>
</div>
</div>
</div>
</div>
)
}
interface FooterLinkProps {
title: string
links: Links[]
}
interface Links {
name: string
href: string
}
function FooterLinks({ title, links }: FooterLinkProps) {
return (
<div>
{/* color */}
<h1 className="font-medium text-gray-700 uppercase">{title}</h1>
<ul className="mt-4 space-y-4">
{links.map((link) => {
return (
<li key={link.name} className="text-white font-normal text-sm+ cursor-pointer">
<Link href={link.href}>{link.name}</Link>
</li>
)
})}
</ul>
</div>
)
}

View File

@@ -1,277 +0,0 @@
import { useNavData } from '@/components/NavDataContext'
import { ArrowLeftIcon, MenuIcon } from '@heroicons/react/outline'
import clsx from 'clsx'
import { useRouter } from 'next/dist/client/router'
import Link from 'next/link'
import React, { MouseEvent, useEffect, useState } from 'react'
import Button from '../components/ui/Button'
import { Nav } from './Nav'
export default function Header() {
const [mobileMenu, setMobileMenu] = useState(false)
const router = useRouter()
const GithubStarsCounter = () => {
const repoUrl = `https://api.github.com/repos/nhost/nhost`
const [count, setCount] = useState(null)
const format = (n: number) => (n > 1000 ? `${(n / 1000).toFixed(1)}k` : n)
useEffect(() => {
;(async () => {
const data = await fetch(repoUrl).then((res) => res.json())
setCount(data.stargazers_count)
})()
}, [repoUrl])
return (
<a
className="text-base font-medium leading-snug flex flex-row items-center justify-center px-2.5 py-1.5 rounded opacity-50 hover:opacity-100 mr-8"
href="https://github.com/nhost/nhost"
target="_blank"
rel="noreferrer"
>
<img
className="mr-2"
src="/logos/Github2.svg"
width={20}
height={20}
alt="Nhost on GitHub"
/>
{count === null ? 0 : format(count)}
</a>
)
}
function handleMobileMenuOpen() {
setMobileMenu(true)
}
function handleMobileMenuClose() {
setMobileMenu(false)
}
if (mobileMenu) {
return <MobileNav onClose={handleMobileMenuClose} />
}
return (
<header className="bg-white md:max-w-full menu-card rounded-md px-4 py-0.5 mx-2">
<div className="md:max-w-header2 mx-auto font-display flex flex-row antialiased">
<div className="flex flex-row w-full mx-auto place-content-between py-2">
<div className="flex flex-row">
<button
className="md:hidden w-8 h-8 flex items-center justify-center cursor-pointer text-greyscaleDark"
aria-label="Open menu"
onClick={handleMobileMenuOpen}
>
<MenuIcon className="h-6 w-6" />
</button>
<Link href="/get-started" passHref>
<a className="hidden ml-3 sm:ml-0 self-center md:flex flex-row cursor-pointer">
<img src="/images/nhost-docs.svg" width={110} height={35} alt="Nhost white logo" />
<h1 className="self-center ml-6 font-medium text-greyscaleDark">DOCS</h1>
</a>
</Link>
<div className="ml-20 hidden md:flex flex-row self-center ">
<ul className="flex flex-row items-center self-center antialiased font-medium text-greyscaleGrey font-display">
<Link href="/get-started" passHref={true}>
<a
className={clsx(
'cursor-pointer text-base- self-center hover:text-greyscaleDark transition-colors duration-200 py-3',
router.query.category === 'get-started' && 'text-greyscaleDark'
)}
>
Get Started
</a>
</Link>
<Link href="/platform" passHref={true}>
<a
className={clsx(
'ml-12 cursor-pointer text-base- self-center hover:text-greyscaleDark transition-colors duration-200 py-3',
router.query.category === 'platform' && 'text-greyscaleDark'
)}
>
Platform
</a>
</Link>
<Link href="/reference" passHref={true}>
<a
className={clsx(
'ml-12 cursor-pointer text-base- self-center hover:text-greyscaleDark transition-colors duration-200 py-3',
router.query.category === 'reference' && 'text-greyscaleDark'
)}
>
Reference
</a>
</Link>
</ul>
</div>
</div>
<div className="hidden sm:flex self-center">
<GithubStarsCounter />
<Button
className="self-center"
variant="primary"
href={'https://app.nhost.io'}
Component="a"
target="_blank"
rel="noreferrer"
type={null}
>
Go to Nhost
</Button>
</div>
</div>
</div>
</header>
)
}
export type MobileNavProps = {
onClose?: VoidFunction
}
export function MobileNav({ onClose }: MobileNavProps) {
const { getConvolutedNavByCategory } = useNavData()
const router = useRouter()
const [selectedMenuSlug, setSelectedMenuSlug] = useState<string | null>(null)
const [selectedMenuName, setSelectedMenuName] = useState<string | null>(null)
function handleMenuSelect(event: MouseEvent<HTMLAnchorElement>, slug: string, name: string) {
event.preventDefault()
setSelectedMenuSlug(slug)
setSelectedMenuName(name)
}
function clearMenuSelection() {
setSelectedMenuSlug(null)
setSelectedMenuName(null)
}
return (
<div className="bg-white menu-card rounded-lg px-4 pb-6 max-w-full mx-2">
<div className="flex flex-col w-full py-3 mx-auto">
<div className="grid grid-flow-col justify-between items-center">
{!selectedMenuSlug && (
<>
<button
className="w-8 h-8 flex items-center justify-center cursor-pointer text-greyscaleDark"
aria-label="Close menu"
onClick={onClose}
>
<MenuIcon className="h-6 w-6" aria-hidden="true" />
</button>
<Link href="/get-started" passHref>
<a
className="ml-3 sm:ml-0 self-center flex flex-row cursor-pointer"
onClick={onClose}
>
<img
src="/images/nhost-docs.svg"
width={110}
height={35}
alt="Nhost white logo"
/>
<h1 className="self-center ml-5 font-medium text-greyscaleDark">DOCS</h1>
</a>
</Link>
</>
)}
{selectedMenuSlug && (
<button
className="ml-2 h-8 grid grid-flow-col gap-2 items-center justify-center cursor-pointer text-greyscaleDark"
aria-label="Go back to main menu"
onClick={clearMenuSelection}
>
<ArrowLeftIcon className="h-4 w-4" aria-hidden="true" />{' '}
<span className="font-medium text-base-">{selectedMenuName}</span>
</button>
)}
{/* Placeholder for making logo appear correctly in the middle */}
<div className="w-8 h-8" />
</div>
<div className="flex flex-col py-6 mt-4 border-divide border-t border-b">
{!selectedMenuSlug && (
<ul className="flex flex-col font-medium text-greyscaleDark text-base- font-display space-y-4 text-left px-4">
<li
className={clsx(
'cursor-pointer text-base- hover:text-greyscaleDark transition-colors duration-200 text-left ',
router.query.category === 'get-started' && 'text-greyscaleDark'
)}
>
<Link href="/get-started" passHref>
<a
className="block"
onClick={(event) => handleMenuSelect(event, 'get-started', 'Get Started')}
>
Get Started
</a>
</Link>
</li>
<li
className={clsx(
'cursor-pointer text-base- hover:text-greyscaleDark transition-colors duration-200 text-left',
router.query.category === 'platform' && 'text-greyscaleDark'
)}
>
<Link href="/platform">
<a
className="block"
onClick={(event) => handleMenuSelect(event, 'platform', 'Platform')}
>
Platform
</a>
</Link>
</li>
<li
className={clsx(
'cursor-pointer text-base- hover:text-greyscaleDark transition-colors duration-200',
router.query.category === 'reference' && 'text-greyscaleDark'
)}
>
<Link href="/reference">
<a
className="block"
onClick={(event) => handleMenuSelect(event, 'reference', 'Reference')}
>
Reference
</a>
</Link>
</li>
</ul>
)}
{selectedMenuSlug && (
<Nav
category={selectedMenuSlug}
categoryTitle={selectedMenuName}
convolutedNav={getConvolutedNavByCategory(selectedMenuSlug)}
onMenuSelected={onClose}
/>
)}
</div>
</div>
<div className="sm:flex self-center py-2">
<Button
className="self-center"
variant="primary"
href="https://app.nhost.io"
Component="a"
target="_blank"
rel="noreferrer"
type={null}
>
Go to Nhost
</Button>
</div>
</div>
)
}

View File

@@ -1,42 +0,0 @@
import Text from '@/components/ui/Text/Text'
import createKebabCase from '@/utils/createKebabCase'
import clsx from 'clsx'
import { useRouter } from 'next/dist/client/router'
import Link from 'next/link'
import React from 'react'
export function HeadingsNavigation(props) {
const {
query: { category, subcategory, post }
} = useRouter()
return (
<div className="hidden xl:flex flex-col mt-10 sticky top-20 w-full h-full pb-12 pl-4">
<Text className="font-medium" color="greyscaleDark" size="normal">
On this page
</Text>
<ul className="space-y-2 mt-2 pl-1">
{props.headings.map((heading) => {
return (
<Link
passHref
key={heading.name}
href={`/${category}/${subcategory}/${post}#${createKebabCase(heading.name)}`}
>
<li
className={clsx(
'text-blue hover:text-darkBlue transition-all duration-300 cursor-pointer hover:translate-x-0.5 transform',
heading.depth === 1 && 'text-sm font-medium',
heading.depth === 2 && 'pl-3 text-sm font-normal',
heading.depth === 3 && 'pl-7 text-xs font-normal'
)}
>
{heading.name}
</li>
</Link>
)
})}
</ul>
</div>
)
}

View File

@@ -1,75 +0,0 @@
import { lightNhostTheme } from '@/data/lightTheme'
import { useState } from 'react'
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'
import Check from '../icons/Check'
import Copy from '../icons/Copy'
// @ts-ignore -> add to types
// @ts-ignore -> add to types
SyntaxHighlighter.registerLanguage('js', js)
// TODO highlight JSX
SyntaxHighlighter.registerLanguage('jsx', js)
export interface CodeEditorProps {
code: string
fileName: string
className: string
fixed: boolean
gradient: boolean
deploy: boolean
url?: string
children: any
}
const CodeEditor = (props: CodeEditorProps) => {
const { children, url } = props
const [copied, setCopied] = useState(false)
return (
<div className="relative min-w-full pb-0 my-4 rounded-md">
<div className="absolute right-0">
<button
className="ml-1.5 self-center inline-block cursor-pointer rounded-md mt-2 mr-2"
onClick={() => {
navigator.clipboard.writeText(children).catch((e) => {
// eslint-disable-next-line no-console
console.log(e)
})
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 1000)
}}
>
{/* <Tooltip text={"Copied!"}> */}
{copied ? (
<Check className="w-3.5 h-3.5 mr-0.5 text-greenDark transition-colors self-center" />
) : (
<Copy className="w-4 h-4 text-gray-500 transition-colors hover:text-gray-900" />
)}
{/* </Tooltip> */}
</button>
</div>
<SyntaxHighlighter
style={lightNhostTheme}
wrapLongLines={true}
wrapLines={true}
lineProps={{
style: { wordBreak: 'break-all', whiteSpace: 'pre-wrap' }
}}
customStyle={{
paddingLeft: '12px',
fontSize: '13px'
}}
className="pt-2 rounded-md"
showLineNumbers={false}
>
{children}
</SyntaxHighlighter>
</div>
)
}
export default CodeEditor

View File

@@ -1,156 +0,0 @@
import AnchorLink, { AnchorLinkProps } from '@/components/AnchorLink'
import CodeComponent, { CodeEditorProps } from '@/components/MDX/CodeComponent'
import Text, { TextProps } from '@/components/ui/Text'
import clsx from 'clsx'
import Image from 'next/image'
import Link from 'next/link'
import React, { DetailedHTMLProps, HTMLProps, PropsWithChildren } from 'react'
import Command from '../Command'
import Divider from '../Divider'
import { Swagger } from '../Swagger'
function Note({ children }: PropsWithChildren<unknown>) {
return (
<div className="px-5 py-5 my-5 space-y-2 text-white rounded-md bg-verydark">
<Text className="text-white">Note</Text>
<Text className="text-white">{children}</Text>
</div>
)
}
function Video({
src,
...props
}: DetailedHTMLProps<HTMLProps<HTMLSourceElement>, HTMLSourceElement>) {
return (
<div className="flex justify-center mx-10 my-8">
<video width="800" controls>
<source src={src} type="video/mp4" {...props} />
</video>
</div>
)
}
const CustomLink = ({
className,
children,
href,
...props
}: DetailedHTMLProps<HTMLProps<HTMLAnchorElement>, HTMLAnchorElement>) => {
const isInternalLink = href && ['./', '../', '/', '#'].some((symbol) => href.startsWith(symbol))
if (isInternalLink) {
return (
<Link href={href} passHref>
<a className={clsx('font-medium text-blue', className)} {...props}>
{children}
</a>
</Link>
)
}
return (
<a
target="_blank"
className={clsx('font-medium text-blue', className)}
rel="noopener noreferrer"
href={href}
{...props}
>
{children}
</a>
)
}
const components = {
img: (props: DetailedHTMLProps<HTMLProps<HTMLImageElement>, HTMLImageElement>) => {
return (
<span className="block mx-10 my-10 ">
<img src={props.src} alt={props.alt} className="mx-auto mt-2" />
</span>
)
},
Video,
Image,
Text,
Note,
code: (props: CodeEditorProps) => {
if (props.className && props.className.includes('language')) {
return <CodeComponent {...props} />
} else {
return <Command>{props.children}</Command>
}
},
Divider,
a: CustomLink,
h1: (props: AnchorLinkProps) => {
return (
<>
<Divider />
<AnchorLink {...props} className="text-3xl cursor-pointer md:text-4xl" />
</>
)
},
h2: (props: AnchorLinkProps) => {
return (
<div className="mt-10">
<AnchorLink {...props} className="cursor-pointer text-lg sm:text-xl md:text-2.5xl" />
</div>
)
},
h3: (props: AnchorLinkProps) => {
return (
<div className="mt-8">
<AnchorLink {...props} className="text-lg cursor-pointer" />
</div>
)
},
h4: (props: AnchorLinkProps) => {
return (
<div className="mt-4">
<AnchorLink {...props} className="font-bold cursor-pointer text-base-" />
</div>
)
},
p: (props: TextProps) => {
return (
<Text
variant="body"
size="small"
color="dark"
className="my-2 antialiased leading-6"
{...props}
/>
)
},
th: ({
className,
...props
}: DetailedHTMLProps<HTMLProps<HTMLTableCellElement>, HTMLTableCellElement>) => {
return <th className={clsx('font-display', className)} {...props} />
},
td: ({
className,
...props
}: DetailedHTMLProps<HTMLProps<HTMLTableCellElement>, HTMLTableCellElement>) => {
return <td className={clsx('font-display', className)} {...props} />
},
Swagger,
Mermaid: ({ chart }) => {
const [html, setHtml] = React.useState('')
React.useEffect(() => {
const start = async () => {
const mermaid = (await import('mermaid')).default
mermaid.mermaidAPI.render(uuid(), chart, (svgCode) => setHtml(svgCode))
}
start()
}, [chart])
return chart ? <div dangerouslySetInnerHTML={{ __html: html }} /> : null
}
}
let currentId = 0
const uuid = () => `mermaid-${(currentId++).toString()}`
export default components

View File

@@ -1,3 +0,0 @@
export function Main({ children }) {
return <div className="flex flex-col w-full lg:min-w-body lg:w-body">{children}</div>
}

View File

@@ -1,130 +0,0 @@
import Text from '@/components/ui/Text'
import clsx from 'clsx'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { ParsedUrlQuery } from 'querystring'
import React, { MouseEvent } from 'react'
import { fixTitle } from '../utils/fixTitle'
import { NavItem } from './NavDataContext'
export type NavProps = {
/**
* Class name to apply to the wrapper element.
*/
className?: string
/**
* Category slug.
*/
category: string
/**
* The category title.
*/
categoryTitle: string
/**
* Convoluted navigation.
*/
convolutedNav: NavItem[]
/**
* Function to be called when a menu item is selected.
*/
onMenuSelected?: (event?: MouseEvent<HTMLAnchorElement, MouseEvent>) => void
}
export function Nav({ className, onMenuSelected, ...props }: NavProps) {
const router = useRouter()
return (
<div className={clsx('lg:min-w-nav lg:w-nav flex-col space-y-5 antialiased mt-1', className)}>
<div>
<ul>
<li
className={clsx(
'transition duration-300 ease-in-out rounded-md hover:text-black hover:bg-veryLightGray',
router.query.category === props.category &&
!router.query.subcategory &&
!router.query.post &&
'bg-veryLightGray'
)}
>
<Link href={`/${props.category}`} passHref>
<Text
variant="a"
color="greyscaleDark"
size="normal"
className={clsx(
'block py-1.5 px-3 transition-colors duration-300 ease-in-out text-greyscaleDark hover:text-dark subpixel-antialiased',
'font-medium'
)}
onClick={onMenuSelected}
>
{props.categoryTitle}
</Text>
</Link>
</li>
</ul>
</div>
{props.convolutedNav.map((elem) => {
const parentCategory = props.category.replace(' ', '-')
return (
<div key={elem.category}>
<Link href={`/${parentCategory}/${elem.category}/`} passHref>
<Text
variant="a"
color="greyscaleGrey"
size="normal"
className="block px-3 py-px font-medium capitalize"
onClick={onMenuSelected}
>
{/* Split */}
{fixTitle(elem)}
</Text>
</Link>
<ul className="mt-1 space-y-1 ">
{elem.posts.map((post) => {
const pathToLink =
post.fileName != 'index'
? `/${parentCategory}/${elem.category}/${post.fileName}`
: `/${parentCategory}/${elem.category}`
const shouldHighlight =
router.query.subcategory === elem.category && router.query.post === post.fileName
const shouldHighlightSubcategories =
!router.query.post &&
post.fileName === 'index' &&
elem.category === router.query.subcategory
return (
<li
className={clsx(
'transition duration-300 ease-in-out rounded-md hover:text-black hover:bg-veryLightGray',
(shouldHighlight || shouldHighlightSubcategories) && 'bg-veryLightGray'
)}
key={pathToLink}
>
<Link href={pathToLink} passHref>
<Text
variant="a"
color="greyscaleDark"
size="normal"
className={clsx(
'py-1.5 px-3 block transition-colors duration-300 ease-in-out text-greyscaleDark hover:text-dark subpixel-antialiased block',
(shouldHighlight || shouldHighlightSubcategories) && 'font-medium'
)}
onClick={onMenuSelected}
>
{post.title}
</Text>
</Link>
</li>
)
})}
</ul>
</div>
)
})}
</div>
)
}

View File

@@ -1,85 +0,0 @@
import { ParsedUrlQuery } from 'querystring'
import { createContext, PropsWithChildren, useContext } from 'react'
export type Post = {
/**
* Title of the post.
*/
title: string
/**
* File name where the post is located.
*/
fileName: string
/**
* Order of posts.
*/
order: string[]
}
export type NavItem = {
/**
* Slug of the category.
*/
category: string
/**
* List of posts in the category.
*/
posts: Post[]
}
export type NavDataContextProps = {
/**
* Category slug.
*/
category: string
/**
* The category title.
*/
categoryTitle: string
/**
* Convoluted navigation.
*/
convolutedNav: NavItem[]
/**
* Available menu items for all categories.
*/
availableCategoryMenus: {
/**
* Slug of the category.
*/
slug: string
/**
* Menu items of the category.
*/
items: NavItem[]
}[]
}
export const NavDataContext = createContext<NavDataContextProps>(null)
export function NavDataProvider({ children, ...props }: PropsWithChildren<NavDataContextProps>) {
return <NavDataContext.Provider value={props}>{children}</NavDataContext.Provider>
}
export function useNavData() {
const context = useContext(NavDataContext)
if (!context) {
throw new Error(`"useNavData" must be used within a "NavDataProvider"`)
}
/**
* Returns all of the navigation items for the specified category.
*
* @param slug Slug of the category.
* @returns All of the navigation items for the specified category.
*/
function getConvolutedNavByCategory(slug: string) {
return (
context.availableCategoryMenus.find(({ slug: category }) => category === slug)?.items ||
context.convolutedNav
)
}
return { getConvolutedNavByCategory, ...context }
}

View File

@@ -1,47 +0,0 @@
import React from 'react'
import AnchorLink from './AnchorLink'
import CustomLink from './CustomLink'
import createKebabCase from '../utils/createKebabCase'
import Text from '@/components/ui/Text'
export default function Nav({ headings }: { headings: any }) {
return (
<div className="flex flex-col space-y-5 mt-9">
{headings.map((heading, index) => {
return (
<NavLink
category={heading.category}
post={heading.post}
headings={heading.content}
key={heading.category + index}
/>
)
})}
</div>
)
}
function NavLink({ category, headings, post }) {
const href = `/${category}/${post.toLowerCase()}`
return (
<div className="mt-10 font-display" key={category}>
<CustomLink href={href} activeClassName="active" key={category}>
<Text variant="body" size="small" className="capitalize cursor-pointer text-grayscale">
{post.split('-').join(' ')}
</Text>
</CustomLink>
<ul className="space-y-1">
{headings.map((heading: { value: string }) => {
return (
<li className="py-1 capitalize rounded-sm" key={heading.value}>
<AnchorLink
id={`/${category}/${post.toLowerCase()}#${createKebabCase(heading.value)}`}
>{`/${heading.value}`}</AnchorLink>
</li>
)
})}
</ul>
</div>
)
}

View File

@@ -1,121 +0,0 @@
import axios from 'axios'
import React, { useEffect } from 'react'
import { useState } from 'react'
import Input from './ui/Input/Input'
import Loading from './ui/Loading'
function NewsletterForm(props) {
return (
<div className="flex flex-row w-64 mt-5">
<form
className="grid grid-flow-row sm:grid-flow-col gap-4"
onSubmit={(e) => props.subscribe(e)}
>
<Input
color="dark"
placeholder="Email address"
value={props.email}
onChange={props.setEmail}
type="email"
/>
<button
className="btn-subscribe font-display text-greyscaleDark font-medium cursor-pointer"
disabled={!props.email}
>
{!props.loading ? 'Subscribe' : <Loading />}
</button>
</form>
</div>
)
}
function NewsletterError({ errorMessage, retry }) {
const formattedError = errorMessage.includes('already a list member')
? errorMessage.split('.').slice(0, 2).join('.')
: errorMessage
return (
<div className="grid grid-flow-row md:grid-flow-col gap-4 mt-5">
<p className="text-white font-normal text-sm mt-2.5">{formattedError}.</p>
<button
className="btn-subscribe font-display text-greyscaleDark font-medium cursor-pointer"
onClick={() => {
retry()
}}
>
Try again
</button>
</div>
)
}
export function Newsletter() {
const [email, setEmail] = useState('')
const [error, setError] = useState('')
const [success, setSuccess] = useState('')
const [loading, setLoading] = useState(false)
const handleSubmit = async function (e) {
e.preventDefault()
setLoading(true)
try {
const res = await axios.post('/api/add-email-to-newsletter', {
email
})
if (!res.data.success) {
setError(res.data.message)
return
}
setSuccess(res.data.message)
} catch (error) {
setError(
error.message ||
"We've encountered an error while subscribing you. Try again in a few seconds"
)
} finally {
setEmail('')
setLoading(false)
}
}
useEffect(() => {
if (success) {
let id = setInterval(() => {
setSuccess('')
}, 5000)
return () => clearInterval(id)
}
}, [success])
return (
<div className="font-display flex flex-col mt-16">
<div className="md:px-0 w-full mx-auto">
<h1 className="font-medium text-gray-700 uppercase">newsletter</h1>
<p className="text-white font-normal text-sm+ mt-2.5">
Platform updates and news on web and mobile development.
</p>
{error ? (
<NewsletterError errorMessage={error} retry={() => setError('')} />
) : !success ? (
<NewsletterForm
email={email}
setEmail={setEmail}
subscribe={handleSubmit}
loading={loading}
/>
) : (
<NewsletterSuccess success={success} />
)}
</div>
</div>
)
}
function NewsletterSuccess({ success }) {
return (
<div className="flex flex-row mt-5">
<p className="text-white font-normal text-sm mt-2.5">{success}</p>
</div>
)
}

View File

@@ -1,32 +0,0 @@
import Text from '@/components/ui/Text'
import React from 'react'
import Github from '@/components/icons/Github'
import { DOCS_GITHUB_ENDPOINT } from '@/utils/constants'
export function PostMetadata(props) {
return (
<div className="mt-3 flex flex-row border-t pt-6 place-content-between px-3">
<div className="flex flex-row">
<Github className="text-blue" />
<a
className="text-blue text-xs ml-2 self-center"
href={`${DOCS_GITHUB_ENDPOINT}${props.category}/${props.subcategory}/${props.post}.mdx`}
target="_blank"
rel="noreferrer"
>
Edit this page on GitHub
</a>
</div>
<div>
{props.frontmatter.updatedAt ? (
<div className="flex">
<Text size="tiny">Last updated on {props.frontmatter.updatedAt}</Text>
</div>
) : (
''
)}
</div>
</div>
)
}

View File

@@ -1,52 +0,0 @@
import ArrowLeft from '@/components/icons/ArrowLeft'
import ArrowRight from '@/components/icons/ArrowRight'
import Text from '@/components/ui/Text/Text'
import { orderTwo } from '@/lib/order'
import { useRouter } from 'next/dist/client/router'
import Link from 'next/link'
import React from 'react'
export function SubNavigation({ category, subcategory, post, convolutedNav }) {
const router = useRouter()
const indexOfSubcategory = Object.keys(orderTwo[category]).indexOf(subcategory)
const indexOfPreviousPost = orderTwo[category][subcategory].indexOf(post) - 1
let indexOfCurrentPost = orderTwo[category][subcategory].indexOf(post)
const previousPost = orderTwo[category][subcategory][indexOfCurrentPost - 1]
let indexOfNextPost = orderTwo[category][subcategory].indexOf(post) + 1
if (!router.query.post) indexOfCurrentPost++ && indexOfNextPost++
const nextPost = orderTwo[category][subcategory][indexOfCurrentPost + 1]
const pathLink = `/${category}/${subcategory}/${previousPost === 'index' ? '' : previousPost}`
return (
<div className="flex flex-row mt-10 place-content-between px-2 antialiased">
<Link href={pathLink} passHref>
<Text variant="a" color="blue" className="font-medium cursor-pointer" size="small">
{indexOfCurrentPost === 0 || !router.query.post ? (
<></>
) : (
<div className="flex flex-row self-center hover:-translate-x-1 transform transition-transform duration-500">
<ArrowLeft className="self-center mr-1" />
{convolutedNav[indexOfSubcategory].posts[indexOfPreviousPost].title}
</div>
)}
</Text>
</Link>
<Link href={`/${category}/${subcategory}/${nextPost}`} passHref>
<Text variant="a" size="small" color="blue" className="font-medium cursor-pointer">
{nextPost ? (
<div className="flex flex-row self-center hover:translate-x-1 transform transition-transform duration-500">
{convolutedNav[indexOfSubcategory].posts[indexOfNextPost].title}
<ArrowRight className="self-center ml-1" />
</div>
) : (
<></>
)}
</Text>
</Link>
</div>
)
}

View File

@@ -1,29 +0,0 @@
import SwaggerUI from 'swagger-ui-react'
import 'swagger-ui-react/swagger-ui.css'
const OperationsLayout = (props) => {
const { getComponent } = props
const Operations = getComponent('operations', true)
let SvgAssets = getComponent('SvgAssets')
return (
<div className="swagger-ui">
<SvgAssets />
<Operations />
</div>
)
}
const OperationsLayoutPlugin = () => ({
components: {
OperationsLayout
}
})
export const Swagger: React.FC<{ spec: string }> = ({ spec }) => (
<SwaggerUI
url={`/openapi/${spec}`}
plugins={[OperationsLayoutPlugin]}
layout="OperationsLayout"
supportedSubmitMethods={[]}
/>
)

View File

@@ -1,25 +0,0 @@
export function Tooltip({ text, children, position = '-mx-20', color = '' }) {
return (
<div className="relative has-tooltip">
{children}
<span
className={`z-50 px-1.5 py-0.5 text-sm bg-verydark -my-12 -mx-9 text-white rounded-sm shadow-2xl border tooltip font-medium`}
>
{text}
</span>
<svg
className="absolute z-50 w-3 h-2 text-verydark transform tooltip -top-2 right-0.5"
x="0px"
y="0px"
viewBox="0 0 255 255"
xmlSpace="preserve"
>
<polygon
className="border border-white fill-current text-lightbrand"
points="0,0 127.5,127.5 255,0"
/>
</svg>
</div>
)
}

View File

@@ -1,46 +0,0 @@
import CaretRight from '@/components/icons/CaretRight'
import Text from '@/components/ui/Text/Text'
import Link from 'next/link'
import React from 'react'
export function TopNavigation(props) {
const category = props.category.split('-').join(' ')
function uppercaseEdgeCases(subcategory) {
switch (subcategory) {
case 'sdk':
return 'SDK'
case 'cli':
return 'CLI'
default:
return subcategory
}
}
const subcategory = props.subcategory.split('-').join(' ')
return (
<div className="flex flex-row w-full">
<Link href={`/${props.category}`} passHref>
<Text
variant="a"
color="grey"
className="self-center font-medium capitalize transition-colors duration-200 cursor-pointer hover:text-greyscaleDark"
size="normal"
>
{category}
</Text>
</Link>
<CaretRight className="self-center text-greyscaleGrey mx-1" />
<Link href={`/${props.category}/${props.subcategory}`} passHref>
<Text
color="grey"
className="self-center font-medium capitalize transition-colors duration-200 cursor-pointer hover:text-greyscaleDark"
size="normal"
>
{uppercaseEdgeCases(subcategory)}
</Text>
</Link>
</div>
)
}

View File

@@ -1,16 +0,0 @@
import * as React from 'react'
function ArrowLeft(props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>) {
return (
<svg width={16} height={16} fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
d="M13.5 8h-11M7 3.5L2.5 8 7 12.5"
stroke="#0052CD"
strokeWidth={1.5}
strokeLinejoin="round"
/>
</svg>
)
}
export default ArrowLeft

View File

@@ -1,16 +0,0 @@
import * as React from 'react'
function ArrowRight(props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>) {
return (
<svg width={16} height={16} fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
d="M2.5 8h11M9 3.5L13.5 8 9 12.5"
stroke="#0052CD"
strokeWidth={1.5}
strokeLinejoin="round"
/>
</svg>
)
}
export default ArrowRight

View File

@@ -1,11 +0,0 @@
import * as React from 'react'
function CaretRight(props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>) {
return (
<svg width={16} height={16} fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path d="M6 3l5 5-5 5" stroke="currentColor" strokeWidth={1.5} strokeLinejoin="round" />
</svg>
)
}
export default CaretRight

View File

@@ -1,11 +0,0 @@
import * as React from 'react'
function Check(props: any) {
return (
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path d="M13.5 4.5l-7 7L3 8" stroke="currentColor" strokeWidth={2} strokeLinejoin="round" />
</svg>
)
}
export default Check

View File

@@ -1,11 +0,0 @@
import * as React from 'react'
function Check2(props: any) {
return (
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path d="M27 9L13 23l-7-7" stroke="#0D3777" strokeWidth={2} strokeLinejoin="round" />
</svg>
)
}
export default Check2

View File

@@ -1,20 +0,0 @@
const Copy = ({ ...props }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
{...props}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
/>
</svg>
)
}
export default Copy

View File

@@ -1,22 +0,0 @@
const Github = ({ ...props }) => {
return (
<div className="cursor-pointer">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" />
</svg>
</div>
)
}
export default Github

View File

@@ -1,23 +0,0 @@
import * as React from 'react'
function GithubIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
width={14}
height={14}
viewBox="0 0 14 14"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7 0a7 7 0 00-2.213 13.642c.35.065.478-.152.478-.337 0-.166-.006-.607-.01-1.19-1.947.422-2.357-.94-2.357-.94-.319-.808-.778-1.023-.778-1.023-.635-.434.048-.426.048-.426.703.05 1.073.722 1.073.722.624 1.07 1.638.76 2.037.581.063-.452.244-.76.444-.935-1.554-.177-3.188-.778-3.188-3.46 0-.764.273-1.39.72-1.878-.072-.177-.312-.89.07-1.853 0 0 .586-.188 1.924.718A6.705 6.705 0 017 3.385c.595.003 1.194.08 1.753.236 1.336-.906 1.923-.718 1.923-.718.382.964.142 1.676.07 1.853a2.7 2.7 0 01.72 1.878c0 2.69-1.638 3.281-3.197 3.454.251.216.475.644.475 1.297 0 .935-.009 1.69-.009 1.92 0 .187.127.405.482.337A7 7 0 007 0z"
fill="currentColor"
/>
</svg>
)
}
export default GithubIcon

View File

@@ -1,20 +0,0 @@
const Help = ({ ...props }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
{...props}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
)
}
export default Help

View File

@@ -1,36 +0,0 @@
import * as React from 'react'
function Logo(props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 95 32" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<g clipPath="url(#prefix__clip0)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M50.657 15.218h4.792v-3.801h2.535v9.752h-2.535v-3.802h-4.792v3.802H48.21v-9.752h2.446v3.801zm16.996-3.801H63.74c-1.084 0-1.744.204-2.243.703-.497.496-.688 1.126-.688 2.238v3.874c0 1.112.19 1.74.688 2.238.497.498 1.157.703 2.243.703h3.913c1.084 0 1.744-.205 2.243-.703.5-.496.688-1.126.688-2.238v-3.874c0-1.112-.19-1.74-.688-2.239-.5-.498-1.159-.702-2.243-.702zm.483 6.872c0 .57-.19.73-.879.73h-3.121c-.688 0-.88-.16-.88-.73v-3.992c0-.571.192-.731.88-.731h3.121c.705 0 .88.145.88.73v3.993zm8.512-2.97h3.501c1.084 0 1.758.205 2.243.703.439.44.688 1.155.688 1.93v.586c0 .776-.25 1.476-.688 1.93-.485.498-1.145.703-2.243.703h-6.681v-2.15h6.271c.688 0 .88-.16.88-.73v-.292c0-.571-.192-.731-.88-.731h-3.5c-1.087 0-1.76-.207-2.243-.703-.439-.44-.689-1.154-.689-1.93v-.585c0-.776.248-1.477.689-1.93.485-.499 1.142-.703 2.242-.703h6.333v2.149h-5.923c-.688 0-.879.16-.879.73v.292c0 .572.191.732.88.732zm7.983-1.753v-2.15h9.963v2.15h-3.75v7.603h-2.448v-7.603H84.63z"
fill="#21324B"
/>
<path
d="M42.355 11.34h-3.913c-1.084 0-1.744.204-2.243.703-.497.496-.688 1.126-.688 2.236v6.888h2.447V14.22c0-.57.191-.73.88-.73h3.121c.704 0 .879.146.879.73v6.948h2.448V14.28c0-1.112-.191-1.74-.689-2.236-.497-.5-1.156-.705-2.242-.705z"
fill="#0052CD"
/>
<g clipPath="url(#prefix__clip1)">
<path
d="M27.208 6.858L16.055.43a3.268 3.268 0 00-3.246 0 3.245 3.245 0 00-1.621 2.803v.839l-.727-.42a3.268 3.268 0 00-3.246 0A3.246 3.246 0 005.594 6.46v.838l-.727-.419a3.268 3.268 0 00-3.245 0A3.246 3.246 0 000 9.683v20.136a1.526 1.526 0 002.47 1.195L8 26.66l8.53 4.914a1.548 1.548 0 001.526 0c.47-.272.763-.776.763-1.319V18.14a5.595 5.595 0 00-2.797-4.835l-2.797-1.612V3.236a1.21 1.21 0 011.815-1.045l11.153 6.425a3.562 3.562 0 011.78 3.076v15.089c0 .43-.232.83-.605 1.045l-2.955 1.703V14.914a5.595 5.595 0 00-2.797-4.834L14.75 6.125v2.343l5.849 3.37a3.559 3.559 0 011.78 3.076v15.492c0 .54.292 1.047.763 1.319a1.549 1.549 0 001.526 0l3.719-2.143c1-.577 1.622-1.65 1.622-2.805V11.688a5.609 5.609 0 00-2.801-4.83zM15 15.062a3.559 3.559 0 011.78 3.077v11.24L9.718 25.31l2.267-1.782a3.214 3.214 0 001.236-2.542V14.04l1.78 1.023zm-3.813-2.197v8.117c0 .373-.169.72-.461.948l-8.693 6.84V9.68a1.209 1.209 0 011.814-1.045L5.594 9.64v14.39l2.033-1.6V6.458a1.209 1.209 0 011.815-1.045l1.745 1.004v4.102L9.155 9.347v2.345l2.034 1.173z"
fill="#0052CD"
/>
</g>
</g>
<defs>
<clipPath id="prefix__clip0">
<path fill="#fff" d="M0 0h94.582v32H0z" />
</clipPath>
<clipPath id="prefix__clip1">
<path fill="#fff" d="M0 0h30.009v31.927H0z" />
</clipPath>
</defs>
</svg>
)
}
export default Logo

View File

@@ -1,15 +0,0 @@
const Permalink = ({ ...props }) => {
return (
<svg fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
d="M5.878 10.12l4.243-4.242M9.06 11.182L7.293 12.95A3 3 0 013.05 8.707l1.768-1.768M11.182 9.06l1.768-1.768A3 3 0 008.707 3.05L6.939 4.818"
stroke="#21324B"
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Permalink

View File

@@ -1,21 +0,0 @@
import * as React from 'react'
function Vector(props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>) {
return (
<svg
width={260}
height={117}
viewBox="0 0 260 117"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M35.5 1h1V0h-1v1zM254 87l-5.773 10h11.546L254 87zM.5 2h2.188V0H.5v2zm6.563 0h4.375V0H7.061v2zm8.75 0h4.374V0h-4.375v2zm8.75 0h4.375V0h-4.375v2zm8.75 0H35.5V0h-2.188v2zM34.5 1v1.982h2V1h-2zm0 5.946v3.965h2V6.946h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.928v3.964h2v-3.964h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.928v3.965h2v-3.965h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.928v3.965h2v-3.965h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.928v3.964h2v-3.964h-2zm0 7.929v3.964h2v-3.964h-2zm0 7.928v3.965h2v-3.965h-2zm0 7.929V112h2v-1.982h-2zm0 1.982c0 .676.135 1.323.38 1.914l1.847-.766A2.985 2.985 0 0136.5 112h-2zm3.086 4.62c.59.245 1.238.38 1.914.38v-2a2.99 2.99 0 01-1.148-.227l-.766 1.847zm1.914.38h2.024v-2H39.5v2zm6.072 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.097 0h4.048v-2H69.86v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0H90.1v-2h-4.048v2zm8.096 0h4.048v-2H94.15v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.097 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.049v-2h-4.049v2zm8.097 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.049v-2h-4.049v2zm8.097 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0h4.048v-2h-4.048v2zm8.096 0H250v-2h-2.024v2zm2.024 0c.676 0 1.323-.135 1.914-.38l-.766-1.847A2.987 2.987 0 01250 115v2zm4.62-3.086c.245-.591.38-1.238.38-1.914h-2c0 .409-.081.796-.227 1.148l1.847.766zM255 112v-2.083h-2V112h2zm0-6.25v-4.167h-2v4.167h2zm0-8.333V93.25h-2v4.167h2z"
fill="#C2CAD6"
/>
</svg>
)
}
export default Vector

View File

@@ -1,97 +0,0 @@
.root {
@apply font-display flex px-2 py-1.6;
justify-content: center;
align-items: center;
line-height: 22px;
font-size: 15px;
}
.primary {
@apply bg-blue font-display flex font-medium text-white;
font-size: 15px;
border-radius: 4px;
line-height: 22px;
}
.danger {
@apply py-2.5 px-2.5 text-red font-display font-medium;
height: 36px;
border-radius: 4px;
justify-content: center;
align-items: center;
display: flex;
flex-direction: row;
border: 1px solid #c2cad6;
}
.blue {
@apply text-blue;
}
.red {
@apply text-red;
}
.root:focus {
@apply outline-none;
}
.root[data-active] {
@apply bg-accent-6;
}
.loading {
@apply bg-accent-1 text-accent-3 border-accent-2 cursor-not-allowed;
}
.secondary {
@apply font-display text-greyscaleDark bg-white;
font-weight: 500;
font-size: 15px;
border: 1px solid #c2cad6;
box-sizing: border-box;
border-radius: 4px;
}
.menu {
@apply font-display text-greyscaleDark cursor-pointer;
font-family: Inter;
font-style: normal;
font-weight: 500;
font-size: 15px;
}
.dark {
@apply font-medium text-white;
background: #21324b;
border-radius: 4px;
}
.dark .disabled {
@apply font-medium text-white;
background: #21324b;
border-radius: 4px;
}
.secondary .disabled {
@apply font-medium;
color: rgba(9, 34, 72, 0.4);
}
.disabled,
.disabled:hover {
@apply text-gray-400 cursor-not-allowed;
border-radius: 4px;
}
.small {
width: 51px;
height: 24px;
font-family: Inter;
font-style: normal;
font-weight: 500;
font-size: 12px;
line-height: 16px;
}
.transparent {
@apply px-0 py-1 bg-transparent border-0;
}
.border {
@apply px-2 py-1.5;
border: 1px solid #c2cad6;
border-radius: 4px;
}

View File

@@ -1,88 +0,0 @@
import cn from 'classnames'
import React, { ButtonHTMLAttributes, forwardRef, JSXElementConstructor, useRef } from 'react'
import mergeRefs from 'react-merge-refs'
import s from './Button.module.css'
// import Loading from "../components/ui/Loading";
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
href?: string
className?: string
variant?: 'primary' | 'dark' | 'secondary' | 'menu' | 'danger'
color?: 'blue' | 'red'
active?: boolean
type?: 'submit' | 'reset' | 'button'
Component?: string | JSXElementConstructor<any>
width?: string | number
loading?: boolean
disabled?: boolean
small?: boolean
transparent?: boolean
target?: string
rel?: string
onClick?: any
border?: boolean
}
// eslint-disable-next-line react/display-name
export const Button: React.FC<ButtonProps> = forwardRef((props, buttonRef) => {
const {
className,
variant,
children,
active,
width,
small,
href,
color,
border,
loading = false,
disabled = false,
transparent = false,
style = {},
type = 'button',
Component = 'button',
...rest
} = props
const ref = useRef<typeof Component>(null)
const rootClassName = cn(
s.root,
{
[s.primary]: variant === 'primary',
[s.secondary]: variant === 'secondary',
[s.menu]: variant === 'menu',
[s.dark]: variant === 'dark',
[s.danger]: variant === 'danger',
[s.loading]: loading,
[s.disabled]: disabled,
[s.small]: small,
[s.transparent]: transparent,
[s.blue]: color === 'blue',
[s.red]: color === 'red',
[s.border]: border
},
className
)
return (
<Component
aria-pressed={active}
data-variant={variant}
ref={mergeRefs([ref, buttonRef])}
className={rootClassName}
disabled={disabled}
type={type}
href={href}
style={{
width,
...style
}}
{...rest}
>
{children}
</Component>
)
})
export default Button

View File

@@ -1 +0,0 @@
export { default } from './Button'

View File

@@ -1,31 +0,0 @@
.root {
@apply border-input text-dark focus:ring-dark focus:border-dark flex px-2 py-2 text-xs rounded-md shadow-sm;
border: 1px solid #c2cad6;
}
.root:focus {
@apply outline-none;
}
.dark {
flex: none;
width: 247px;
height: 36px;
left: 0px;
top: 0px;
color: white;
/* Translucent white/White light (20) */
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
border: none;
/* Inside Auto Layout */
order: 0;
flex-grow: 1;
}
.disabled,
.disabled:hover {
@apply text-accent-3 cursor-not-allowed;
}

View File

@@ -1,44 +0,0 @@
import cn from 'classnames'
import s from './Input.module.css'
import React, { InputHTMLAttributes } from 'react'
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
className?: string
onChange?: (...args: any[]) => any
disabled?: boolean
}
type Color = 'dark' | 'light'
const Input: React.FC<InputProps> = (props) => {
const { className, children, onChange, color, disabled, placeholder = '', ...rest } = props
const rootClassName = cn(
s.root,
{ [s.disabled]: disabled, [s.dark]: color === 'dark' },
className
)
const handleOnChange = (e: any) => {
if (onChange) {
onChange(e.target.value)
}
return null
}
return (
<input
className={rootClassName}
onChange={handleOnChange}
disabled={disabled}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
placeholder={placeholder}
{...rest}
/>
)
}
export default Input

View File

@@ -1 +0,0 @@
export { default } from './Input'

View File

@@ -1,19 +0,0 @@
import React from 'react'
export default function Loading() {
return (
<svg
className="w-5 h-5 text-dark animate-spin"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
)
}

View File

@@ -1,90 +0,0 @@
.body {
font-family: Inter;
font-style: normal;
}
.dark {
@apply text-dark;
}
.greyscaleDark {
@apply text-greyscaleDark;
}
.white {
@apply text-white;
}
.greyscaleGrey {
@apply text-greyscaleGrey;
}
.grey {
@apply text-grayscale;
}
.red {
@apply text-red;
}
.blue {
@apply text-blue;
}
.heading {
@apply font-display;
}
.pageHeading {
@apply pt-1 pb-4 text-2xl font-bold leading-7 tracking-wide;
}
.a {
font-family: Inter;
font-style: normal;
}
.tiny {
font-size: 12px;
line-height: 16px;
}
.small {
font-size: 15px;
}
.normal {
font-size: 15px;
line-height: 22px;
}
.large {
font-size: 18px;
line-height: 26px;
}
.big {
font-size: 26px;
line-height: 36px;
}
.heading {
font-size: 36px;
line-height: 48px;
}
.subHeading {
font-family: Inter;
font-style: normal;
font-weight: 500;
}
.sectionHeading {
@apply text-lg font-medium font-display;
color: gray;
}
.item {
font-family: Inter;
font-style: normal;
}

View File

@@ -1,123 +0,0 @@
import cn from 'classnames'
import React, {
CSSProperties,
ForwardedRef,
forwardRef,
FunctionComponent,
JSXElementConstructor
} from 'react'
import mergeRefs from 'react-merge-refs'
import s from './Text.module.css'
export interface TextProps {
variant?: Variant
className?: string
style?: CSSProperties
children?: React.ReactNode | any
color?: Color
html?: string
size?: Size
target?: any
rel?: any
href?: string
onClick?: () => any
name?: any
}
type Variant = 'heading' | 'body' | 'pageHeading' | 'sectionHeading' | 'item' | 'subHeading' | 'a'
type Size = 'tiny' | 'small' | 'normal' | 'large' | 'big' | 'heading'
type Color = 'dark' | 'grey' | 'blue' | 'greyscaleDark' | 'greyscaleGrey' | 'red' | 'white'
export const Text: FunctionComponent<TextProps> = forwardRef(function DefaultText(
{
style,
className = '',
variant = 'body',
color,
children,
html,
onClick,
size,
rel,
href,
target,
name
},
ref: ForwardedRef<HTMLElement>
) {
const componentsMap: {
[P in Variant]: React.ComponentType<any> | string
} = {
body: 'div',
heading: 'h1',
pageHeading: 'h1',
sectionHeading: 'h2',
subHeading: 'h3',
item: 'p',
a: 'a'
}
const Component:
| JSXElementConstructor<any>
| React.ReactElement<any>
| React.ComponentType<any>
| string = componentsMap![variant!]
const htmlContentProps = html
? {
dangerouslySetInnerHTML: { __html: html }
}
: {}
const aProps =
variant === 'a'
? {
rel,
href,
target
}
: {}
return (
<Component
ref={ref}
className={cn(
s.root,
{
[s.body]: variant === 'body',
[s.a]: variant === 'a',
[s.heading]: variant === 'heading',
[s.pageHeading]: variant === 'pageHeading',
[s.sectionHeading]: variant === 'sectionHeading',
[s.subHeading]: variant === 'subHeading',
[s.item]: variant === 'item',
[s.dark]: color === 'dark',
[s.greyscaleDark]: color === 'greyscaleDark',
[s.grey]: color === 'grey',
[s.blue]: color === 'blue',
[s.tiny]: size === 'tiny',
[s.small]: size === 'small',
[s.normal]: size === 'normal',
[s.large]: size === 'large',
[s.big]: size === 'big',
[s.heading]: size === 'heading',
[s.greyscaleGrey]: color === 'greyscaleGrey',
[s.red]: color === 'red',
[s.white]: color === 'white'
},
className
)}
onClick={onClick}
style={style}
{...htmlContentProps}
{...aProps}
name={name}
>
{children}
</Component>
)
})
export default Text

View File

@@ -1,2 +0,0 @@
export * from './Text'
export { default } from './Text'

View File

@@ -1,2 +0,0 @@
export * from './Button/Button'
export * from './Text/Text'

View File

@@ -1,6 +0,0 @@
---
title: 'API Reference'
subtitle: 'Hasura Auth'
---
<Swagger spec="hasura-auth.json" />

View File

@@ -1,38 +0,0 @@
---
title: 'Reference'
---
In this section:
### Nhost SDK
- [Overview](/reference/sdk)
- [GraphQL](/reference/sdk/graphql)
- [Authentication](/reference/sdk/authentication)
- [Storage](/reference/sdk/storage)
- [Functions](/reference/sdk/functions)
### React
- [Getting started](./reference/react)
- [Hooks](./reference/react/hooks)
- [Protecting routes](./reference/react/protecting-routes)
- [Apollo GraphQL](./reference/react/apollo)
### Next.js
- [Introduction](./reference/nextjs)
- [Configuration](./reference/nextjs/configuration)
- [Protecting routes](./reference/nextjs/protecting-routes)
### Nhost CLI
- [CLI overview](/reference/cli)
### Hasura Auth
- [Overview](./reference/hasura-auth)
- [Installation](./reference/hasura-auth/installation)
- [Configuration](./reference/hasura-auth/configuration)
- [Environment variables](./reference/hasura-auth/environment-variables)
- [API](./reference/hasura-auth/api-reference)
- [Schema](./reference/hasura-auth/api-reference)

View File

@@ -1,40 +0,0 @@
---
title: 'Protecting routes'
---
Create a `auth-protected.js` file:
```jsx
import { useRouter } from 'next/router'
import { useAuthenticationStatus } from '@nhost/nextjs'
export function authProtected(Comp) {
return function AuthProtected(props) {
const router = useRouter()
const { isLoading, isAuthenticated } = useAuthenticationStatus()
if (isLoading) {
return <div>Loading...</div>
}
if (!isAuthenticated) {
router.push('/login')
return null
}
return <Comp {...props} />
}
}
```
Then wrap the Next.js page with `authProtected` to only allow signed in users to access the page.
```js
import { authProtected } from '<some-path>/auth-protected'
function Index() {
return <div>Only signed in users can access this page.</div>
}
export default authProtected(Index)
```

View File

@@ -1,43 +0,0 @@
---
title: 'Protecting routes'
---
## React Router
You can protect routes by creating an `AuthGate` component when using `@nhost/react` with [React Router](https://reactrouter.com/web/guides/quick-start).
```jsx
import { Redirect } from 'react-router-dom'
import { useAuthenticationStatus } from '@nhost/react'
export function AuthGate(children) {
const { isLoading, isAuthenticated } = useAuthenticationStatus()
if (isLoading) {
return <div>Loading...</div>
}
if (!isAuthenticated) {
return <Redirect to="/login" />
}
return children
}
```
Then, in your React Router, wrap the `AuthGate` component around the routes you want to protect:
```jsx
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/" exact>
<AuthGate> // <--- Use AuthGate component like this
<div>My protected dashboard</div>
</AuthGate>
</Route>
</Switch>
</Router>
```

View File

@@ -1,112 +0,0 @@
export const nhostTheme = {
hljs: {
display: 'block',
background: '#F4F7F9',
color: '#21324B'
},
'hljs-tag': {
color: '#9C73DF'
},
'hljs-keyword': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-selector-tag': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-literal': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-strong': {
color: '#9C73DF'
},
'hljs-name': {
color: '#9C73DF'
},
'hljs-code': {
color: '#66d9ef'
},
'hljs-class .hljs-title': {
color: 'red'
},
'hljs-attribute': {
color: '#bf79db'
},
'hljs-symbol': {
color: '#bf79db'
},
'hljs-regexp': {
color: '#bf79db'
},
'hljs-link': {
color: '#bf79db'
},
'hljs-string': {
color: '#B7A590'
},
'hljs-bullet': {
color: '#B7A590'
},
'hljs-subst': {
color: '#B7A590'
},
'hljs-title': {
color: '#B7A590',
fontWeight: 'bold'
},
'hljs-section': {
color: '#B7A590',
fontWeight: 'bold'
},
'hljs-emphasis': {
color: '#3ECF8E'
},
'hljs-type': {
color: '#3ECF8E',
fontWeight: 'bold'
},
'hljs-built_in': {
color: '#3ECF8E'
},
'hljs-builtin-name': {
color: '#3ECF8E'
},
'hljs-selector-attr': {
color: '#3ECF8E'
},
'hljs-selector-pseudo': {
color: '#3ECF8E'
},
'hljs-addition': {
color: '#3ECF8E'
},
'hljs-variable': {
color: '#3ECF8E'
},
'hljs-template-tag': {
color: '#3ECF8E'
},
'hljs-template-variable': {
color: '#3ECF8E'
},
'hljs-comment': {
color: '#75715e'
},
'hljs-quote': {
color: '#75715e'
},
'hljs-deletion': {
color: '#75715e'
},
'hljs-meta': {
color: '#75715e'
},
'hljs-doctag': {
fontWeight: 'bold'
},
'hljs-selector-id': {
fontWeight: 'bold'
}
}

View File

@@ -1,112 +0,0 @@
export const lightNhostTheme = {
hljs: {
display: 'block',
background: '#F4F7F9',
color: '#21324B'
},
'hljs-tag': {
color: '#9C73DF'
},
'hljs-keyword': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-selector-tag': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-literal': {
color: '#9C73DF',
fontWeight: 'bold'
},
'hljs-strong': {
color: '#9C73DF'
},
'hljs-name': {
color: '#9C73DF'
},
'hljs-code': {
color: '#66d9ef'
},
'hljs-class .hljs-title': {
color: 'red'
},
'hljs-attribute': {
color: '#bf79db'
},
'hljs-symbol': {
color: '#bf79db'
},
'hljs-regexp': {
color: '#bf79db'
},
'hljs-link': {
color: '#bf79db'
},
'hljs-string': {
color: '#B7A590'
},
'hljs-bullet': {
color: '#B7A590'
},
'hljs-subst': {
color: '#B7A590'
},
'hljs-title': {
color: '#B7A590',
fontWeight: 'bold'
},
'hljs-section': {
color: '#B7A590',
fontWeight: 'bold'
},
'hljs-emphasis': {
color: '#3ECF8E'
},
'hljs-type': {
color: '#3ECF8E',
fontWeight: 'bold'
},
'hljs-built_in': {
color: '#3ECF8E'
},
'hljs-builtin-name': {
color: '#3ECF8E'
},
'hljs-selector-attr': {
color: '#3ECF8E'
},
'hljs-selector-pseudo': {
color: '#3ECF8E'
},
'hljs-addition': {
color: '#3ECF8E'
},
'hljs-variable': {
color: '#3ECF8E'
},
'hljs-template-tag': {
color: '#3ECF8E'
},
'hljs-template-variable': {
color: '#3ECF8E'
},
'hljs-comment': {
color: '#75715e'
},
'hljs-quote': {
color: '#75715e'
},
'hljs-deletion': {
color: '#75715e'
},
'hljs-meta': {
color: '#75715e'
},
'hljs-doctag': {
fontWeight: 'bold'
},
'hljs-selector-id': {
fontWeight: 'bold'
}
}

View File

@@ -1,23 +0,0 @@
{
"order": [
{
"id": "get-started",
"name": "get-started",
"description": "get-started",
"pages": [
{
"route": "quickstart",
"display": "Quick Start"
},
{
"route": "app-development",
"display": "App Development"
},
{
"route": "workflow",
"display": "Workflow"
}
]
}
]
}

View File

@@ -1,15 +0,0 @@
export interface Meta {
order: CategoryLink[]
}
export interface CategoryLink {
id: string
name: string
description: string
pages: Page[]
}
interface Page {
route: string
display: string
}

View File

@@ -1,64 +0,0 @@
{
"siteLinks": [
{
"text": "product",
"links": [
{
"name": "Product",
"href": "https://nhost.io/#product"
},
{
"name": "Features",
"href": "https://nhost.io/#features"
},
{
"name": "Pricing",
"href": "https://nhost.io/pricing"
}
]
},
{
"text": "docs",
"links": [
{
"name": "Get Started",
"href": "/get-started"
},
{
"name": "Platform",
"href": "/platform"
},
{
"name": "Reference",
"href": "/reference"
}
]
},
{
"text": "Frameworks",
"links": [
{
"name": "API Reference",
"href": "/reference"
},
{
"name": "JS SDK",
"href": "/reference/sdk"
}
]
},
{
"text": "community",
"links": [
{
"name": "GitHub",
"href": "https://github.com/nhost"
},
{
"name": "Discord",
"href": "https://discord.com/invite/9V7Qb2U"
}
]
}
]
}

View File

@@ -1,8 +0,0 @@
export interface SiteLinks {
siteLinks: SiteLink[]
}
interface SiteLink {
text: string
links: string[]
}

View File

@@ -1,5 +1,6 @@
---
title: 'Authenticate users'
slug: /get-started/authentication
---
You defined `select` permissions for the `public` role in the previous section. You will now add `insert` and `create` permissions for authenticated users to secure your app's GraphQL API with authentication.
@@ -12,7 +13,7 @@ You defined `select` permissions for the `public` role in the previous section.
Manually create a user by going to your app's **Users** tab (top menu) and clicking on **Add User**.
![Add user](/images/quick-start/add-user.gif)
![Add user](/img/quick-start/add-user.gif)
You will now use that newly created user to make authenticated requests to the API.
@@ -23,20 +24,20 @@ You will now use that newly created user to make authenticated requests to the A
Add the following code to sign in the new user and request the list of todos again:
```js
import { NhostClient } from '@nhost/nhost-js'
import { NhostClient } from '@nhost/nhost-js';
const nhost = new NhostClient({
backendUrl: 'https://[app-subdomain].nhost.run'
backendUrl: 'https://[app-subdomain].nhost.run',
})(async () => {
// Sign in user
const signInResponse = await nhost.auth.signIn({
email: 'joe@example.com',
password: 'securepassword'
})
password: 'securepassword',
});
// Handle sign-in error
if (signInResponse.error) {
throw signInResponse.error
throw signInResponse.error;
}
// Get todos
@@ -49,10 +50,10 @@ const nhost = new NhostClient({
is_completed
}
}
`)
`);
console.log(JSON.stringify(todos.data, null, 2))
})()
console.log(JSON.stringify(todos.data, null, 2));
})();
```
Why is the return value `null`? Because when making GraphQL requests as an authenticated user, the `user` role is assumed.
@@ -67,7 +68,7 @@ Why is the return value `null`? Because when making GraphQL requests as an authe
We won't use the `public` role anymore, so let's remove all permission for that role.
![Remove public permissions from Hasura](/images/quick-start/remove-public-permissions.png)
![Remove public permissions from Hasura](/img/quick-start/remove-public-permissions.png)
Now we'll add permissions for the `user` role.
@@ -79,12 +80,12 @@ First, we'll set the **Insert permission**.
A user can only insert `name` because all other columns will be set automatically. More specifically, `user_id` is set to the user's id making the request (`x-hasura-user-id`) and is configured in the `Column presets` section. See the image below.
![User insert permission](/images/quick-start/user-insert-permission.png)
![User insert permission](/img/quick-start/user-insert-permission.png)
### Select permission
For **Select permission**, set a **custom check** so users can only select todos where `user_id` is the same as their user id. In other words: users are only allowed to select their own todos. See the image below.
![User select permission](/images/quick-start/user-select-permission.png)
![User select permission](/img/quick-start/user-select-permission.png)
Now rerun the app. New todos are inserted, and only todos for the user are fetched and displayed. Your backend is successfully secured!

View File

@@ -0,0 +1,4 @@
{
"label": "CLI",
"position": 8
}

View File

@@ -12,9 +12,9 @@ In the previous tutorials, we tested various parts of Nhost, such as:
All changes we did to our database and API happened directly in production of our Nhost app.
Its not ideal for making changes in production because you might break things, which will affect all users of your app.
It's not ideal for making changes in production because you might break things, which will affect all users of your app.
Instead, its recommended to make changes and test your app locally before deploying those changes to production.
Instead, it's recommended to make changes and test your app locally before deploying those changes to production.
To do changes locally, we need to have a complete Nhost app running locally, which the Nhost CLI does.
@@ -26,8 +26,8 @@ The Nhost CLI matches your production application in a local environment, this w
2. Push changes to GitHub.
3. Nhost automatically applies changes to production.
## What youll learn in this guide:
## What you'll learn in this guide:
- Use the Nhost CLI to create a local environment
- Connect a GitHub repository with a Nhost app
- Deploy local changes to production
- Deploy local changes to production

View File

@@ -4,13 +4,13 @@ title: 'Install the CLI'
Install the Nhost CLI using the following command:
```sql
```bash
sudo curl -L https://raw.githubusercontent.com/nhost/cli/main/get.sh | bash
```
Initialize a new Nhost App locally:
```sql
```bash
nhost init -n "nhost-example-app" && cd nhost-example-app
```
@@ -28,10 +28,10 @@ git push -u origin main
Now go back to the **Nhost Console** and click **Deployments**. You just made a new deployment to your Nhost app!
![Deployments tab](/images/cli-workflow/deployments-tab.png)
![Deployments tab](/img/cli-workflow/deployments-tab.png)
If you click on the deployment you can see that nothing was really deployed. Thats because we just made a change to the README file.
![Deployments details](/images/cli-workflow/deployments-details.png)
![Deployments details](/img/cli-workflow/deployments-details.png)
Let's do some local backend changes!

View File

@@ -4,11 +4,13 @@ title: 'Local changes'
Start Nhost locally:
```sql
```bash
nhost dev
```
>💡 Make sure you have [Docker](https://www.docker.com/get-started) installed on your computer. Its required for Nhost to work.
:::tip
Make sure you have [Docker](https://www.docker.com/get-started) installed on your computer. Its required for Nhost to work.
:::
The `nhost dev` command will automatically start a complete Nhost environment locally on your computer using:
@@ -23,18 +25,22 @@ You use this local environment to do changes and testing before you deploy your
Running `nhost dev` also starts the Hasura Console.
:::tip
It's important that you use the Hasura Console that is started automatically when you do changes. This way, changes are automatically tracked for you.
:::
>💡 Its important that you use the Hasura Console that is started automatically when you do changes. This way, changes are automatically tracked for you.
![Hasura Console](/images/cli-workflow/hasura-console.png)
![Hasura Console](/img/cli-workflow/hasura-console.png)
In the Hasura Console, create a new table `customers` with two columns:
- id
- name
<Video src="/videos/cli-workflow/hasura-create-customers-table.mp4">
</Video>
<video
src="/videos/cli-workflow/hasura-create-customers-table.mp4"
width="100%"
controls
/>
When we created the `customers` table there was also a migration created automatically. The migration was created at under `nhost/migrations/default`.
@@ -50,12 +56,11 @@ This database migration has only been applied locally, meaning, you created the
To apply the local change to production we need to commit the changes and push it to GitHub. Nhost will then automatically pick up the change in the repository and apply the changes.
<aside>
💡 You can commit and push files in another terminal while still having `nhost dev` running.
:::tip
You can commit and push files in another terminal while still having `nhost dev` running.
:::
</aside>
```sql
```bash
git add -A
git commit -m "Initialized Nhost and added a customers table"
git push
@@ -63,14 +68,14 @@ git push
Head over to the **Deployments** tab in the **Nhost console** to see the deployment.
![Deployments tab after changes](/images/cli-workflow/deployments-tab-with-changes.png)
![Deployments tab after changes](/img/cli-workflow/deployments-tab-with-changes.png)
Once the deployment finishes the `customers` table is created in production.
![Customers table in Hasura Console](/images/cli-workflow/hasura-customers-table.png)
![Customers table in Hasura Console](/img/cli-workflow/hasura-customers-table.png)
Weve now completed the recommended workflow with Nhost:
We've now completed the recommended workflow with Nhost:
1. Develop locally using the Nhost CLI.
2. Push changes to GitHub.
3. Nhost deploys changes to production.
3. Nhost deploys changes to production.

View File

@@ -10,18 +10,18 @@ There are three things the CLI and the GitHub integration track and applies to p
2. Hasura Metadata
3. Serverless Functions
For this section, lets do one change to the Hasura metadata and create one serverless function
For this section, let's do one change to the Hasura metadata and create one serverless function
### Hasura Metadata
Well add permissions to the `users` table, making sure users can only see their own data. For this, go to the `auth` schema and click on the `users` table. then click on **Permissions** and enter a new role **user** and create a new **select** permission for that role**.**
We'll add permissions to the `users` table, making sure users can only see their own data. For this, go to the `auth` schema and click on the `users` table. then click on **Permissions** and enter a new role **user** and create a new **select** permission for that role**.**
Create the permission **with custom check**:
```json
{
"id": {
"_eq" : "X-Hasura-User-Id"
"_eq": "X-Hasura-User-Id"
}
}
```
@@ -36,12 +36,15 @@ Select the following columns:
Then click **Save permissions**.
<Video src="/videos/cli-workflow/hasura-user-permissions.mp4">
</Video>
<video
src="/videos/cli-workflow/hasura-user-permissions.mp4"
width="100%"
controls
/>
Now, lets do a `git status` again to confirm the permission changes we did was tracked locally in your git repository.
Now, let's do a `git status` again to confirm the permission changes we did was tracked locally in your git repository.
![Git status](/images/cli-workflow/git-status.png)
![Git status](/img/cli-workflow/git-status.png)
We can now commit this change:
@@ -50,13 +53,13 @@ git add -A
git commit -m "added permission for uses"
```
Now lets create a serverless function before we push all changes to GitHub so Nhost can deploy our changes.
Now let's create a serverless function before we push all changes to GitHub so Nhost can deploy our changes.
### Serverless Function
A serverless function is a pieces of code written in JavaScript or TypeScript that take an HTTP request and returns a response.
Heres an example:
Here's an example:
```bash
import { Request, Response } from 'express'
@@ -68,7 +71,7 @@ export default (req: Request, res: Response) => {
Serverless functions are placed in the `functions/` folder of your repository. Every file will become its own endpoint.
Before we create our serverless function well install `express`, which is a requirement for serverless functions to work.
Before we create our serverless function we'll install `express`, which is a requirement for serverless functions to work.
```bash
npm install express
@@ -76,7 +79,7 @@ npm install express
yarn add express
```
Well use TypeScript so well install two type definitions too:
We'll use TypeScript so we'll install two type definitions too:
```bash
npm install -d @types/node @types/express
@@ -84,9 +87,9 @@ npm install -d @types/node @types/express
yarn add -D @types/node @types/express
```
Then well create a file `functions/time.ts`
Then we'll create a file `functions/time.ts`
In the file `time.ts` well add the following code to create our serverless function:
In the file `time.ts` we'll add the following code to create our serverless function:
```bash
import { Request, Response } from 'express';
@@ -98,11 +101,11 @@ export default (req: Request, res: Response) => {
};
```
We can now test the function locally. Locally, the backend URL is `http://localhost:1337`. Functions are under `/v1/functions`. And every functions path and filename becomes an API endpoint.
We can now test the function locally. Locally, the backend URL is `http://localhost:1337`. Functions are under `/v1/functions`. And every function's path and filename becomes an API endpoint.
This means our function `functions/time.ts` is at `http://localhost:1337/v1/functions/time`.
Lets use curl to test our new function:
Let's use curl to test our new function:
```bash
curl http://localhost:1337/v1/functions/time
@@ -116,9 +119,9 @@ curl http://localhost:1337/v1/functions/time\?name\=Johan
Hello Johan! It's now: Sun, 06 Feb 2022 17:44:48 GMT
```
Again, lets use `git status` to see the changes we did to create our serverless function.
Again, let's use `git status` to see the changes we did to create our serverless function.
Now lets commit the changes and push them to GitHub.
Now let's commit the changes and push them to GitHub.
```bash
git add -A
@@ -128,32 +131,32 @@ git push
In the Nhost Console, click on the new deployment to see details.
![Deployments details for function](/images/cli-workflow/details-for-function.png)
![Deployments details for function](/img/cli-workflow/details-for-function.png)
After Nhost has finished deploying your changes we can test them in production. First lets confirm that the user permissions are applied.
After Nhost has finished deploying your changes we can test them in production. First let's confirm that the user permissions are applied.
![Hasura Console permissions table](/images/cli-workflow/hasura-permissions-table.png)
![Hasura Console permissions table](/img/cli-workflow/hasura-permissions-table.png)
Then, lets confirm that the serverless function was deployed. Again, well use curl:
Then, let's confirm that the serverless function was deployed. Again, we'll use curl:
```bash
curl https://your-backend-url.nhost.run/v1/functions/time\?name\=Johan
```
![Serverless Function test](/images/cli-workflow/function-test.png)
![Serverless Function test](/img/cli-workflow/function-test.png)
## Conclusion
In this tutorial we have installed the Nhost CLI and created a local Nhost environment to do local development and testing.
In the local environment weve made changes to our database, to Hasuras metadata and created a serverless function.
In the local environment we've made changes to our database, to Hasura's metadata and created a serverless function.
Weve connected a GitHub repository and pushed our changes to GitHub.
We've connected a GitHub repository and pushed our changes to GitHub.
Weve seen Nhost automatically deploying our changes and weve verified that the changes were applied.
We've seen Nhost automatically deploying our changes and we've verified that the changes were applied.
In summary, weve set up a productive environment using the recommended Nhost workflow:
In summary, we've set up a productive environment using the recommended Nhost workflow:
1. Develop locally using the Nhost CLI.
2. Push changes to GitHub.
3. Nhost deploys changes to production.
3. Nhost deploys changes to production.

View File

@@ -8,19 +8,24 @@ What follows is a detailed tutorial on how you setup Nhost for this workflow
Create a **new Nhost app** for this tutorial.
> Its important that you create a **new** Nhost app for this guide instead of reusing an old Nhost app because we want to start with a clean Nhost app.
:::tip
It's important that you create a **new** Nhost app for this guide instead of reusing an old Nhost app because we want to start with a clean Nhost app.
:::
![Create new app](/images/cli-workflow/create-app.png)
![Create new app](/img/cli-workflow/create-app.png)
### Create new GitHub Repository
Create a new GitHub repository for your new Nhost app. The repo can be either private or public.
![Create new repo](/images/cli-workflow/create-repo.png)
![Create new repo](/img/cli-workflow/create-repo.png)
## Connect GitHub Repository to Nhost App
In the Nhost Console, go to the dashboard of your Nhost app and click **Connect to GitHub**.
<Video src="/videos/cli-workflow/connect-github-repo.mp4">
</Video>
<video
src="/videos/cli-workflow/connect-github-repo.mp4"
width="100%"
controls
/>

View File

@@ -0,0 +1,36 @@
---
title: 'Welcome to Nhost'
sidebar_position: 1
---
Nhost is an open-source, real-time, server-less backend platform for building reliable apps that scale with your business.
---
## Components
Nhost uses an opinionated set of open-source components.
#### Database
Your application gets its own PostgreSQL database, the world's most advanced relational database.
#### GraphQL API
Highly performant and real-time GraphQL API with Hasura.
#### Authentication and storage
User management & file storage seamlessly integrated with Hasura permissions.
#### Serverless functions
JavaScript and TypeScript functions run your custom code in the backend.
---
## Get started
Follow our [Quick start](/get-started/quick-start) guide to build your first app.
Check out [Nhost on GitHub](https://github.com/nhost/nhost). Give us a star, and feel free to open a discussion for any feature requests as well.

View File

@@ -1,5 +1,7 @@
---
title: 'Create your app'
slug: /get-started/quick-start
sidebar_position: 1
---
Let's create a simple todo-app using Nhost. In a todo-app, a user should be able to create list items for their account (CRUD) and not have anyone else see them (permissions).
@@ -28,7 +30,7 @@ Press the **"New App"** button on the console's home page. Choose a name and pic
You'll be all set with the Default Workspace and the Free plan for now.
![New App](/images/quick-start/new-app.png)
![New App](/img/quick-start/new-app.png)
Creating a new app takes around 20 seconds or so. During this time, Nhost sets up your app's entire backend and infrastructure.

View File

@@ -18,9 +18,17 @@ In this guide, we'll keep the example simple. We're not using a frontend framewo
Create a new folder called `nhost-todos`, and initialize a new JavaScript app there:
```sh
Using npm package manager
```bash
npm init -y
# or
```
or
Using Yarn package manager
```bash
yarn init -y
```
@@ -28,9 +36,16 @@ yarn init -y
Install Nhost JavaScript SDK:
```sh
Using npm package manager
```bash
npm install @nhost/nhost-js
# or
```
or
Using Yarn package manager
```bash
yarn add @nhost/nhost-js
```
@@ -43,18 +58,18 @@ In the new directory, create a file called `index.js`.
Enter the following code into this file. It will initialize a new `NhostClient` that will interact with your backend:
```js
import { NhostClient } from '@nhost/nhost-js'
import { NhostClient } from '@nhost/nhost-js';
const nhost = new NhostClient({
backendUrl: 'https://[app-subdomain].nhost.run' // replace this with the backend URL of your app
})
backendUrl: 'https://[app-subdomain].nhost.run', // replace this with the backend URL of your app
});
console.log(nhost.graphql.getUrl())
console.log(nhost.graphql.getUrl());
```
Run the code in your terminal. You should see your app's GraphQL endpoint URL:
```sh
```bash
➜ node index.js
https://[app-subdomain].nhost.run/v1/graphql
@@ -65,10 +80,10 @@ https://[app-subdomain].nhost.run/v1/graphql
If you now add the following GraphQL query to the client, let's see what happens when you run the updated version:
```js
import { NhostClient } from '@nhost/nhost-js'
import { NhostClient } from '@nhost/nhost-js';
const nhost = new NhostClient({
backendUrl: 'https://[app-subdomain].nhost.run'
backendUrl: 'https://[app-subdomain].nhost.run',
})(async () => {
// nhost.graphql.request returns a promise, so we use await here
const todos = await nhost.graphql.request(`
@@ -80,14 +95,14 @@ const nhost = new NhostClient({
is_completed
}
}
`)
`);
// Print todos to console
console.log(JSON.stringify(todos.data, null, 2))
})()
console.log(JSON.stringify(todos.data, null, 2));
})();
```
```sh
```bash
➜ node index.js
null

View File

@@ -18,11 +18,11 @@ In Hasura Console, go to the **Data** tab, click on the **todos** table, then cl
Add the following permissions:
![Public role](/images/quick-start/permissions-public-select.png)
![Public role](/img/quick-start/permissions-public-select.png)
Rerun the program. Now you see all todos.
```sh
```bash
➜ node index.js
{

View File

@@ -14,7 +14,7 @@ Go to the **Data** tab on your app's dashboard and select **Open Hasura**. Remem
The Hasura Console of your app's dedicated Hasura instance will open in a new tab. You can use Hasura Console to manage your app's schema, data, permissions, and event triggers.
![Data -> Open Hasura](/images/quick-start/data-tab.png)
![Data -> Open Hasura](/img/quick-start/data-tab.png)
---
@@ -27,7 +27,7 @@ You should see all your database tables on the left-hand side of the screen. You
If you open the `auth` schema, you'll see that your app already has a `users` table, so you don't have to create one.
![To store the users, we already have a users table from the auth schema](/images/quick-start/list-of-schemas.png)
![To store the users, we already have a users table from the auth schema](/img/quick-start/list-of-schemas.png)
---
@@ -44,7 +44,7 @@ In Hasura Console, go to the **data** tab, then click **Create Table**. Name thi
Using frequently used columns ensures the columns get the right name, type, and default value.
![Frequently used columns in the Hasura console](/images/quick-start/frequently-used-columns.png)
![Frequently used columns in the Hasura console](/img/quick-start/frequently-used-columns.png)
### Add custom columns
@@ -55,7 +55,7 @@ Add two more columns manually:
Make sure to set the default value of `is_completed` to `false`.
![Create a table in the Hasura console](/images/quick-start/create-table.png)
![Create a table in the Hasura console](/img/quick-start/create-table.png)
This is all we need! A new table will be created when you click **Add Table**.
@@ -65,7 +65,7 @@ This is all we need! A new table will be created when you click **Add Table**.
Go to the **Insert Row** tab to add some data to your database.
![Inserting todos](/images/quick-start/insert-todos.gif)
![Inserting todos](/img/quick-start/insert-todos.gif)
---

View File

@@ -10,9 +10,11 @@ Upgrading from Nhost v1 to v2 requires database schema and Hasura metadata chang
### Create a new Nhost v2 app locally
> Make sure you have the [Nhost CLI](/reference/cli) installed
:::tip
Make sure you have the [Nhost CLI](/reference/cli) installed
:::
```sh
```bash
nhost init my-nhost-v2-app
cd my-nhost-v2-app
```
@@ -25,7 +27,7 @@ Update `config: 3` to `config: 2` in `nhost/config.yaml`. This will update Hasur
Inside the `nhost/` folder of your app, run:
```sh
```bash
hasura migrate create init --from-server --endpoint=[v1-endpoint] --admin-secret=[v1-admin-secret]
hasura metadata export --endpoint=[v1-endpoint] --admin-secret=[v1-admin-secret]
@@ -35,7 +37,9 @@ hasura metadata export --endpoint=[v1-endpoint] --admin-secret=[v1-admin-secret]
Make the following changes manually to your migrations.
> The migration file is located at `nhost/migrations/[timestamp]/up.sql`.
:::tip
The migration file is located at `nhost/migrations/[timestamp]/up.sql`.
:::
- Add `OR REPLACE` after `CREATE` for the `public.set_current_timestamp_updated_at` function
- Delete all `auth.*` tables and functions (if any).
@@ -46,7 +50,9 @@ Make the following changes manually to your migrations.
Make the following changes manually to your metadata.
> The metadata is located at `nhost/metadata/tables.yaml`.
:::tip
The metadata is located at `nhost/metadata/tables.yaml`.
:::
- Delete tracking all tables in the `auth` schema.
- Delete tracking the `public.users` table.
@@ -56,11 +62,13 @@ Make the following changes manually to your metadata.
Start Nhost locally using the [CLI](/reference/cli). From the root of your app, run:
```sh
```bash
nhost -d
```
> Running Nhost applies your local database migrations and Hasura metadata.
:::tip
Running Nhost applies your local database migrations and Hasura metadata.
:::
### Restart Auth and Storage containers
@@ -70,7 +78,7 @@ Open Docker UI and restart Hasura Auth and Hasura Storage. Restarting those cont
Delete the local migrations and metadata.
```
```bash
rm -rf nhost/migrations nhost/metadata
```
@@ -80,9 +88,11 @@ Update `config: 2` to `config: 3` in `nhost/config.yaml`.
### Pull migrations and metadata from our local instance
> You can not use port `1337` in these requests. You have to use the specific port Huasra uses. Go to the Hasura Console under API and look what port Hasura is using under GraphQL Endpoint.
:::tip
You can not use port `1337` in these requests. You have to use the specific port Huasra uses. Go to the Hasura Console under API and look what port Hasura is using under GraphQL Endpoint.
:::
```
```bash
hasura migrate create init --from-server --endpoint=http://localhost:[hasura-port] --admin-secret=nhost-admin-secret
hasura metadata export --from-server --endpoint=http://localhost:[hasura-port] --admin-secret=nhost-admin-secret
```

View File

@@ -0,0 +1,5 @@
{
"label": "Authentication",
"position": 3,
"link": { "id": "platform/authentication/index", "type": "doc" }
}

View File

@@ -1,5 +1,6 @@
---
title: 'Email templates'
sidebar_position: 4
---
The following emails can be sent as part of the authentication flow:
@@ -17,7 +18,7 @@ If you have developed custom email templates, you must make them available over
Go to **Users -> Login settings** and scroll down to **Custom email templates**, and set the URL to where your templates are located:
![ ](/images/platform/email-templates.svg)
![Email templates](/img/platform/email-templates.svg)
You only need to define the base URL to point to your hosted templates. The UI will give you a hint about where Nhost will look for your actual template files.

View File

@@ -1,38 +1,37 @@
---
title: 'Overview'
title: Authentication
sidebar_position: 1
---
Nhost provides a ready-to-use authentication service, integrated with Nhost JavaScript SDK. This makes it easy to build login flows with multiple login methods.
# Authentication
---
Nhost provides a ready-to-use authentication service, integrated with Nhost JavaScript SDK. This makes it easy to build login flows with multiple sign-in methods.
## Getting started
## Getting Started
Using [Nhost JavaScript SDK](/reference/sdk), sign up a new user:
Sign up a user with the [Nhost JavaScript SDK](/reference/sdk):
```js
import { NhostClient } from '@nhost/nhost-js'
import { NhostClient } from '@nhost/nhost-js';
const nhost = new NhostClient({
backendUrl: 'https://[app-subdomain].nhost.run'
})
backendUrl: 'https://[app-subdomain].nhost.run',
});
await nhost.auth.signUp({
email: 'joe@nhost.io',
password: 'secret-password'
})
password: 'secret-password',
});
```
---
## How it works
1. A user signs up and the user information is added to the `auth.users` table
2. Nhost returns an access token (JWT token) with the user's information. The access token is cryptographically signed.
1. A user signs up and the user information is added to the `auth.users` table.
2. Nhost returns an [access token](#access-tokens) (JWT token) and the user's information.
3. The user sends a request to the GraphQL API together with the access token.
4. The GraphQL API reviews the access token to ensure the user is authorized to send the request.
Nhost's authentication service is integrated with your database. All users are saved in the app's database under the `auth` schema and can be accessed using GraphQL:
Nhost's authentication service is integrated with your database. All users are stored in the app's database under the `auth` schema and can be accessed using GraphQL:
```graphql
query {
@@ -45,13 +44,11 @@ query {
}
```
---
## Tokens
Nhost authentication uses two tokens: Access tokens and refresh tokens.
[Nhost JavaScript SDK](/sdk/) automatically handles access and refresh tokens.
[Nhost JavaScript SDK](/reference/sdk) automatically handles access and refresh tokens.
### Access tokens

View File

@@ -0,0 +1,4 @@
{
"label": "OAuth providers",
"position": 3
}

View File

@@ -1,14 +1,23 @@
---
title: Sign In with Facebook
title: Sign in with Facebook
sidebar_position: 2
slug: /platform/authentication/sign-in-with-facebook
---
Follow this guide to sign in users with Facebook with your Nhost App.
![Facebook Sign In Preview](/images/platform/social-providers/facebook-preview.png)
<p align="center">
<img
alt="Facebook Sign In Preview"
src="/img/social-providers/facebook-preview.svg"
width={480}
height={267}
/>
</p>
# Create Facebook account
## Create Facebook account
- Create a new [Facebook account](https://www.facebook.com/) if you dont have one already.
- Create a new [Facebook account](https://www.facebook.com/) if you don't have one already.
## Create Facebook App
@@ -24,7 +33,7 @@ Follow this guide to sign in users with Facebook with your Nhost App.
- Click on Add Product in the left menu.
- Click on Setup in the Facebook login card.
- **Dont** complete the quickstart. Instead, follow the next step.
- **Don't** complete the quickstart. Instead, follow the next step.
- Click on **Settings** under **Facebook Login** in the left menu.
- Make sure **Embedded Browser OAuth Login** is set to **Yes**.
- Fill in **Valid OAuth Redirect URIs** with your **OAuth Callback URL** from Nhost.
@@ -43,7 +52,7 @@ To make sure we can fetch all user data (email, profile picture and name). For t
## Configure Nhost
- Click **Settings** and then **Basic** in the left menu.
- Copy and paste the **App ID (Client ID)** and **App secret (Client Secret)** from Facebook to your Nhost OAuth settings for Facebook. Make sure the [OAuth provider is enabled in Nhost](/platform/authentication/social-sign-in#enabling-social-sign-in).
- Copy and paste the **App ID (Client ID)** and **App secret (Client Secret)** from Facebook to your Nhost OAuth settings for Facebook. Make sure the [OAuth provider is enabled in Nhost](/platform/authentication/social-sign-in#enabling-social-sign-in-provider).
- Click the checkbox “**I have pasted the redirect URI into Facebook”**.
- Click **Confirm settings**.
@@ -53,6 +62,6 @@ Use the [Nhost JavaScript client](/reference/sdk) to sign in users in your app:
```js
nhost.auth.signIn({
provider: 'facebook'
})
provider: 'facebook',
});
```

View File

@@ -1,14 +1,23 @@
---
title: Sign In with GitHub
title: Sign in with GitHub
sidebar_position: 3
slug: /platform/authentication/sign-in-with-github
---
Follow this guide to sign in users with GitHub with your Nhost App.
![GitHub Sign In Preview](/images/platform/social-providers/github-preview.png)
<p align="center">
<img
alt="GitHub Sign In Preview"
src="/img/social-providers/github-preview.svg"
width={480}
height={267}
/>
</p>
# Create GitHub account
## Create GitHub account
- Create a new [GitHub account](https://github.com/signup) if you dont have one already.
- Create a new [GitHub account](https://github.com/signup) if you don't have one already.
## Create GitHub OAuth App
@@ -28,7 +37,7 @@ Follow this guide to sign in users with GitHub with your Nhost App.
## Configure Nhost
- Click Generate a new client secret to generate a OAuth client secret.
- Copy and paste the **Client ID** and **Client Secret** from GitHub to your Nhost OAuth settings for GitHub. Make sure the [OAuth provider is enabled in Nhost](/platform/authentication/social-sign-in#enabling-social-sign-in).
- Copy and paste the **Client ID** and **Client Secret** from GitHub to your Nhost OAuth settings for GitHub. Make sure the [OAuth provider is enabled in Nhost](/platform/authentication/social-sign-in#enabling-social-sign-in-provider).
- Click the checkbox “**I have pasted the redirect URI into GitHub”**.
- Click **Confirm settings**.
@@ -38,6 +47,6 @@ Use the [Nhost JavaScript client](/reference/sdk) to sign in users in your app:
```js
nhost.auth.signIn({
provider: 'github'
})
provider: 'github',
});
```

View File

@@ -1,10 +1,19 @@
---
title: Sign In with Google
title: Sign in with Google
sidebar_position: 1
slug: /platform/authentication/sign-in-with-google
---
Follow this guide to sign in users with Google with your Nhost App.
![Google Sign In Preview](/images/platform/social-providers/google-preview.png)
<p align="center">
<img
alt="Google Sign In Preview"
src="/img/social-providers/google-preview.svg"
width={480}
height={267}
/>
</p>
## Sign up for Google
@@ -52,16 +61,16 @@ Follow this guide to sign in users with Google with your Nhost App.
## Configure Nhost
- A modal appears with your Google Client ID and Client secret.
- Copy and paste the **Client ID** and **Client Secret** from Google to your Nhost OAuth settings for Google. Make sure the [OAuth provider is enabled in Nhost](/platform/authentication/social-sign-in#enabling-social-sign-in).
- Copy and paste the **Client ID** and **Client Secret** from Google to your Nhost OAuth settings for Google. Make sure the OAuth provider is enabled in Nhost.
- Click the checkbox “**I have pasted the redirect URI into Google”**.
- Click **Confirm settings**.
## Sign In users in your app
Use the [Nhost JavaScript client](/reference/sdk) to sign in users in your app:
Use the Nhost JavaScript client to sign in users in your app:
```js
nhost.auth.signIn({
provider: 'google'
})
provider: 'google',
});
```

View File

@@ -1,12 +1,13 @@
---
title: 'Social Sign-In Providers'
title: 'OAuth Providers'
slug: /platform/authentication/social-sign-in
---
Nhost Auth supports the following social sign-in providers:
- [GitHub](/platform/authentication/sign-in-with-github)
- [Google](/platform/authentication/sign-in-with-google)
- [Facebook](/platform/authentication/sign-in-with-facebook)
- [GitHub](/platform/authentication/sign-in-with-github)
- [LinkedIn](/platform/authentication/sign-in-with-linkedin)
- [Spotify](/platform/authentication/sign-in-with-spotify)
@@ -28,8 +29,8 @@ Here's an example of how to implement sign-in with GitHub:
```js
nhost.auth.signIn({
provider: 'github'
})
provider: 'github',
});
```
Users are redirected to your Nhost app's **client URL** by default. By default your Nhost app's client URL is set to `http://localhost:3000`. You can change the value of your client URL in the Nhost console by going to **Users****Login settings****Client URL**.

View File

@@ -1,10 +1,19 @@
---
title: Sign In with LinkedIn
title: Sign in with LinkedIn
sidebar_position: 4
slug: /platform/authentication/sign-in-with-linkedin
---
Follow this guide to sign in users with LinkedIn with your Nhost App.
![LinkedIn Sign In Preview](/images/platform/social-providers/linkedin-preview.png)
<p align="center">
<img
alt="LinkedIn Sign In Preview"
src="/img/social-providers/linkedin-preview.svg"
width={480}
height={267}
/>
</p>
## Create LinkedIn account
@@ -45,6 +54,6 @@ Use the [Nhost JavaScript client](/reference/sdk) to sign in users in your app:
```js
nhost.auth.signIn({
provider: 'linkedin'
})
provider: 'linkedin',
});
```

View File

@@ -1,12 +1,21 @@
---
title: Sign In with Spotify
title: Sign in with Spotify
sidebar_position: 5
slug: /platform/authentication/sign-in-with-spotify
---
Follow this guide to sign in users with Spotify with your Nhost App.
![Spotify Sign In Preview](/images/platform/social-providers/spotify-preview.png)
<p align="center">
<img
alt="Spotify Sign In Preview"
src="/img/social-providers/spotify-preview.svg"
width={480}
height={267}
/>
</p>
# Create Spotify account
## Create Spotify account
- Create a new [Spotify account](https://www.spotify.com/) if you don't have one already.
@@ -38,6 +47,6 @@ Use the [Nhost JavaScript client](/reference/sdk) to sign in users in your app:
```js
nhost.auth.signIn({
provider: 'spotify'
})
provider: 'spotify',
});
```

View File

@@ -1,5 +1,6 @@
---
title: 'Sign-in methods'
sidebar_position: 2
---
Nhost supports a variety of sign-in methods:
@@ -13,8 +14,8 @@ To sign in a user with email and password, the user must first sign up:
```js
await nhost.auth.signUp({
email: 'joe@nhost.io',
password: 'secret-password'
})
password: 'secret-password',
});
```
If you've turned on email verification in your app's **login settings**, a user will be sent a verification email upon signup. The user must click the verification link in the email before they can log in.
@@ -24,8 +25,8 @@ Once a user has been signed up (and optionally verified), you can sign them in:
```js
await nhost.auth.signIn({
email: 'joe@nhost.io',
password: 'secret-password'
})
password: 'secret-password',
});
```
---
@@ -42,8 +43,8 @@ Example in JavaScript:
```js
await nhost.auth.signIn({
email: 'joe@nhost.io'
})
email: 'joe@nhost.io',
});
```
---
@@ -56,8 +57,8 @@ First, "sign in" the user with a phone number.
```js
await nnhost.auth.signIn({
phoneNumber: '+467610337135'
})
phoneNumber: '+467610337135',
});
```
This will create the user if the user does not already exist, and send a One Time Password (OTP) to the user's
@@ -68,8 +69,8 @@ Use the OTP to finalize the sign-in:
```js
await nhost.auth.signIn({
phoneNumber: '+467610337135',
otp: 'otp-from-sms'
})
otp: 'otp-from-sms',
});
```
---

View File

@@ -1,5 +1,6 @@
---
title: 'User management'
sidebar_position: 1
---
Users are saved in the database in the `auth.users` table and are accessible via the GraphQL API.
@@ -66,7 +67,7 @@ If the user is not signed in, the `public` role will be used.
When no request role is specified, the user's default role will be used:
```js
await nhost.graphql.request(QUERY, {})
await nhost.graphql.request(QUERY, {});
```
Make a GraphQL request with the `me` role:
@@ -77,10 +78,10 @@ await nhost.graphql.request(
{},
{
headers: {
'x-hasura-role': 'me'
}
}
)
'x-hasura-role': 'me',
},
},
);
```
If the request is not part of the user's roles, the request will fail.

View File

@@ -0,0 +1,6 @@
{
"label": "Database",
"position": 2,
"collapsed": false,
"link": { "type": "generated-index", "slug": "/platform/database" }
}

View File

@@ -1,5 +1,6 @@
---
title: 'GraphQL'
sidebar_position: 3
---
GraphQL is a query language for APIs. It provides a complete and understandable description of the data in your API.
@@ -110,7 +111,13 @@ GraphQL mutation to insert data looks like this:
```graphql
mutation InsertTodo {
insert_todos(
objects: [{ title: "Delete Firebase account", body: "Migrate to nhost.io", done: false }]
objects: [
{
title: "Delete Firebase account"
body: "Migrate to nhost.io"
done: false
}
]
) {
returning {
id
@@ -147,7 +154,11 @@ Multiple rows can be inserted with an array as the objects property. This can be
mutation InsertMultipleTodos {
insert_todos(
objects: [
{ title: "Build the front end", body: "Mobile app or website first?", done: false }
{
title: "Build the front end"
body: "Mobile app or website first?"
done: false
}
{ title: "Launch 🚀", body: "That was easy", done: false }
]
) {

View File

@@ -1,5 +1,6 @@
---
title: 'Permissions'
sidebar_position: 2
---
The GraphQL API is protected by a role-based permission system based on access tokens. Permissions are handled on a per-table basis in Hasura Console.
@@ -26,7 +27,7 @@ The default role for users is `user`.
## Select permissions
![Select permissions](/images/platform/permission-select.png)
![Select permissions](/img/platform/permission-select.png)
One of the most common permission requirements is that logged-in users should only be able to read their own data. This is how it can be achieved with Hasura.
@@ -49,7 +50,7 @@ Note that if you add columns to your table table later, you must check new colum
## Insert permissions
![Insert permissions](/images/platform/permission-insert.png)
![Insert permissions](/img/platform/permission-insert.png)
Here is a popular approach for insert permission for logged in users.
@@ -67,7 +68,7 @@ We also want every new record's `user_id` value to be set to the ID of the user
You can add extra permission variables in the Nhost console under **Users** and then **Roles and permissions**. These permission variables are then available when creating permissions for your GraphQL API in the Hasura console.
![Permission Variables](/images/platform/permission-variables-preview.svg)
![Permission Variables](/img/platform/permission-variables-preview.svg)
As an example, let's say you add a new permission variable `x-hasura-organisation-id` with path `user.profile.organisation.id`. This means that Nhost Auth will get the value for `x-hasura-organisation-id` by internally generating the following GraphQL query:

View File

@@ -1,5 +1,6 @@
---
title: 'Schema'
sidebar_position: 1
---
Every Nhost app comes with a Postgres database. Postgres is the world's most advanced open-source relational database and the most popular SQL database among developers. The database is hosted with Amazon RDS.

View File

@@ -1,5 +1,6 @@
---
title: 'The Nhost platform'
sidebar_position: 1
---
This section:
@@ -15,7 +16,7 @@ This section:
- [Authentication overview](/platform/authentication)
- [User management](/platform/authentication/user-management)
- [Sign-in methods](/platform/authentication/sign-in-methods)
- [Social login](/platform/authentication/social-login)
- [OAuth providers](/platform/authentication/social-sign-in)
- [Email templates](/platform/authentication/email-templates)
### Storage

View File

@@ -0,0 +1,4 @@
{
"label": "Nhost",
"position": 6
}

View File

@@ -1,5 +1,6 @@
---
title: 'Environment variables'
sidebar_position: 1
---
Environment variables are key-value pairs configured outside your source code. They are used to store environment-specific values such as API keys.
@@ -17,7 +18,7 @@ System environment variables are automatically available in production and local
Example values:
```sh
```bash
NHOST_ADMIN_SECRET=e7w36ag287qn5qry795f6ymm57qgvqup
NHOST_WEBHOOK_SECRET=ns3sfjgdw4y6zeqthwnnw347dzh8wyj4
NHOST_JWT_SECRET={"type": "HS256", "key": "vumpbe2w2mgaqj5yqfp7dvxu6kywtvsgb68ejpdaqxerea8

View File

@@ -1,5 +1,6 @@
---
title: 'GitHub integration'
sidebar_position: 2
---
You can connect your Nhost app to a GitHub repository. When you do this, any updates you push to your code will automatically be deployed.

View File

@@ -1,5 +1,6 @@
---
title: 'Nhost CLI'
sidebar_position: 3
---
Nhost CLI lets you run Nhost's development environment locally on macOS, Linux and Windows.
@@ -10,7 +11,7 @@ Nhost CLI lets you run Nhost's development environment locally on macOS, Linux a
Download and install Nhost CLI for your platform by running this command in your terminal:
```sh
```bash
sudo curl -L https://raw.githubusercontent.com/nhost/cli/main/get.sh | bash
```
@@ -27,7 +28,7 @@ To run serverless functions locally, you must have the appropriate runtimes inst
For Node.js, you will also need to have [express](https://www.npmjs.com/package/express) installed in your repository:
```sh
```bash
npm install --save-dev express @types/express
```
@@ -63,7 +64,7 @@ This will run the Hasura GraphQL engine using Rosetta on your machine until an M
If you already Nhost CLI installed, you can upgrade your installation:
```sh
```bash
# sudo permissions needed
sudo nhost upgrade
```

Some files were not shown because too many files have changed in this diff Show More