feat: v4.0.0 (#1016)
Co-authored-by: Denys Konovalov <kontakt@denyskon.de> Co-authored-by: Mathieu COSYNS <64072917+Mathieu-COSYNS@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
682576ffc4
commit
799c7e6936
@ -114,7 +114,6 @@ module.exports = {
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': [0],
|
||||
'@typescript-eslint/explicit-module-boundary-types': [0],
|
||||
'@typescript-eslint/no-duplicate-imports': 'error',
|
||||
'@typescript-eslint/no-use-before-define': [
|
||||
'error',
|
||||
{ functions: false, classes: true, variables: true },
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "Help us build the CMS of the future",
|
||||
"subtitle": "Get support, give support and find out what's new through the channels below.",
|
||||
"subtitle": "Get support, give support and find out what is new through the channels below.",
|
||||
"sections": [
|
||||
{
|
||||
"title": "Contributing",
|
||||
|
@ -4,7 +4,7 @@ title: Bundling
|
||||
weight: 5
|
||||
---
|
||||
|
||||
This tutorial guides you through the steps for adding Static CMS via a package manager to a site that's built with a common [static site generator](https://www.staticgen.com/). If you want to start form a template, the [Next Template](/docs/start-with-a-template) provides a great example of bundling in action.
|
||||
This tutorial guides you through the steps for adding Static CMS via a package manager to a site that is built with a common [static site generator](https://www.staticgen.com/). If you want to start form a template, the [Next Template](/docs/start-with-a-template) provides a great example of bundling in action.
|
||||
|
||||
## Installation
|
||||
|
||||
@ -58,11 +58,11 @@ Make sure the file containing the CMS object will be built as a page, with `@sta
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is different for every site, so we'll break it down into parts. Add all the code snippets in this section to your `admin/config.js` file (which is passed into the `CMS.init({ config })` call).
|
||||
Configuration is different for every site, so we will break it down into parts. Add all the code snippets in this section to your `admin/config.js` file (which is passed into the `CMS.init({ config })` call).
|
||||
|
||||
### Backend
|
||||
|
||||
We're using [Netlify](https://www.netlify.com) for our hosting and authentication in this tutorial, so backend configuration is fairly straightforward.
|
||||
We are using [Netlify](https://www.netlify.com) for our hosting and authentication in this tutorial, so backend configuration is fairly straightforward.
|
||||
|
||||
For GitHub and GitLab repositories, you can start your Static CMS `config` file with these lines:
|
||||
|
||||
@ -84,7 +84,22 @@ backend:
|
||||
|
||||
_(For Bitbucket repositories, use the [Bitbucket backend](/docs/bitbucket-backend) instructions instead.)_
|
||||
|
||||
The configuration above specifies your backend protocol and your publication branch. Git Gateway is an open source API that acts as a proxy between authenticated users of your site and your site repo. (We'll get to the details of that in the [Authentication section](#authentication) below.) If you leave out the `branch` declaration, it defaults to `main`.
|
||||
The configuration above specifies your backend protocol and your publication branch. Git Gateway is an open source API that acts as a proxy between authenticated users of your site and your site repo. (We will get to the details of that in the [Authentication section](#authentication) below.) If you leave out the `branch` declaration, it defaults to `main`.
|
||||
|
||||
### Editorial Workflow <BetaImage />
|
||||
|
||||
By default, saving a post in the CMS interface pushes a commit directly to the publication branch specified in `backend`. However, you also have the option to enable the [Editorial Workflow](/docs/editorial-workflow), which adds an interface for drafting, reviewing, and approving posts. To do this, add the following line to your `config.yml`:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
publish_mode: editorial_workflow
|
||||
```
|
||||
|
||||
```js
|
||||
publish_mode: 'editorial_workflow'
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### Media and Public Folders
|
||||
|
||||
@ -102,9 +117,9 @@ media_folder: 'images/uploads' # Media files will be stored in the repo under im
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
If you're creating a new folder for uploaded media, you'll need to know where your static site generator expects static files. You can refer to the paths outlined above in [App File Structure](#app-file-structure), and put your media folder in the same location where you put the `admin` folder.
|
||||
If you are creating a new folder for uploaded media, you will need to know where your static site generator expects static files. You can refer to the paths outlined above in [App File Structure](#app-file-structure), and put your media folder in the same location where you put the `admin` folder.
|
||||
|
||||
Note that the`media_folder` file path is relative to the project root, so the example above would work for Jekyll, GitBook, or any other generator that stores static files at the project root. However, it would not work for Hugo, Hexo, Middleman or others that store static files in a subfolder. Here's an example that could work for a Hugo site:
|
||||
Note that the`media_folder` file path is relative to the project root, so the example above would work for Jekyll, GitBook, or any other generator that stores static files at the project root. However, it would not work for Hugo, Hexo, Middleman or others that store static files in a subfolder. Here is an example that could work for a Hugo site:
|
||||
|
||||
<CodeTabs>
|
||||
```js
|
||||
@ -120,7 +135,7 @@ public_folder: '/images/uploads' # The src attribute for uploaded media will beg
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
The configuration above adds a new setting, `public_folder`. While `media_folder` specifies where uploaded files are saved in the repo, `public_folder` indicates where they are found in the published site. Image `src` attributes use this path, which is relative to the file where it's called. For this reason, we usually start the path at the site root, using the opening `/`.
|
||||
The configuration above adds a new setting, `public_folder`. While `media_folder` specifies where uploaded files are saved in the repo, `public_folder` indicates where they are found in the published site. Image `src` attributes use this path, which is relative to the file where it is called. For this reason, we usually start the path at the site root, using the opening `/`.
|
||||
|
||||
_If `public_folder` is not set, Static CMS defaults to the same value as `media_folder`, adding an opening `/` if one is not included._
|
||||
|
||||
@ -128,7 +143,7 @@ _If `public_folder` is not set, Static CMS defaults to the same value as `media_
|
||||
|
||||
Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings differ greatly from one site to the next.
|
||||
|
||||
Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so:
|
||||
Let us say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so:
|
||||
|
||||
```yaml
|
||||
---
|
||||
@ -151,7 +166,7 @@ collections: [
|
||||
label: 'Blog', // Used in the UI
|
||||
folder: '_posts/blog', // The path to the folder where the documents are stored
|
||||
create: true, // Allow users to create new documents in this collection
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}', // Filename template, e.g., YYYY-MM-DD-title.md
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}', // Filename template, e.g., yyyy-MM-dd-title.md
|
||||
fields: [ // The fields for each document, usually in front matter
|
||||
{ label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' },
|
||||
{ label: 'Title', name: 'title', widget: 'string' },
|
||||
@ -170,7 +185,7 @@ collections:
|
||||
label: 'Blog' # Used in the UI
|
||||
folder: '_posts/blog' # The path to the folder where the documents are stored
|
||||
create: true # Allow users to create new documents in this collection
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., yyyy-MM-dd-title.md
|
||||
fields: # The fields for each document, usually in front matter
|
||||
- { label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' }
|
||||
- { label: 'Title', name: 'title', widget: 'string' }
|
||||
@ -182,7 +197,7 @@ collections:
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
Let's break that down:
|
||||
Let us break that down:
|
||||
|
||||
| Field | Description |
|
||||
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@ -239,7 +254,7 @@ collections:
|
||||
|
||||
## Authentication
|
||||
|
||||
Now that you have your Static CMS files in place and configured, all that's left is to enable authentication. We're using the [Netlify](https://www.netlify.com/) platform here because it's one of the quickest ways to get started, but you can learn about other authentication options in the [Backends](/docs/backends-overview) doc.
|
||||
Now that you have your Static CMS files in place and configured, all that is left is to enable authentication. We are using the [Netlify](https://www.netlify.com/) platform here because it is one of the quickest ways to get started, but you can learn about other authentication options in the [Backends](/docs/backends-overview) doc.
|
||||
|
||||
### Setup on Netlify
|
||||
|
||||
@ -250,9 +265,9 @@ Netlify offers a built-in authentication service called Identity. In order to us
|
||||
Netlify's Identity and Git Gateway services allow you to manage CMS admin users for your site without requiring them to have an account with your Git host or commit access on your repo. From your site dashboard on Netlify:
|
||||
|
||||
1. Go to **Settings > Identity**, and select **Enable Identity service**.
|
||||
2. Under **Registration preferences**, select **Open** or **Invite only**. In most cases, you want only invited users to access your CMS, but if you're just experimenting, you can leave it open for convenience.
|
||||
2. Under **Registration preferences**, select **Open** or **Invite only**. In most cases, you want only invited users to access your CMS, but if you are just experimenting, you can leave it open for convenience.
|
||||
3. If you'd like to allow one-click login with services like Google and GitHub, check the boxes next to the services you'd like to use, under **External providers**.
|
||||
4. Scroll down to **Services > Git Gateway**, and click **Enable Git Gateway**. This authenticates with your Git host and generates an API access token. In this case, we're leaving the **Roles** field blank, which means any logged in user may access Static CMS. For information on changing this, check the [Netlify Identity documentation](https://www.netlify.com/docs/identity/).
|
||||
4. Scroll down to **Services > Git Gateway**, and click **Enable Git Gateway**. This authenticates with your Git host and generates an API access token. In this case, we are leaving the **Roles** field blank, which means any logged in user may access Static CMS. For information on changing this, check the [Netlify Identity documentation](https://www.netlify.com/docs/identity/).
|
||||
|
||||
### Add the Netlify Identity Widget
|
||||
|
||||
@ -262,7 +277,7 @@ With the backend set to handle authentication, now you need a frontend interface
|
||||
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
|
||||
```
|
||||
|
||||
Add this to the `<head>` of your CMS index page at `/admin/index.html`, as well as the `<head>` of your site's main index page. Depending on how your site generator is set up, this may mean you need to add it to the default template, or to a "partial" or "include" template. If you can find where the site stylesheet is linked, that's probably the right place. Alternatively, you can include the script in your site using Netlify's [Script Injection](https://www.netlify.com/docs/inject-analytics-snippets/) feature.
|
||||
Add this to the `<head>` of your CMS index page at `/admin/index.html`, as well as the `<head>` of your site's main index page. Depending on how your site generator is set up, this may mean you need to add it to the default template, or to a "partial" or "include" template. If you can find where the site stylesheet is linked, that is probably the right place. Alternatively, you can include the script in your site using Netlify's [Script Injection](https://www.netlify.com/docs/inject-analytics-snippets/) feature.
|
||||
|
||||
When a user logs in with the Netlify Identity widget, an access token directs to the site homepage. In order to complete the login and get back to Static CMS, redirect the user back to the `/admin/` path. To do this, add the following script before the closing `body` tag of your site's main index page:
|
||||
|
||||
@ -290,6 +305,6 @@ If you set your registration preference to "Invite only," invite yourself (and a
|
||||
|
||||
If you left your site registration open, or for return visits after confirming an email invitation, access your site's CMS at `yoursite.com/admin/`.
|
||||
|
||||
**Note:** No matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it always fetches and commits files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS `config` file. This means that content fetched in the admin UI matches the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI saves directly to the hosted repository, even if you're running the UI locally or in staging.
|
||||
**Note:** No matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it always fetches and commits files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS `config` file. This means that content fetched in the admin UI matches the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI saves directly to the hosted repository, even if you are running the UI locally or in staging.
|
||||
|
||||
Happy posting!
|
||||
|
@ -4,11 +4,11 @@ title: CDN Hosting
|
||||
weight: 4
|
||||
---
|
||||
|
||||
This tutorial guides you through the steps for adding Static CMS via a public CDN to a site that's built with a common [static site generator](https://www.staticgen.com/), like Jekyll, Next, Hugo, Hexo, or Gatsby. Alternatively, you can [start from a template](/docs/start-with-a-template) or dive right into [configuration options](/docs/configuration-options).
|
||||
This tutorial guides you through the steps for adding Static CMS via a public CDN to a site that is built with a common [static site generator](https://www.staticgen.com/), like Jekyll, Next, Hugo, Hexo, or Gatsby. Alternatively, you can [start from a template](/docs/start-with-a-template) or dive right into [configuration options](/docs/configuration-options).
|
||||
|
||||
## App File Structure
|
||||
|
||||
A static `admin` folder contains all Static CMS files, stored at the root of your published site. Where you store this folder in the source files depends on your static site generator. Here's the static file location for a few of the most popular static site generators:
|
||||
A static `admin` folder contains all Static CMS files, stored at the root of your published site. Where you store this folder in the source files depends on your static site generator. Here is the static file location for a few of the most popular static site generators:
|
||||
|
||||
| These generators | store static files in |
|
||||
| ------------------------------------------------------- | --------------------- |
|
||||
@ -25,9 +25,9 @@ A static `admin` folder contains all Static CMS files, stored at the root of you
|
||||
| preact-cli | `/src/static` |
|
||||
| Docusaurus | `/static` |
|
||||
|
||||
If your generator isn't listed here, you can check its documentation, or as a shortcut, look in your project for a `css` or `images` folder. The contents of folders like that are usually processed as static files, so it's likely you can store your `admin` folder next to those. (When you've found the location, feel free to add it to these docs by [filing a pull request](https://github.com/StaticJsCMS/static-cms/blob/main/CONTRIBUTING.md#pull-requests)!)
|
||||
If your generator is not listed here, you can check its documentation, or as a shortcut, look in your project for a `css` or `images` folder. The contents of folders like that are usually processed as static files, so it is likely you can store your `admin` folder next to those. (When you have found the location, feel free to add it to these docs by [filing a pull request](https://github.com/StaticJsCMS/static-cms/blob/main/CONTRIBUTING.md#pull-requests)!)
|
||||
|
||||
Inside the `admin` folder, you'll create two files:
|
||||
Inside the `admin` folder, you will create two files:
|
||||
|
||||
```bash
|
||||
admin
|
||||
@ -35,7 +35,7 @@ admin
|
||||
└ config.yml
|
||||
```
|
||||
|
||||
The first file, `admin/index.html`, is the entry point for the Static CMS admin interface. This means that users navigate to `yoursite.com/admin/` to access it. On the code side, it's a basic HTML starter page that loads the Static CMS JavaScript file from a public CDN and initializes it. The second file, `admin/config.yml`, is the heart of your Static CMS installation, and a bit more complex. The [Configuration](#configuration) section covers the details.
|
||||
The first file, `admin/index.html`, is the entry point for the Static CMS admin interface. This means that users navigate to `yoursite.com/admin/` to access it. On the code side, it is a basic HTML starter page that loads the Static CMS JavaScript file from a public CDN and initializes it. The second file, `admin/config.yml`, is the heart of your Static CMS installation, and a bit more complex. The [Configuration](#configuration) section covers the details.
|
||||
|
||||
In this example, we pull the `admin/index.html` file from a public CDN.
|
||||
|
||||
@ -62,11 +62,11 @@ In the code above the `script` is loaded from the `unpkg` CDN. Should there be a
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is different for every site, so we'll break it down into parts. Add all the code snippets in this section to your `admin/config.yml` file. Alternatively, you can use a javascript file (`admin/config.js`) instead of a yaml file. Simply import the javascript config and pass it into your `CMS.init({ config })` call.
|
||||
Configuration is different for every site, so we will break it down into parts. Add all the code snippets in this section to your `admin/config.yml` file. Alternatively, you can use a javascript file (`admin/config.js`) instead of a yaml file. Simply import the javascript config and pass it into your `CMS.init({ config })` call.
|
||||
|
||||
### Backend
|
||||
|
||||
We're using [Netlify](https://www.netlify.com) for our hosting and authentication in this tutorial, so backend configuration is fairly straightforward.
|
||||
We are using [Netlify](https://www.netlify.com) for our hosting and authentication in this tutorial, so backend configuration is fairly straightforward.
|
||||
|
||||
For GitHub repositories, you can start your Static CMS `config` file with these lines:
|
||||
|
||||
@ -88,7 +88,22 @@ backend: {
|
||||
|
||||
_(For GitLab repositories, use [GitLab backend](/docs/gitlab-backend) and for Bitbucket repositories, use [Bitbucket backend](/docs/bitbucket-backend).)_
|
||||
|
||||
The configuration above specifies your backend protocol and your publication branch. Git Gateway is an open source API that acts as a proxy between authenticated users of your site and your site repo. (We'll get to the details of that in the [Authentication section](#authentication) below.) If you leave out the `branch` declaration, it defaults to `main`.
|
||||
The configuration above specifies your backend protocol and your publication branch. Git Gateway is an open source API that acts as a proxy between authenticated users of your site and your site repo. (We will get to the details of that in the [Authentication section](#authentication) below.) If you leave out the `branch` declaration, it defaults to `main`.
|
||||
|
||||
### Editorial Workflow <BetaImage />
|
||||
|
||||
By default, saving a post in the CMS interface pushes a commit directly to the publication branch specified in `backend`. However, you also have the option to enable the [Editorial Workflow](/docs/editorial-workflow), which adds an interface for drafting, reviewing, and approving posts. To do this, add the following line to your `config.yml`:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
publish_mode: editorial_workflow
|
||||
```
|
||||
|
||||
```js
|
||||
publish_mode: 'editorial_workflow'
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### Media and Public Folders
|
||||
|
||||
@ -106,9 +121,9 @@ media_folder: 'images/uploads', // Media files will be stored in the repo under
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
If you're creating a new folder for uploaded media, you'll need to know where your static site generator expects static files. You can refer to the paths outlined above in [App File Structure](#app-file-structure), and put your media folder in the same location where you put the `admin` folder.
|
||||
If you are creating a new folder for uploaded media, you will need to know where your static site generator expects static files. You can refer to the paths outlined above in [App File Structure](#app-file-structure), and put your media folder in the same location where you put the `admin` folder.
|
||||
|
||||
Note that the `media_folder` file path is relative to the project root, so the example above would work for Jekyll, GitBook, or any other generator that stores static files at the project root. However, it would not work for Hugo, Next, Hexo, Middleman or others that store static files in a subfolder. Here's an example that could work for a Hugo site:
|
||||
Note that the `media_folder` file path is relative to the project root, so the example above would work for Jekyll, GitBook, or any other generator that stores static files at the project root. However, it would not work for Hugo, Next, Hexo, Middleman or others that store static files in a subfolder. Here is an example that could work for a Hugo site:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
@ -124,7 +139,7 @@ public_folder: '/images/uploads', // The src attribute for uploaded media will b
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
The configuration above adds a new setting, `public_folder`. While `media_folder` specifies where uploaded files are saved in the repo, `public_folder` indicates where they are found in the published site. Image `src` attributes use this path, which is relative to the file where it's called. For this reason, we usually start the path at the site root, using the opening `/`.
|
||||
The configuration above adds a new setting, `public_folder`. While `media_folder` specifies where uploaded files are saved in the repo, `public_folder` indicates where they are found in the published site. Image `src` attributes use this path, which is relative to the file where it is called. For this reason, we usually start the path at the site root, using the opening `/`.
|
||||
|
||||
_If `public_folder` is not set, Static CMS defaults to the same value as `media_folder`, adding an opening `/` if one is not included._
|
||||
|
||||
@ -132,7 +147,7 @@ _If `public_folder` is not set, Static CMS defaults to the same value as `media_
|
||||
|
||||
Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings differ greatly from one site to the next.
|
||||
|
||||
Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so:
|
||||
Let us say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so:
|
||||
|
||||
```yaml
|
||||
---
|
||||
@ -154,7 +169,7 @@ collections:
|
||||
label: 'Blog' # Used in the UI
|
||||
folder: '_posts/blog' # The path to the folder where the documents are stored
|
||||
create: true # Allow users to create new documents in this collection
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., yyyy-MM-dd-title.md
|
||||
fields: # The fields for each document, usually in front matter
|
||||
- { label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' }
|
||||
- { label: 'Title', name: 'title', widget: 'string' }
|
||||
@ -171,7 +186,7 @@ collections: [
|
||||
label: 'Blog', // Used in the UI
|
||||
folder: '_posts/blog', // The path to the folder where the documents are stored
|
||||
create: true, // Allow users to create new documents in this collection
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}', // Filename template, e.g., YYYY-MM-DD-title.md
|
||||
slug: '{{year}}-{{month}}-{{day}}-{{slug}}', // Filename template, e.g., yyyy-MM-dd-title.md
|
||||
fields: [
|
||||
// The fields for each document, usually in front matter
|
||||
{ label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' },
|
||||
@ -187,7 +202,7 @@ collections: [
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
Let's break that down:
|
||||
Let us break that down:
|
||||
|
||||
| Field | Description |
|
||||
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@ -244,7 +259,7 @@ collections: [
|
||||
|
||||
## Authentication
|
||||
|
||||
Now that you have your Static CMS files in place and configured, all that's left is to enable authentication. We're using the [Netlify](https://www.netlify.com/) platform here because it's one of the quickest ways to get started, but you can learn about other authentication options in the [Backends](/docs/backends-overview) doc.
|
||||
Now that you have your Static CMS files in place and configured, all that is left is to enable authentication. We are using the [Netlify](https://www.netlify.com/) platform here because it is one of the quickest ways to get started, but you can learn about other authentication options in the [Backends](/docs/backends-overview) doc.
|
||||
|
||||
### Setup on Netlify
|
||||
|
||||
@ -255,9 +270,9 @@ Netlify offers a built-in authentication service called Identity. In order to us
|
||||
Netlify's Identity and Git Gateway services allow you to manage CMS admin users for your site without requiring them to have an account with your Git host or commit access on your repo. From your site dashboard on Netlify:
|
||||
|
||||
1. Go to **Settings > Identity**, and select **Enable Identity service**.
|
||||
2. Under **Registration preferences**, select **Open** or **Invite only**. In most cases, you want only invited users to access your CMS, but if you're just experimenting, you can leave it open for convenience.
|
||||
2. Under **Registration preferences**, select **Open** or **Invite only**. In most cases, you want only invited users to access your CMS, but if you are just experimenting, you can leave it open for convenience.
|
||||
3. If you'd like to allow one-click login with services like Google and GitHub, check the boxes next to the services you'd like to use, under **External providers**.
|
||||
4. Scroll down to **Services > Git Gateway**, and click **Enable Git Gateway**. This authenticates with your Git host and generates an API access token. In this case, we're leaving the **Roles** field blank, which means any logged in user may access Static CMS. For information on changing this, check the [Netlify Identity documentation](https://www.netlify.com/docs/identity/).
|
||||
4. Scroll down to **Services > Git Gateway**, and click **Enable Git Gateway**. This authenticates with your Git host and generates an API access token. In this case, we are leaving the **Roles** field blank, which means any logged in user may access Static CMS. For information on changing this, check the [Netlify Identity documentation](https://www.netlify.com/docs/identity/).
|
||||
|
||||
### Add the Netlify Identity Widget
|
||||
|
||||
@ -267,7 +282,7 @@ With the backend set to handle authentication, now you need a frontend interface
|
||||
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
|
||||
```
|
||||
|
||||
Add this to the `<head>` of your CMS index page at `/admin/index.html`, as well as the `<head>` of your site's main index page. Depending on how your site generator is set up, this may mean you need to add it to the default template, or to a "partial" or "include" template. If you can find where the site stylesheet is linked, that's probably the right place. Alternatively, you can include the script in your site using Netlify's [Script Injection](https://www.netlify.com/docs/inject-analytics-snippets/) feature.
|
||||
Add this to the `<head>` of your CMS index page at `/admin/index.html`, as well as the `<head>` of your site's main index page. Depending on how your site generator is set up, this may mean you need to add it to the default template, or to a "partial" or "include" template. If you can find where the site stylesheet is linked, that is probably the right place. Alternatively, you can include the script in your site using Netlify's [Script Injection](https://www.netlify.com/docs/inject-analytics-snippets/) feature.
|
||||
|
||||
When a user logs in with the Netlify Identity widget, an access token directs to the site homepage. In order to complete the login and get back to Static CMS, redirect the user back to the `/admin/` path. To do this, add the following script before the closing `body` tag of your site's main index page:
|
||||
|
||||
@ -295,6 +310,6 @@ If you set your registration preference to "Invite only," invite yourself (and a
|
||||
|
||||
If you left your site registration open, or for return visits after confirming an email invitation, access your site's CMS at `yoursite.com/admin/`.
|
||||
|
||||
**Note:** No matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it always fetches and commits files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS `config` file. This means that content fetched in the admin UI matches the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI saves directly to the hosted repository, even if you're running the UI locally or in staging.
|
||||
**Note:** No matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it always fetches and commits files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS `config` file. This means that content fetched in the admin UI matches the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI saves directly to the hosted repository, even if you are running the UI locally or in staging.
|
||||
|
||||
Happy posting!
|
||||
|
@ -10,7 +10,7 @@ You can add Static CMS to your site in two different ways:
|
||||
|
||||
## CDN hosting
|
||||
|
||||
Adding Static CMS via a public CDN to a site that's built with a common static site generator, like Jekyll, Hugo, Hexo, or Gatsby. Alternatively, is a quick and easy way to get started. You can start from a [template](/docs/start-with-a-template) or use [this guide](/docs/add-to-your-site-cdn) to get started.
|
||||
Adding Static CMS via a public CDN to a site that is built with a common static site generator, like Jekyll, Hugo, Hexo, or Gatsby. Alternatively, is a quick and easy way to get started. You can start from a [template](/docs/start-with-a-template) or use [this guide](/docs/add-to-your-site-cdn) to get started.
|
||||
|
||||
## Bundling
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Custom Links & Pages
|
||||
weight: 60
|
||||
---
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to register external links or links custom pages, via `registerAdditionalLink`. The links are displayed at the bottom of the navigation menu in the order they are registered.
|
||||
Static CMS exposes a `window.CMS` global object that you can use to register external links or links custom pages, via `registerAdditionalLink`. The links are displayed at the bottom of the navigation menu in the order they are registered.
|
||||
|
||||
### React Components Inline
|
||||
|
||||
|
@ -10,15 +10,16 @@ A backend is JavaScript code that allows Static CMS to communicate with a servic
|
||||
|
||||
Individual backends provide their own configuration documentation, but there are some configuration options that are common to multiple backends. A full reference is below. Note that these are properties of the `backend` field, and should be nested under that field.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | 'git-gateway'<br />\| 'github'<br />\| 'gitlab'<br />\| 'bitbucket'<br />\| 'gitea'<br />\|'test-repo'<br />\| 'proxy' | | The backend git provider |
|
||||
| repo | string | | Required for `github`, `gitlab`, `gitea` and `bitbucket` backends. Ignored by `git-gateway`. Follows the pattern `[org-or-username]/[repo-name]` |
|
||||
| branch | string | `main` | _Optional_. The branch where published content is stored. All CMS commits and PRs are made to this branch |
|
||||
| api_root | string | GitHub<br />`https://api.github.com`<br /><br />GitLab<br/>`https://gitlab.com/api/v4`<br /><br />Bitbucket<br />`https://api.bitbucket.org/2.0`<br /><br />Gitea<br />`https://try.gitea.io/api/v1` | _Optional_. The API endpoint. Only necessary in certain cases, like with GitHub Enterprise or self-hosted GitLab |
|
||||
| site_domain | string | `location.hostname`<br /><br />On `localhost`<br />`cms.netlify.com` | _Optional_. Sets the `site_id` query param sent to the API endpoint. Non-Netlify auth setups will often need to set this for local development to work properly |
|
||||
| base_url | string | GitHub or Bitbucket<br />`https://api.netlify.com`<br /><br />GitLab<br />`https://gitlab.com`<br /><br />Gitea<br />`https://try.gitea.io` | _Optional_. OAuth client hostname (just the base domain, no path). **Required** when using an external OAuth server or self-hosted GitLab/Gitea |
|
||||
| auth_endpoint | string | GitHub or Bitbucket<br />`auth`<br /><br />GitLab<br />`oauth/authorize` | _Optional_. Path to append to `base_url` for authentication requests. |
|
||||
| Name | Type | Default | Description |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | 'git-gateway'<br />\| 'github'<br />\| 'gitlab'<br />\| 'bitbucket'<br />\| 'gitea'<br />\|'test-repo'<br />\| 'proxy' | | The backend git provider |
|
||||
| repo | string | | Required for `github`, `gitlab`, `gitea` and `bitbucket` backends. Ignored by `git-gateway`. Follows the pattern `[org-or-username]/[repo-name]` |
|
||||
| branch | string | `main` | _Optional_. The branch where published content is stored. All CMS commits and PRs are made to this branch |
|
||||
| api_root | string | GitHub<br />`https://api.github.com`<br /><br />GitLab<br/>`https://gitlab.com/api/v4`<br /><br />Bitbucket<br />`https://api.bitbucket.org/2.0`<br /><br />Gitea<br />`https://try.gitea.io/api/v1` | _Optional_. The API endpoint. Only necessary in certain cases, like with GitHub Enterprise or self-hosted GitLab |
|
||||
| site_domain | string | `location.hostname`<br /><br />On `localhost`<br />`cms.netlify.com` | _Optional_. Sets the `site_id` query param sent to the API endpoint. Non-Netlify auth setups will often need to set this for local development to work properly |
|
||||
| base_url | string | GitHub or Bitbucket<br />`https://api.netlify.com`<br /><br />GitLab<br />`https://gitlab.com`<br /><br />Gitea<br />`https://try.gitea.io` | _Optional_. OAuth client hostname (just the base domain, no path). **Required** when using an external OAuth server or self-hosted GitLab/Gitea |
|
||||
| auth_endpoint | string | GitHub or Bitbucket<br />`auth`<br /><br />GitLab<br />`oauth/authorize` | _Optional_. Path to append to `base_url` for authentication requests. |
|
||||
| cms_label_prefix | string | `cms/` | Pull (or Merge) Requests label prefix when using editorial workflow. Optional. |
|
||||
|
||||
## Creating a New Backend
|
||||
|
||||
|
@ -9,191 +9,22 @@ weight: 200
|
||||
fix the features as well as update the docs. Use at your own risk.
|
||||
</Alert>
|
||||
|
||||
Static CMS runs new functionality in an open beta format from time to time. That means that this functionality is totally available for use, an it might be ready for primetime, but it could break or change without notice.
|
||||
Static CMS runs new functionality in an open beta format from time to time. That means that this functionality is fully available for use, and it might be ready for primetime, but it could break or change without notice.
|
||||
|
||||
**Use these features at your own risk.**
|
||||
|
||||
## Folder Collections Path
|
||||
## Editorial Workflow
|
||||
|
||||
By default Static CMS stores folder collection content under the folder specified in the collection setting. You can now specify an additional `path` template (similar to the `slug` template) to control the content destination.
|
||||
By default, all entries created or edited in Static CMS are committed directly into the main repository branch.
|
||||
|
||||
This allows saving content in subfolders, e.g. configuring `path: '{{year}}/{{slug}}'` will save the content under `posts/2019/post-title.md`.
|
||||
The publish_mode option allows you to enable "Editorial Workflow" mode for more control over the content publishing phases. All unpublished entries will be arranged in a board according to their status, and they can be further reviewed and edited before going live.
|
||||
|
||||
See [Folder Collections Path](/docs/collection-types#folder-collections-path) for more information.
|
||||
See [Editorial Workflow](/docs/editorial-workflow) for more information.
|
||||
|
||||
## Nested Collections
|
||||
## Open Authoring
|
||||
|
||||
Nested collections is a beta feature that allows a folder collection to show a nested structure of entries and edit the locations of the entries. This feature is useful when you have a complex folder structure and may not want to create separate collections for every directory.
|
||||
When using the [GitHub backend](/docs/github-backend), you can use Static CMS to accept contributions from GitHub users without giving them access to your repository. When they make changes in the CMS, the CMS forks your repository for them behind the scenes, and all the changes are made to the fork. When the contributor is ready to submit their changes, they can set their draft as ready for review in the CMS. This triggers a pull request to your repository, which you can merge using the GitHub UI.
|
||||
|
||||
See [Nested Collections](/docs/collection-types#nested-collections) for more information.
|
||||
At the same time, any contributors who _do_ have write access to the repository can continue to use Static CMS normally.
|
||||
|
||||
## Image widget file size limit
|
||||
|
||||
You can set a limit to as what the maximum file size of a file is that users can upload directly into a image field.
|
||||
|
||||
See [Media Library](/docs/configuration-options#media-library) for more information.
|
||||
|
||||
## Media Library Folders
|
||||
|
||||
Adds support for viewing subfolders and creating new subfolders in the media library, under your configured `media_folder`.
|
||||
|
||||
See [Media Library](/docs/configuration-options#media-library) for more information.
|
||||
|
||||
## Summary string template transformations
|
||||
|
||||
You can apply transformations on fields in a summary string template using filter notation syntax.
|
||||
|
||||
Example config:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
collections:
|
||||
- name: 'posts'
|
||||
label: 'Posts'
|
||||
folder: '_posts'
|
||||
summary: "{{title | upper}} - {{date | date('YYYY-MM-DD')}} - {{body | truncate(20, '***')}}"
|
||||
fields:
|
||||
- { label: 'Title', name: 'title', widget: 'string' }
|
||||
- { label: 'Publish Date', name: 'date', widget: 'datetime' }
|
||||
- { label: 'Body', name: 'body', widget: 'markdown' }
|
||||
```
|
||||
|
||||
```js
|
||||
collections: [
|
||||
{
|
||||
name: 'posts',
|
||||
label: 'Posts',
|
||||
folder: '_posts',
|
||||
summary: "{{title | upper}} - {{date | date('YYYY-MM-DD')}} - {{body | truncate(20, '***')}}",
|
||||
fields: [
|
||||
{ label: 'Title', name: 'title', widget: 'string' },
|
||||
{ label: 'Publish Date', name: 'date', widget: 'datetime' },
|
||||
{ label: 'Body', name: 'body', widget: 'markdown' },
|
||||
],
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
The above config will transform the title field to uppercase and format the date field using `YYYY-MM-DD` format.
|
||||
Available transformations are `upper`, `lower`, `date('<format>')`, `default('defaultValue')`, `ternary('valueForTrue','valueForFalse')` and `truncate(<number>)`/`truncate(<number>, '<string>')`
|
||||
|
||||
## Registering to CMS Events
|
||||
|
||||
You can execute a function when a specific CMS event occurs. Supported events are `mounted`, `login`, `logout`, `change`, `preSave` and `postSave`.
|
||||
|
||||
### Mounted
|
||||
|
||||
The `mounted` event handler fires once the CMS is fully loaded.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'mounted',
|
||||
handler: () => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Login
|
||||
|
||||
The `login` event handler fires when a user logs into the CMS.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'login',
|
||||
handler: ({ author: { login, name } }) => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Logout
|
||||
|
||||
The `logout` event handler fires when a user logs out of the CMS.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'logout',
|
||||
handler: () => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Pre Save
|
||||
|
||||
The `preSave` event handler fires before the changes have been saved to your git backend, and can be used to modify the entry data like so:
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
collection: 'posts',
|
||||
handler: ({ data: { entry } }) => {
|
||||
return {
|
||||
...entry.data,
|
||||
title: 'new title',
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Post Save
|
||||
|
||||
The `postSave` event handler fires after the changes have been saved to your git backend.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'postSave',
|
||||
collection: 'posts',
|
||||
handler: ({ data: { entry } }) => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Change
|
||||
|
||||
The `change` event handler must provide a field name, and can be used to modify the entry data like so:
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
collection: 'posts',
|
||||
field: 'path.to.my.field',
|
||||
handler: ({ data, collection, field }) => {
|
||||
const currentValue = data.path.to.my.field;
|
||||
|
||||
return {
|
||||
...data,
|
||||
path: {
|
||||
...data.path,
|
||||
to: {
|
||||
...data.path.to,
|
||||
my: {
|
||||
...data.path.to.my,
|
||||
field: `new${currentValue}`
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## i18n Support
|
||||
|
||||
Static CMS can provide a side by side interface for authoring content in multiple languages. Configuring Static CMS for i18n support requires top level configuration, collection level configuration and field level configuration.
|
||||
|
||||
## Gitea Backend
|
||||
|
||||
For repositories stored on Gitea, the gitea backend allows CMS users to log in directly with their Gitea account. Note that all users must have push access to your content repository for this to work.
|
||||
|
||||
See [Gitea Backend](/docs/gitea-backend) for more information.
|
||||
|
||||
## Large Media Support
|
||||
|
||||
Netlify Large Media allows you to store your media files outside of your git backend. This is helpful if you are trying to store large media files.
|
||||
|
||||
See [Netlify Large Media](/docs/netlify-large-media) for more information.
|
||||
See [Open Authoring](/docs/open-authoring) for more information.
|
||||
|
288
packages/docs/content/docs/cms-events.mdx
Normal file
288
packages/docs/content/docs/cms-events.mdx
Normal file
@ -0,0 +1,288 @@
|
||||
---
|
||||
group: Customization
|
||||
title: Events Hooks
|
||||
weight: 110
|
||||
---
|
||||
|
||||
You can execute a function when a specific event occurs within Static CMSD.
|
||||
|
||||
Supported events are:
|
||||
|
||||
| Name | Description |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| [mounted](#mounted-event) | Event fires once Static CMS is fully loaded |
|
||||
| [login](#login-event) | Event fires when a user logs into Static CMS |
|
||||
| [logout](#logout-event) | Event fires when a user logs out of Static CMS |
|
||||
| [change](#change-event) | Event fires when a user changes the value of a field in the editor |
|
||||
| [preSave](#pre-save-event) | Event fires before the changes have been saved to your git backend |
|
||||
| [postSave](#post-save-event) | Event fires after the changes have been saved to your git backend |
|
||||
| [prePublish](#pre-publish-event) | _**Editorial Workflow ONLY**_. Event fires before the entry is "published", before the PR is merged into default branch |
|
||||
| [postPublish](#post-publish-event) | _**Editorial Workflow ONLY**_. Event fires after the entry is "published", after the PR is merged into default branch |
|
||||
|
||||
## Mounted Event
|
||||
|
||||
The `mounted` event handler fires once Static CMS is fully loaded.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'mounted',
|
||||
handler: () => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Login Event
|
||||
|
||||
The `login` event handler fires when a user logs into Static CMS.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'login',
|
||||
handler: ({ author: { login, name } }) => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Logout Event
|
||||
|
||||
The `logout` event handler fires when a user logs out of Static CMS.
|
||||
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'logout',
|
||||
handler: () => {
|
||||
// your code here
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Change Event
|
||||
|
||||
The `change` event handler fires when a user changes the value of a field in the editor. Event listeners for `change` can optionally provide collection, file and field names. They can also be used to modify the entry data.
|
||||
|
||||
```javascript
|
||||
// Listen for ALL change events
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all change events in a specific collection
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
collection: 'posts',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all change events in a specific file in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
collection: 'settings',
|
||||
file: 'global',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all change events in a specific field in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
collection: 'posts',
|
||||
// file: 'global', // You can specify a file if in a file collection
|
||||
field: 'path.to.my.field',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Alter the entry data when a specific field changes
|
||||
CMS.registerEventListener({
|
||||
name: 'change',
|
||||
collection: 'posts',
|
||||
// file: 'global', // You can specify a file if in a file collection
|
||||
field: 'path.to.my.field',
|
||||
handler: ({ data, collection, field }) => {
|
||||
const currentValue = data.path.to.my.field;
|
||||
|
||||
return {
|
||||
...data,
|
||||
path: {
|
||||
...data.path,
|
||||
to: {
|
||||
...data.path.to,
|
||||
my: {
|
||||
...data.path.to.my,
|
||||
field: `new${currentValue}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Pre Save Event
|
||||
|
||||
The `preSave` event handler fires before the changes have been saved to your git backend, and can be used to modify the entry data.
|
||||
|
||||
```javascript
|
||||
// Listen for ALL preSave events
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all preSave events in a specific collection
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
collection: 'posts',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all preSave events in a specific file in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
collection: 'settings',
|
||||
file: 'global',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Alter the entry data
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
collection: 'posts',
|
||||
// file: 'global', // You can specify a file if in a file collection
|
||||
handler: ({ data, collection, field }) => {
|
||||
const currentValue = data.path.to.my.field;
|
||||
|
||||
return {
|
||||
...data,
|
||||
path: {
|
||||
...data.path,
|
||||
to: {
|
||||
...data.path.to,
|
||||
my: {
|
||||
...data.path.to.my,
|
||||
field: `new${currentValue}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Post Save Event
|
||||
|
||||
The `postSave` event handler fires after the changes have been saved to your git backend.
|
||||
|
||||
```javascript
|
||||
// Listen for ALL postSave events
|
||||
CMS.registerEventListener({
|
||||
name: 'postSave',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all postSave events in a specific collection
|
||||
CMS.registerEventListener({
|
||||
name: 'postSave',
|
||||
collection: 'posts',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all postSave events in a specific file in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'postSave',
|
||||
collection: 'settings',
|
||||
file: 'global',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Pre Publish Event
|
||||
|
||||
<Alert severity="info">Editorial Workflow ONLY</Alert>
|
||||
|
||||
The `prePublish` event handler fires before the entry is "published", before the PR is merged into default branch.
|
||||
|
||||
```javascript
|
||||
// Listen for ALL prePublish events
|
||||
CMS.registerEventListener({
|
||||
name: 'prePublish',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all prePublish events in a specific collection
|
||||
CMS.registerEventListener({
|
||||
name: 'prePublish',
|
||||
collection: 'posts',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all prePublish events in a specific file in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'prePublish',
|
||||
collection: 'settings',
|
||||
file: 'global',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Post Publish Event
|
||||
|
||||
<Alert severity="info">Editorial Workflow ONLY</Alert>
|
||||
|
||||
The `postPublish` event handler fires after the entry is "published", after the PR is merged into default branch.
|
||||
|
||||
```javascript
|
||||
// Listen for ALL postPublish events
|
||||
CMS.registerEventListener({
|
||||
name: 'postPublish',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all postPublish events in a specific collection
|
||||
CMS.registerEventListener({
|
||||
name: 'postPublish',
|
||||
collection: 'posts',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for all postPublish events in a specific file in a collection
|
||||
CMS.registerEventListener({
|
||||
name: 'postPublish',
|
||||
collection: 'settings',
|
||||
file: 'global',
|
||||
handler: ({ data, collection, field }) => {
|
||||
// Your handler code
|
||||
},
|
||||
});
|
||||
```
|
@ -17,6 +17,7 @@ weight: 9
|
||||
| files or folder | [Collection Files](/docs/collection-types#file-collections)<br />\| [Collection Folder](/docs/collection-types#folder-collections) | | **Requires one of these**: Specifies the collection type and location; details in [collection types](/docs/collection-types) |
|
||||
| filter | FilterRule<br />\| List of FilterRules | | _Optional_. Field and file filter for [Folder Collections](/docs/collection-types#folder-collections). See [filtered folder collections](/docs/collection-types#filtered-folder-collections) |
|
||||
| create | boolean | `false` | _Optional_. **For [Folder Collections](/docs/collection-types#folder-collections) only**<br />`true` - Allows users to create new items in the collection |
|
||||
| publish | boolean | `true` | _Optional_ For `publish_mode: editorial_workflow` only;<br />`false` hides UI publishing controls for a collection |
|
||||
| hide | boolean | `false` | _Optional_. `true` hides a collection in the Static CMS UI. Useful when using the relation widget to hide referenced collections |
|
||||
| delete | boolean | `true` | _Optional_. `false` prevents users from deleting items in a collection |
|
||||
| extension | string | | _Optional_. See [extension and format](#extension-and-format) below |
|
||||
@ -66,7 +67,7 @@ You may also specify a custom `extension` not included in the list above, as lon
|
||||
- `yml` or `yaml`: parses and saves files as YAML-formatted data files; saves with `yml` extension by default
|
||||
- `json`: parses and saves files as JSON-formatted data files; saves with `json` extension by default
|
||||
- `toml`: parses and saves files as TOML-formatted data files; saves with `toml` extension by default
|
||||
- `frontmatter`: parses files and saves files with data frontmatter followed by an unparsed body text (edited using a `body` field); saves with `md` extension by default; default for collections that can't be inferred. Collections with `frontmatter` format (either inferred or explicitly set) can parse files with frontmatter in YAML or JSON format. However, they will be saved with YAML frontmatter.
|
||||
- `frontmatter`: parses files and saves files with data frontmatter followed by an unparsed body text (edited using a `body` field); saves with `md` extension by default; default for collections that cannot be inferred. Collections with `frontmatter` format (either inferred or explicitly set) can parse files with frontmatter in YAML or JSON format. However, they will be saved with YAML frontmatter.
|
||||
- `yaml-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved only as YAML, followed by unparsed body text. The default delimiter for this option is `---`.
|
||||
- `json-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved as JSON, followed by unparsed body text. The default delimiter for this option is `{` `}`.
|
||||
- `toml-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved only as TOML, followed by unparsed body text. The default delimiter for this option is `+++`.
|
||||
@ -219,6 +220,55 @@ summary: 'Version: {{version}} - {{title}}',
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### Template Transformations
|
||||
|
||||
You can apply transformations on fields in a summary string template using filter notation syntax.
|
||||
|
||||
Example config:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
collections:
|
||||
- name: 'posts'
|
||||
label: 'Posts'
|
||||
folder: '_posts'
|
||||
summary: "{{title | upper}} - {{date | date('yyyy-MM-dd')}} - {{body | truncate(20, '***')}}"
|
||||
fields:
|
||||
- { label: 'Title', name: 'title', widget: 'string' }
|
||||
- { label: 'Publish Date', name: 'date', widget: 'datetime' }
|
||||
- { label: 'Body', name: 'body', widget: 'markdown' }
|
||||
```
|
||||
|
||||
```js
|
||||
collections: [
|
||||
{
|
||||
name: 'posts',
|
||||
label: 'Posts',
|
||||
folder: '_posts',
|
||||
summary: "{{title | upper}} - {{date | date('yyyy-MM-dd')}} - {{body | truncate(20, '***')}}",
|
||||
fields: [
|
||||
{ label: 'Title', name: 'title', widget: 'string' },
|
||||
{ label: 'Publish Date', name: 'date', widget: 'datetime' },
|
||||
{ label: 'Body', name: 'body', widget: 'markdown' },
|
||||
],
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
The above config will transform the title field to uppercase and format the date field using `yyyy-MM-dd` format.
|
||||
Available transformations are:
|
||||
|
||||
| Name | Format | Description |
|
||||
| -------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| upper | `upper` | Transforms the value to uppercase |
|
||||
| lower | `lower` | Transforms the value to lowercase |
|
||||
| date | `date('<format>')` | Formats a date string in the provided format. Accepts [date-fns tokens](https://date-fns.org/docs/format) |
|
||||
| default | `default('defaultValue')` | Provides default value if no field value |
|
||||
| ternary | `ternary('valueForTrue','valueForFalse')` | <ul><li>If field has value, show `valueForTrue`</li><li>If field does not have a value, show `valueForFalse`</li></ul> |
|
||||
| truncate | `truncate(<number>)`<br />`truncate(<number>, '<string>')` | Truncates text to a specified length. An optional replacement string for the omitted text can be provided as a second parameter |
|
||||
|
||||
## Sortable Fields
|
||||
|
||||
The `sortable_fields` setting is an optional object with the following options:
|
||||
@ -230,7 +280,7 @@ The `sortable_fields` setting is an optional object with the following options:
|
||||
|
||||
Defaults to inferring `title`, `date`, `author` and `description` fields and will also show `Update On` sort field in git based backends.
|
||||
|
||||
When `author` field can't be inferred commit author will be used.
|
||||
When `author` field cannot be inferred commit author will be used.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
@ -280,79 +330,122 @@ sortable_fields: {
|
||||
|
||||
## View Filters
|
||||
|
||||
The `view_filters` setting is an optional list of predefined view filters to show in the UI.
|
||||
|
||||
Defaults to an empty list.
|
||||
The `view_filters` setting is an optional property which takes a list of predefined view filters to show in the UI and an optional default view filter.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_filters:
|
||||
- label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
default: drafts
|
||||
filters:
|
||||
- name: alice-and-bob
|
||||
label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- name: posts-2020
|
||||
label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
```
|
||||
|
||||
```js
|
||||
view_filters: [
|
||||
{
|
||||
label: "Alice's and Bob's Posts",
|
||||
field: 'author',
|
||||
pattern: 'Alice|Bob',
|
||||
},
|
||||
{
|
||||
label: 'Posts published in 2020',
|
||||
field: 'date',
|
||||
pattern: '2020',
|
||||
},
|
||||
{
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
pattern: true,
|
||||
},
|
||||
],
|
||||
view_filters: {
|
||||
default: 'drafts',
|
||||
filters: [
|
||||
{
|
||||
name: 'alice-and-bob',
|
||||
label: "Alice's and Bob's Posts",
|
||||
field: 'author',
|
||||
pattern: 'Alice|Bob',
|
||||
},
|
||||
{
|
||||
name: 'posts-2020',
|
||||
label: 'Posts published in 2020',
|
||||
field: 'date',
|
||||
pattern: '2020',
|
||||
},
|
||||
{
|
||||
name: 'drafts',
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
pattern: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## View Groups
|
||||
|
||||
The `view_groups` setting is an optional list of predefined view groups to show in the UI.
|
||||
|
||||
Defaults to an empty list.
|
||||
The `view_groups` setting is an optional property which takes a list of predefined view groups to show in the UI and an optional default view group.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_groups:
|
||||
- label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- label: Drafts
|
||||
field: draft
|
||||
default: by-year
|
||||
groups:
|
||||
- name: by-year
|
||||
label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
```
|
||||
|
||||
```js
|
||||
view_groups: [
|
||||
{
|
||||
label: 'Year',
|
||||
field: 'date',
|
||||
pattern: '\\d{4}',
|
||||
},
|
||||
{
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
},
|
||||
],
|
||||
view_groups: {
|
||||
default: by-year
|
||||
groups: [
|
||||
{
|
||||
name: 'by-year',
|
||||
label: 'Year',
|
||||
field: 'date',
|
||||
pattern: '\\d{4}',
|
||||
},
|
||||
{
|
||||
name: 'drafts',
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
},
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Media Library
|
||||
|
||||
The `media_library` settings allows customization of the media library at the collection level. See [Media Library](/docs/configuration-options#media-library) for more details.
|
||||
The `media_library` settings allows customization of the media library at the collection level.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --------------------- | ------- | -------- | -------------------------------------------------------------------------------------- |
|
||||
| max_file_size | number | `512000` | _Optional_. The max size, in bytes, of files that can be uploaded to the media library |
|
||||
| folder_support | boolean | `false` | _Optional_. Enables directory navigation and folder creation in your media library |
|
||||
|
||||
### Example
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
media_library:
|
||||
max_file_size: 512000
|
||||
folder_support: true
|
||||
```
|
||||
|
||||
```js
|
||||
{
|
||||
media_library: {
|
||||
max_file_size: 512000,
|
||||
folder_support: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
@ -471,7 +471,7 @@ collections: [
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### Folder Collections Path <BetaImage />
|
||||
### Folder Collections Path
|
||||
|
||||
By default Static CMS stores folder collection content under the folder specified in the collection setting.
|
||||
|
||||
@ -577,9 +577,9 @@ Supports all of the [`slug` templates](/docs/configuration-options#slug) and:
|
||||
- `{{media_folder}}` The global `media_folder`.
|
||||
- `{{public_folder}}` The global `public_folder`.
|
||||
|
||||
### Nested Collections <BetaImage />
|
||||
### Nested Collections
|
||||
|
||||
Nested collections is a beta feature that allows a folder collection to show a nested structure of entries and edit the locations of the entries. This feature is useful when you have a complex folder structure and may not want to create separate collections for every directory.
|
||||
Nested collections allow a folder collection to show a nested structure of entries and edit the locations of the entries. This feature is useful when you have a complex folder structure and may not want to create separate collections for every directory.
|
||||
|
||||
Example configuration:
|
||||
|
||||
|
@ -25,7 +25,7 @@ _This setting is required._
|
||||
|
||||
The `backend` option specifies how to access the content for your site, including authentication. Full details and code samples can be found in [Backends](/docs/backends-overview).
|
||||
|
||||
**Note**: no matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it will always fetch and commit files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS config file. This means that content fetched in the admin UI will match the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI will save directly to the hosted repository, even if you're running the UI locally or in staging. If you want to have your local CMS write to a local repository, [try the local_backend setting](/docs/local-backend).
|
||||
**Note**: no matter where you access Static CMS — whether running locally, in a staging environment, or in your published site — it will always fetch and commit files in your hosted repository (for example, on GitHub), on the branch you configured in your Static CMS config file. This means that content fetched in the admin UI will match the content in the repository, which may be different from your locally running site. It also means that content saved using the admin UI will save directly to the hosted repository, even if you are running the UI locally or in staging. If you want to have your local CMS write to a local repository, [try the local_backend setting](/docs/local-backend).
|
||||
|
||||
### Commit Message Templates
|
||||
|
||||
@ -44,6 +44,7 @@ backend:
|
||||
delete: Delete {{collection}} "{{slug}}"
|
||||
uploadMedia: Upload "{{path}}"
|
||||
deleteMedia: Delete "{{path}}"
|
||||
openAuthoring: "{{message}}"
|
||||
```
|
||||
|
||||
```js
|
||||
@ -54,6 +55,7 @@ backend: {
|
||||
delete: 'Delete {{collection}} "{{slug}}"',
|
||||
uploadMedia: 'Upload "{{path}}"',
|
||||
deleteMedia: 'Delete "{{path}}"',
|
||||
openAuthoring: '"{{message}}"'
|
||||
},
|
||||
},
|
||||
```
|
||||
@ -82,6 +84,14 @@ Template tags produce the following output:
|
||||
- `{{author-login}}`: login/username of the author
|
||||
- `{{author-name}}`: full name of the author (might be empty based on the user's profile)
|
||||
|
||||
## Publish Mode
|
||||
|
||||
By default, all entries created or edited in Static CMS are committed directly into the main repository branch.
|
||||
|
||||
The `publish_mode` option allows you to enable "Editorial Workflow" mode for more control over the content publishing phases. All unpublished entries will be arranged on a dashboard according to their status, and they can be further reviewed and edited before going live.
|
||||
|
||||
See [Editorial Workflow](/docs/editorial-workflow) for more information.
|
||||
|
||||
## Media and Public Folders
|
||||
|
||||
Static CMS users can upload files to your repository using the Media Gallery. The following settings specify where these files are saved, and where they can be accessed on your built site.
|
||||
@ -122,16 +132,17 @@ Based on the settings above, if a user used an image widget field called `avatar
|
||||
|
||||
This setting can be set to an absolute URL e.g. `https://netlify.com/media` should you wish, however in general this is not advisable as content should have relative paths to other content.
|
||||
|
||||
## Media Library <BetaImage />
|
||||
## Media Library
|
||||
|
||||
The `media_library` settings allows customization of the media library.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| -------------- | ------- | -------- | -------------------------------------------------------------------------------------- |
|
||||
| max_file_size | number | `512000` | _Optional_. <BetaImage /> The max size, in bytes, of files that can be uploaded to the media library |
|
||||
| folder_support | boolean | `false` | _Optional_. <BetaImage /> Enables directory navigation and folder creation in your media library |
|
||||
| Name | Type | Default | Description |
|
||||
| --------------------- | ------- | -------- | -------------------------------------------------------------------------------------- |
|
||||
| max_file_size | number | `512000` | _Optional_. The max size, in bytes, of files that can be uploaded to the media library |
|
||||
| folder_support | boolean | `false` | _Optional_. Enables directory navigation and folder creation in your media library |
|
||||
| display_in_navigation | boolean | `true` | _Optional_. Displays the "Media" link in the main navigation |
|
||||
|
||||
### Example
|
||||
|
||||
@ -293,4 +304,34 @@ The `collections` setting is the heart of your Static CMS configuration, as it d
|
||||
|
||||
## Disable Local Backup
|
||||
|
||||
When the `disable_local_backup` setting is set to `true` local backups will no be taken for your entries and you will not be prompted to load local backups.
|
||||
When the `disable_local_backup` setting is set to `true` local backups will no be taken for your entries.
|
||||
|
||||
## YAML Options
|
||||
|
||||
The YAML format parsing and stringifing can be customized via the `yaml` setting. Available options can be found in the [yaml docs](https://eemeli.org/yaml/#options),
|
||||
|
||||
| Setting | Docs |
|
||||
| ----------------- | ------------------------------------------- |
|
||||
| parseOptions | https://eemeli.org/yaml/#parse-options |
|
||||
| documentOptions | https://eemeli.org/yaml/#document-options |
|
||||
| schemaOptions | https://eemeli.org/yaml/#schema-options |
|
||||
| createNodeOptions | https://eemeli.org/yaml/#createnode-options |
|
||||
| toJsOptions | https://eemeli.org/yaml/#tojs-options |
|
||||
| toStringOptions | https://eemeli.org/yaml/#tostring-options |
|
||||
|
||||
**Example**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
yaml:
|
||||
toStringOptions:
|
||||
indentSeq: false
|
||||
```
|
||||
|
||||
```js
|
||||
yaml: {
|
||||
toStringOptions: { indentSeq: false },
|
||||
},
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
@ -4,7 +4,7 @@ title: Contributor Guide
|
||||
weight: 20
|
||||
---
|
||||
|
||||
We're hoping that Static CMS will do for the [Jamstack](https://www.jamstack.org) what WordPress did for dynamic sites back in the day. We know we can't do that without building a thriving community of contributors and users, and we'd love to have you join us.
|
||||
We are hoping that Static CMS will do for the [Jamstack](https://www.jamstack.org) what WordPress did for dynamic sites back in the day. We know we cannot do that without building a thriving community of contributors and users, and we would love to have you join us.
|
||||
|
||||
## Getting started with contributing
|
||||
Being a developer is not a requirement for contributing to Static CMS, you only need the desire, a web browser, and a [GitHub account](https://github.com/join). The GitHub repo has a step-by-step [guide](https://github.com/StaticJsCMS/static-cms/blob/main/CONTRIBUTING.md) to get started with the code.
|
||||
@ -18,12 +18,12 @@ The GitHub website allows you to submit issues, work with files, search for cont
|
||||
A [style guide](/docs/writing-style-guide/) is available to help provide context around grammar, code styling, syntax, etc.
|
||||
|
||||
## Filing issues
|
||||
If you have a GitHub account, you can file an [issue](https://github.com/StaticJsCMS/static-cms/issues) (aka bug report) against the Static CMS docs. Even if you're not able to, or don't know how to, fix the issue (see [Improve existing content](#improve-existing-content)), it helps to start the conversation.
|
||||
If you have a GitHub account, you can file an [issue](https://github.com/StaticJsCMS/static-cms/issues) (aka bug report) against the Static CMS docs. Even if you are not able to, or do not know how to, fix the issue (see [Improve existing content](#improve-existing-content)), it helps to start the conversation.
|
||||
|
||||
When filing an issue, it is important to remember the [Code of Conduct](https://github.com/StaticJsCMS/static-cms/blob/main/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Improve existing content
|
||||
If you are able to offer up a change to existing content, it is welcome. Once you've forked the repo, and changed the content, you would file a pull request (PR). The repo [Contributing file](https://github.com/StaticJsCMS/static-cms/blob/main/CONTRIBUTING.md) lays out the correct format for PRs.
|
||||
If you are able to offer up a change to existing content, it is welcome. Once you have forked the repo, and changed the content, you would file a pull request (PR). The repo [Contributing file](https://github.com/StaticJsCMS/static-cms/blob/main/CONTRIBUTING.md) lays out the correct format for PRs.
|
||||
|
||||
## Other places to get involved
|
||||
Here are some links with more information about getting involved:
|
||||
|
@ -4,7 +4,7 @@ title: Adding Custom Icons
|
||||
weight: 100
|
||||
---
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to register custom icons via `registerIcon`. The same object is also the default export if you import Static CMS as an npm module.
|
||||
Static CMS exposes a `window.CMS` global object that you can use to register custom icons via `registerIcon`. The same object is also the default export if you import Static CMS as an npm module.
|
||||
|
||||
Custom icons can be used with [Collections](/docs/collection-overview) or [Custom Links & Pages](/docs/additional-links)
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Creating Custom Previews
|
||||
weight: 50
|
||||
---
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to register custom previews for an entire collection (or file within a file collection) via `registerPreviewTemplate` (editor view) and `registerPreviewCard` / `registerFieldPreview` (collection view).
|
||||
Static CMS exposes a `window.CMS` global object that you can use to register custom previews for an entire collection (or file within a file collection) via `registerPreviewTemplate` (editor view) and `registerPreviewCard` / `registerFieldPreview` (collection view).
|
||||
|
||||
### React Components Inline
|
||||
|
||||
@ -34,7 +34,6 @@ The following parameters will be passed to your `react_component` during render:
|
||||
| window | Window | The window object the preview is within. If rendered with a frame, it will be the frame's window |
|
||||
| widgetFor | Function | Given a field name, returns the rendered preview of that field's widget and value |
|
||||
| widgetsFor | Function | Given a field name, returns the rendered previews of that field's nested child widgets and values |
|
||||
| theme | 'light'<br />\| 'dark' | The current theme being used by the app |
|
||||
|
||||
#### Example
|
||||
|
||||
@ -352,7 +351,6 @@ The following parameters will be passed to your `react_component` during render:
|
||||
| entry | object | Object with a `data` field that contains the current value of all widgets in the editor |
|
||||
| widgetFor | Function | Given a field name, returns the rendered preview of that field's widget and value |
|
||||
| widgetsFor | Function | Given a field name, returns the rendered previews of that field's nested child widgets and values |
|
||||
| theme | 'light'<br />\| 'dark' | The current theme being used by the app |
|
||||
| hasLocalBackup | boolean | Whether the current entry has a local backup |
|
||||
|
||||
#### Example
|
||||
@ -478,7 +476,9 @@ import type { TemplatePreviewCardProps } from '@staticcms/core';
|
||||
interface Post {
|
||||
image: string;
|
||||
title: string;
|
||||
date: string;
|
||||
body: string;
|
||||
draft: boolean;
|
||||
}
|
||||
|
||||
const PostPreviewCard = ({ entry, widgetFor }: TemplatePreviewCardProps<Post>) => {
|
||||
@ -502,12 +502,12 @@ const PostPreviewCard = ({ entry, widgetFor }: TemplatePreviewCardProps<Post>) =
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<strong style={{ fontSize: '24px' }}>{entry.data.title}</strong>
|
||||
<span style={{ fontSize: '16px' }}>{entry.data.date}</span>
|
||||
<strong style={{ fontSize: '24px' }}>{entry.data?.title}</strong>
|
||||
<span style={{ fontSize: '16px' }}>{entry.data?.date}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: entry.data.draft === true ? 'blue' : 'green',
|
||||
backgroundColor: entry.data?.draft === true ? 'blue' : 'green',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '4px 8px',
|
||||
@ -518,7 +518,7 @@ const PostPreviewCard = ({ entry, widgetFor }: TemplatePreviewCardProps<Post>) =
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
>
|
||||
{entry.data.draft === true ? 'Draft' : 'Published'}
|
||||
{entry.data?.draft === true ? 'Draft' : 'Published'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -554,7 +554,6 @@ The following parameters will be passed to your `component` during render:
|
||||
| collection | object | Collection configuration |
|
||||
| field | object | Field configuration |
|
||||
| value | Function | The current value of the field for the given entry |
|
||||
| theme | 'light'<br />\| 'dark' | The current theme being used by the app |
|
||||
|
||||
#### Example
|
||||
|
||||
|
471
packages/docs/content/docs/custom-theme.mdx
Normal file
471
packages/docs/content/docs/custom-theme.mdx
Normal file
@ -0,0 +1,471 @@
|
||||
---
|
||||
group: Customization
|
||||
title: Theming
|
||||
weight: 30
|
||||
---
|
||||
|
||||
Static CMS comes with two default themes (`light` and `dark`), and you can add your own custom themes as well.
|
||||
|
||||
Static CMS exposes a `window.CMS` global object that you can use to register custom themes via `registerTheme`. The same object is also the default export if you import Static CMS as an npm module.
|
||||
|
||||
## Register Theme
|
||||
|
||||
Register a custom theme.
|
||||
|
||||
<CodeTabs>
|
||||
|
||||
```js
|
||||
const theme = {
|
||||
name: 'Custom Dark',
|
||||
text: {
|
||||
primary: '#fff',
|
||||
secondary: 'rgba(255, 255, 255, 0.7)',
|
||||
disabled: 'rgba(255, 255, 255, 0.5)',
|
||||
},
|
||||
background: {
|
||||
main: '#1e293b',
|
||||
light: '#2c3b55',
|
||||
dark: '#0f172a',
|
||||
divider: '#2c3b55',
|
||||
},
|
||||
scrollbar: {
|
||||
main: '#1e293b',
|
||||
light: '#2c3b55',
|
||||
},
|
||||
button: {
|
||||
disabled: '#334155',
|
||||
},
|
||||
primary: {
|
||||
main: '#339ef4',
|
||||
light: '#6bb9f7',
|
||||
dark: '#0c82e0',
|
||||
contrastColor: '#ffffff',
|
||||
},
|
||||
error: {
|
||||
main: '#f44336',
|
||||
light: '#e57373',
|
||||
dark: '#d32f2f',
|
||||
contrastColor: '#ffffff',
|
||||
},
|
||||
warning: {
|
||||
main: '#ffa726',
|
||||
light: '#ffb74d',
|
||||
dark: '#f57c00',
|
||||
contrastColor: '#ffffff',
|
||||
},
|
||||
info: {
|
||||
main: '#29b6f6',
|
||||
light: '#4fc3f7',
|
||||
dark: '#0288d1',
|
||||
contrastColor: '#ffffff',
|
||||
},
|
||||
success: {
|
||||
main: '#66bb6a',
|
||||
light: '#81c784',
|
||||
dark: '#388e3c',
|
||||
contrastColor: '#ffffff',
|
||||
},
|
||||
codemirror: {
|
||||
theme: 'dark',
|
||||
},
|
||||
};
|
||||
|
||||
// Using global window object
|
||||
CMS.registerTheme(theme);
|
||||
|
||||
// Using npm module import
|
||||
import CMS from '@staticcms/core';
|
||||
|
||||
CMS.registerTheme(theme);
|
||||
```
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
themes:
|
||||
- name: Custom Dark
|
||||
text:
|
||||
primary: '#fff'
|
||||
secondary: 'rgba(255, 255, 255, 0.7)'
|
||||
disabled: 'rgba(255, 255, 255, 0.5)'
|
||||
background:
|
||||
main: '#1e293b'
|
||||
light: '#2c3b55'
|
||||
dark: '#0f172a'
|
||||
divider: '#2c3b55'
|
||||
scrollbar:
|
||||
main: '#1e293b'
|
||||
light: '#2c3b55'
|
||||
button:
|
||||
disabled: '#334155'
|
||||
primary:
|
||||
main: '#339ef4'
|
||||
light: '#6bb9f7'
|
||||
dark: '#0c82e0'
|
||||
contrastColor: '#ffffff'
|
||||
error:
|
||||
main: '#f44336'
|
||||
light: '#e57373'
|
||||
dark: '#d32f2f'
|
||||
contrastColor: '#ffffff'
|
||||
warning:
|
||||
main: '#ffa726'
|
||||
light: '#ffb74d'
|
||||
dark: '#f57c00'
|
||||
contrastColor: '#ffffff'
|
||||
info:
|
||||
main: '#29b6f6'
|
||||
light: '#4fc3f7'
|
||||
dark: '#0288d1'
|
||||
contrastColor: '#ffffff'
|
||||
success:
|
||||
main: '#66bb6a'
|
||||
light: '#81c784'
|
||||
dark: '#388e3c'
|
||||
contrastColor: '#ffffff'
|
||||
codemirror:
|
||||
theme: dark
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Extend Built-in Themes
|
||||
|
||||
Extend either the `light` or `dark` themes.
|
||||
|
||||
<CodeTabs>
|
||||
|
||||
```js
|
||||
// Using global window object
|
||||
CMS.registerTheme({
|
||||
name: 'Red Orange',
|
||||
extends: 'dark',
|
||||
primary: {
|
||||
main: '#ff4500',
|
||||
},
|
||||
});
|
||||
|
||||
// Using npm module import
|
||||
import CMS from '@staticcms/core';
|
||||
|
||||
CMS.registerTheme({
|
||||
name: 'Red Orange',
|
||||
extends: 'dark',
|
||||
primary: {
|
||||
main: '#ff4500',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
themes:
|
||||
- name: Red Orange
|
||||
extends: dark
|
||||
primary:
|
||||
main: '#ff4500'
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Set Default Theme
|
||||
|
||||
By default `light` is the main theme (or `dark` if the user's system is set to dark mode). `default_theme` allows you to change that.
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
default_theme: false
|
||||
themes:
|
||||
# Can also be registered via javascript
|
||||
- name: Red Orange
|
||||
extends: dark
|
||||
primary:
|
||||
main: '#ff4500'
|
||||
```
|
||||
|
||||
## Hide Built-in themes
|
||||
|
||||
By default both a `light` and `dark` them are available. However, if you provide at least one custom theme, `include_built_in_themes` allows you to disable the built-in themes.
|
||||
|
||||
If `default_theme` is not provided, then the first custom theme is used (when `include_built_in_themes` is `false`).
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
include_built_in_themes: false
|
||||
themes:
|
||||
# Can also be registered via javascript
|
||||
- name: Red Orange
|
||||
extends: dark
|
||||
primary:
|
||||
main: '#ff4500'
|
||||
```
|
||||
|
||||
## useTheme Hook
|
||||
|
||||
The `useTheme` hook can be utilized in customize widgets and previews to utilize values from the theme.
|
||||
|
||||
### Example Preview Card
|
||||
|
||||
<CodeTabs>
|
||||
|
||||
```js
|
||||
const PostPreviewCard = ({ entry, widgetFor }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{ style: { width: '100%' } },
|
||||
widgetFor('image'),
|
||||
h(
|
||||
'div',
|
||||
{ style: { padding: '16px', width: '100%' } },
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'start',
|
||||
},
|
||||
},
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'baseline',
|
||||
gap: '8px',
|
||||
},
|
||||
},
|
||||
h('strong', { style: { fontSize: '24px' } }, entry.data.title),
|
||||
h('span', { style: { fontSize: '16px' } }, entry.data.date),
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
backgroundColor: entry.data.draft === true
|
||||
? theme.info.main
|
||||
: theme.success.main,
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '4px 8px',
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
display: 'inline-block',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '4px',
|
||||
},
|
||||
},
|
||||
entry.data.draft === true ? 'Draft' : 'Published',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
CMS.registerPreviewCard('posts', PostPreviewCard, () => 240);
|
||||
```
|
||||
|
||||
```jsx
|
||||
import CMS from '@staticcms/core';
|
||||
|
||||
const PostPreviewCard = ({ entry, widgetFor }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
{widgetFor('image')}
|
||||
<div style={{ padding: '16px', width: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'start',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'baseline',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<strong style={{ fontSize: '24px' }}>{entry.data.title}</strong>
|
||||
<span style={{ fontSize: '16px' }}>{entry.data.date}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: entry.data.draft === true
|
||||
? theme.info.main
|
||||
: theme.success.main,
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '4px 8px',
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
display: 'inline-block',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
>
|
||||
{entry.data.draft === true ? 'Draft' : 'Published'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CMS.registerPreviewCard('posts', PostPreviewCard, () => 240);
|
||||
```
|
||||
|
||||
```tsx
|
||||
import CMS, { useTheme } from '@staticcms/core';
|
||||
|
||||
import type { TemplatePreviewCardProps } from '@staticcms/core';
|
||||
|
||||
/**
|
||||
* The type for 'entry.data'
|
||||
*/
|
||||
interface Post {
|
||||
image: string;
|
||||
title: string;
|
||||
date: string;
|
||||
body: string;
|
||||
draft: boolean;
|
||||
}
|
||||
|
||||
const PostPreviewCard = ({ entry, widgetFor }: TemplatePreviewCardProps<Post>) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
{widgetFor('image')}
|
||||
<div style={{ padding: '16px', width: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'start',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'baseline',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<strong style={{ fontSize: '24px' }}>{entry.data?.title}</strong>
|
||||
<span style={{ fontSize: '16px' }}>{entry.data?.date}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: entry.data?.draft === true
|
||||
? theme.info.main
|
||||
: theme.success.main,
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '4px 8px',
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
display: 'inline-block',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
>
|
||||
{entry.data?.draft === true ? 'Draft' : 'Published'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CMS.registerPreviewCard('posts', PostPreviewCard, () => 240);
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Theme
|
||||
|
||||
The react component that renders the control. It receives the following props:
|
||||
|
||||
| Param | Type | Description |
|
||||
| ---------- | ------ | ------------------------------------------------------------------------------------ |
|
||||
| name | string | The name of the theme |
|
||||
| extends | string | _Optional if all other theme options are provided._<br />The default theme to extend |
|
||||
| common | object | _Optional if `extends` is provided._ See [Common Colors](#common-colors) |
|
||||
| text | object | _Optional if `extends` is provided._ See [Text Colors](#text-colors) |
|
||||
| background | object | _Optional if `extends` is provided._ See [Background Colors](#background-colors) |
|
||||
| scrollbar | object | _Optional if `extends` is provided._ See [Scrollbar Colors](#scrollbar-colors) |
|
||||
| primary | object | _Optional if `extends` is provided._ See [Theme Color](#theme-color) |
|
||||
| error | object | _Optional if `extends` is provided._ See [Theme Color](#theme-color) |
|
||||
| warning | object | _Optional if `extends` is provided._ See [Theme Color](#theme-color) |
|
||||
| info | object | _Optional if `extends` is provided._ See [Theme Color](#theme-color) |
|
||||
| success | object | _Optional if `extends` is provided._ See [Theme Color](#theme-color) |
|
||||
| codemirror | object | _Optional if `extends` is provided._ See [Codemirror](#codemirror) |
|
||||
|
||||
### Common Colors
|
||||
|
||||
`common` allows you to change the common colors.
|
||||
|
||||
| Param | Type | Description |
|
||||
| ----- | ------ | ------------------------------------ |
|
||||
| gray | string | _Optional if `extends` is provided._ |
|
||||
|
||||
### Text Colors
|
||||
|
||||
`text` allows you to change the text colors.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --------- | ------ | ------------------------------------ |
|
||||
| primary | string | _Optional if `extends` is provided._ |
|
||||
| secondary | string | _Optional if `extends` is provided._ |
|
||||
| disabled | string | _Optional if `extends` is provided._ |
|
||||
|
||||
### Background Colors
|
||||
|
||||
`background` allows you to change the background colors.
|
||||
|
||||
| Param | Type | Description |
|
||||
| ------- | ------ | ----------------------------------------------------------------------------------------- |
|
||||
| main | string | _Optional if `extends` is provided._ |
|
||||
| light | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
||||
| dark | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
||||
| divider | string | _Optional if `extends` is provided._ |
|
||||
|
||||
### Scrollbar Colors
|
||||
|
||||
`scrollbar` allows you to change the scrollbar colors.
|
||||
|
||||
| Param | Type | Description |
|
||||
| ----- | ------ | ----------------------------------------------------------------------------------------- |
|
||||
| main | string | _Optional if `extends` is provided._ |
|
||||
| light | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
||||
|
||||
### Theme Color
|
||||
|
||||
`primary`, `error`, `warning`, `info` and `success` are theme colors and share the same options.
|
||||
|
||||
| Param | Type | Description |
|
||||
| ------------- | ------ | ----------------------------------------------------------------------------------------- |
|
||||
| main | string | _Optional if `extends` is provided._ |
|
||||
| light | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
||||
| dark | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
||||
| contrastColor | string | _Optional if `extends` is provided._ |
|
||||
|
||||
### Codemirror
|
||||
|
||||
`codemirror` allows you to change the theme settings for Codemirror instances (used by the [code](/docs/widget-code) and [markdown](/docs/widget-markdown) widgets).
|
||||
|
||||
| Param | Type | Description |
|
||||
| ----- | ------ | ----------------------------------------------------------------------------------------- |
|
||||
| main | string | _Optional if `extends` is provided._ |
|
||||
| light | string | _Optional if `extends` is provided._<br />Will be calculated from `main` if not provided. |
|
@ -4,7 +4,7 @@ title: Creating Custom Widgets
|
||||
weight: 40
|
||||
---
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to register custom widgets via `registerWidget`. The same object is also the default export if you import Static CMS as an npm module.
|
||||
Static CMS exposes a `window.CMS` global object that you can use to register custom widgets via `registerWidget`. The same object is also the default export if you import Static CMS as an npm module.
|
||||
|
||||
### React Components Inline
|
||||
|
||||
@ -64,7 +64,6 @@ The react component that renders the control. It receives the following props:
|
||||
| query | function | Runs a search on another collection. See [Query](#query) |
|
||||
| i18n | object | The current i18n settings |
|
||||
| t | function | Translates a given key to the current locale |
|
||||
| theme | 'light'<br />\| 'dark' | The current theme being used by the app |
|
||||
|
||||
#### Query
|
||||
|
||||
@ -90,7 +89,6 @@ The react component that renders the preview. It receives the following props:
|
||||
| collection | object | The collection configuration for the current widget. See [Collections](/docs/collection-overview) |
|
||||
| config | object | The current Static CMS config. See [configuration options](/docs/configuration-options) |
|
||||
| entry | object | Object with a `data` field that contains the current value of all widgets in the editor |
|
||||
| theme | 'light'<br />\| 'dark' | The current theme being used by the app |
|
||||
|
||||
### Options
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Overview
|
||||
weight: 1
|
||||
---
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to customize your CMS. The same object is also the default export if you import Static CMS as an npm module. Available options are:
|
||||
Static CMS exposes a `window.CMS` global object that you can use to customize your CMS. The same object is also the default export if you import Static CMS as an npm module. Available options are:
|
||||
|
||||
- Register [custom widgets](/docs/custom-widgets)
|
||||
- Register [custom previews](/docs/custom-previews)
|
||||
|
@ -1,35 +1,45 @@
|
||||
---
|
||||
group: Migration
|
||||
title: Decap CMS Migration Guide
|
||||
title: Decap / Netlify Migration Guide
|
||||
weight: 190
|
||||
---
|
||||
|
||||
Static CMS is a fork of [Decap](https://github.com/decaporg/decap-cms) (previously Netlify CMS) . Many changes have been made, some big, some small.
|
||||
Static CMS is a fork of [Decap](https://github.com/decaporg/decap-cms) (previously Netlify CMS). Many changes have been made, some big, some small.
|
||||
|
||||
In this guide, we will walk you through the steps of migrating from Decap to Static CMS.
|
||||
In this guide, we will walk you through the steps of migrating from Decap or Netlify to Static CMS.
|
||||
|
||||
## How to Migrate
|
||||
|
||||
Start by replacing Decap with Static CMS, then address the changes below.
|
||||
Start by replacing Decap / Netlify with Static CMS, then address the changes below.
|
||||
|
||||
### CDN
|
||||
|
||||
Decap:
|
||||
Decap (_remove_):
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/netlify-cms@^3.0.0/dist/decap-cms.js"></script>
|
||||
```
|
||||
|
||||
Netlify (_remove_):
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/netlify-cms@^3.0.0/dist/netlify-cms.js"></script>
|
||||
```
|
||||
|
||||
Static CMS:
|
||||
Static CMS (_add_):
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@staticcms/app@^3.0.0/dist/static-cms-app.js"></script>
|
||||
<script src="https://unpkg.com/@staticcms/app@^4.0.0/dist/static-cms-app.js"></script>
|
||||
```
|
||||
|
||||
### Bundling
|
||||
|
||||
```bash
|
||||
# Uninstall Decap
|
||||
npm uninstall decap-cms-app
|
||||
npm uninstall decap-cms-core
|
||||
|
||||
# Uninstall Netlify
|
||||
npm uninstall netlify-cms-app
|
||||
npm uninstall netlify-cms-core
|
||||
|
||||
@ -39,13 +49,19 @@ npm install @staticcms/core
|
||||
|
||||
#### Change your imports
|
||||
|
||||
Decap:
|
||||
Decap (_remove_):
|
||||
|
||||
```js
|
||||
import CMS from 'decap-cms-app';
|
||||
```
|
||||
|
||||
Netlify (_remove_):
|
||||
|
||||
```js
|
||||
import CMS from 'netlify-cms-app';
|
||||
```
|
||||
|
||||
Static CMS:
|
||||
Static CMS (_add_):
|
||||
|
||||
```js
|
||||
import CMS from '@staticcms/core';
|
||||
@ -81,7 +97,7 @@ However, the Gitlab, Client-Side Implicit Grant has been removed as a method of
|
||||
|
||||
### Dates
|
||||
|
||||
[Moment](https://momentjs.com/) has been dropped as the date library used. Instead we are now using [date-fns](https://date-fns.org/). Date formats in your configuration will need to be updated. See [format docs](https://date-fns.org/v2.29.3/docs/format).
|
||||
[Moment](https://momentjs.com/) has been dropped as the date library used. Instead we are now using [date-fns](https://date-fns.org/). Date formats in your configuration will need to be updated. See [format docs](https://date-fns.org/docs/format).
|
||||
|
||||
### Initializing Static CMS
|
||||
|
||||
@ -93,20 +109,152 @@ A [new markdown editor](/docs/widget-markdown) has been added. It comes with a n
|
||||
|
||||
### Sortable Fields
|
||||
|
||||
The `sortable_fields` configuration option has been slightly changed, as we now allow a [default sorting option](/docs/collection-overview#sortable_fields).
|
||||
The `sortable_fields` configuration option has been slightly changed, as we now allow a [default sorting option](/docs/collection-overview#default-sort).
|
||||
|
||||
**Decap**:
|
||||
**Decap / Netlify**:
|
||||
|
||||
```yaml
|
||||
sortable_fields: - field1 - field2
|
||||
sortable_fields:
|
||||
- field1
|
||||
- field2
|
||||
```
|
||||
|
||||
**Static CMS**:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
sortable_fields: fields: - field1 - field2
|
||||
sortable_fields:
|
||||
fields:
|
||||
- field1
|
||||
- field2
|
||||
```
|
||||
|
||||
```js
|
||||
sortable_fields: {
|
||||
fields: ['field1', 'field2'];
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### View Filters
|
||||
|
||||
The `view_filters` configuration option has been slightly changed, as we now allow a [default filter option](/docs/collection-overview#view-filters). Also each filter now requires a unique name.
|
||||
|
||||
**Decap / Netlify**:
|
||||
|
||||
```yaml
|
||||
view_filters:
|
||||
- label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
```
|
||||
|
||||
**Static CMS**:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_filters:
|
||||
fields:
|
||||
- name: alice-and-bob
|
||||
label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- name: posts-2020
|
||||
label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
```
|
||||
|
||||
```js
|
||||
view_filters: {
|
||||
fields: [
|
||||
{
|
||||
name: 'alice-and-bob',
|
||||
label: "Alice's and Bob's Posts",
|
||||
field: 'author',
|
||||
pattern: 'Alice|Bob',
|
||||
},
|
||||
{
|
||||
name: 'posts-2020',
|
||||
label: 'Posts published in 2020',
|
||||
field: 'date',
|
||||
pattern: '2020',
|
||||
},
|
||||
{
|
||||
name: 'drafts',
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
pattern: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### View Groups
|
||||
|
||||
The `view_groups` configuration option has been slightly changed, as we now allow a [default grouping option](/docs/collection-overview#view-groups). Also each group now requires a unique name.
|
||||
|
||||
**Decap / Netlify**:
|
||||
|
||||
```yaml
|
||||
view_groups:
|
||||
- label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- label: Drafts
|
||||
field: draft
|
||||
```
|
||||
|
||||
**Static CMS**:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_groups:
|
||||
groups:
|
||||
- name: by-year
|
||||
label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
```
|
||||
|
||||
```js
|
||||
view_groups: {
|
||||
groups: [
|
||||
{
|
||||
name: "by-year",
|
||||
label: "Year",
|
||||
field: "date",
|
||||
pattern: "\\d{4}
|
||||
},
|
||||
{
|
||||
name: "drafts",
|
||||
label: "Drafts",
|
||||
field: "draft"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### List Widget
|
||||
|
||||
Support in the List Widget for the `field` property has been dropped. A single field in the `fields` property [achieves the same behavior](/docs/widget-list).
|
||||
@ -146,7 +294,7 @@ The `getAsset` method has been removed, the new `useMediaAsset` hook should be u
|
||||
|
||||
### Beta Features
|
||||
|
||||
The following beta features from Decap have been dropped:
|
||||
The following beta features from Decap / Netlify have been dropped:
|
||||
|
||||
- GraphQL support for GitHub and GitLab
|
||||
- Remark plugins (new markdown editor has its own plugin system)
|
||||
@ -226,7 +374,7 @@ collections:
|
||||
If you are using Gatsby you will need to change out your CMS plugin.
|
||||
|
||||
```bash
|
||||
# Uninstall Decap plugin
|
||||
# Uninstall Decap / Netlify plugin
|
||||
npm uninstall gatsby-plugin-netlify-cms
|
||||
|
||||
# Install Static CMS plugin
|
||||
@ -237,13 +385,19 @@ npm install gatsby-plugin-static-cms
|
||||
|
||||
If you are using the local backend you will need to switch the proxy server package you are using.
|
||||
|
||||
Decap:
|
||||
Decap (_remove_):
|
||||
|
||||
```bash
|
||||
npx decap-server
|
||||
```
|
||||
|
||||
Netlify (_remove_):
|
||||
|
||||
```bash
|
||||
npx netlify-cms-proxy-server
|
||||
```
|
||||
|
||||
Static CMS:
|
||||
Static CMS (_add_):
|
||||
|
||||
```bash
|
||||
npx @staticcms/proxy-server
|
||||
|
35
packages/docs/content/docs/editorial-workflow.mdx
Normal file
35
packages/docs/content/docs/editorial-workflow.mdx
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
group: Workflow
|
||||
weight: 10
|
||||
title: Editorial Workflow
|
||||
beta: true
|
||||
---
|
||||
|
||||
<Alert severity="warning">
|
||||
Editorial Workflow is not available for the Gitea backend.
|
||||
</Alert>
|
||||
|
||||
By default, all entries created or edited in Static CMS are committed directly into the main repository branch.
|
||||
|
||||
The `publish_mode` option allows you to enable "Editorial Workflow" mode for more control over the content publishing phases. The unpublished entries will be arranged on a dashboard, in Static CMS, according to their status (Draft, Ready for Review, Ready To Publish). This allows for quick access to unpublished entries, allowing them to be reviewed and edited before going live.
|
||||
|
||||
You can enable the Editorial Workflow with the following line in your `config.yml` file:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
publish_mode: editorial_workflow
|
||||
```
|
||||
|
||||
```js
|
||||
publish_mode: 'editorial_workflow';
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
From a technical perspective, the workflow translates editor UI actions into common Git commands:
|
||||
|
||||
| Actions in Netlify UI | Perform these Git actions |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| Save draft | Commits to a new branch (named according to the pattern `cms/collectionName/entrySlug`), and opens a pull/merge request |
|
||||
| Edit draft | Pushes another commit to the draft branch and pull/merge request |
|
||||
| Approve and publish draft | Merges pull/merge request and deletes branch |
|
@ -2,9 +2,12 @@
|
||||
title: Gitea
|
||||
group: Backends
|
||||
weight: 45
|
||||
beta: true
|
||||
---
|
||||
|
||||
<Alert severity="warning">
|
||||
Gitea backend cannot be used with the Editorial Workflow.
|
||||
</Alert>
|
||||
|
||||
- **Name**: `gitea`
|
||||
|
||||
For repositories stored on Gitea, the `gitea` backend allows CMS users to log in directly with their Gitea account. Note that all users must have push access to your content repository for this to work.
|
||||
|
@ -1,7 +1,6 @@
|
||||
---
|
||||
group: Collections
|
||||
title: i18n Support
|
||||
beta: true
|
||||
weight: 30
|
||||
---
|
||||
|
||||
@ -25,7 +24,7 @@ i18n:
|
||||
|
||||
# Optional, defaults to the first item in locales.
|
||||
# The locale to be used for fields validation and as a baseline for the entry.
|
||||
defaultLocale: en
|
||||
default_locale: en
|
||||
```
|
||||
|
||||
```js
|
||||
@ -45,7 +44,7 @@ i18n: {
|
||||
* Optional, defaults to the first item in locales.
|
||||
* The locale to be used for fields validation and as a baseline for the entry.
|
||||
*/
|
||||
defaultLocale: 'en'
|
||||
default_locale: 'en'
|
||||
},
|
||||
```
|
||||
|
||||
|
@ -37,7 +37,7 @@ backend: {
|
||||
## Usage
|
||||
|
||||
1. Run `npx @staticcms/proxy-server` from the root directory of the above repository.
|
||||
- If the default port (8081) is in use, the proxy server won't start and you will see an error message. In this case, follow [these steps](#configure-the-@staticcms/proxy-server-port-number) before proceeding.
|
||||
- If the default port (8081) is in use, the proxy server will not start and you will see an error message. In this case, follow [these steps](#configure-the-@staticcms/proxy-server-port-number) before proceeding.
|
||||
2. Start your local development server (e.g. run `gatsby develop`).
|
||||
3. Open `http://localhost:<port>/admin` to verify that your can administer your content locally. Replace `<port>` with the port of your local development server. For example Gatsby's default port is `8000`
|
||||
|
||||
|
@ -1,89 +0,0 @@
|
||||
---
|
||||
group: Migration
|
||||
title: How to Upgrade to v3
|
||||
weight: 101
|
||||
---
|
||||
|
||||
Static CMS v3 introduces:
|
||||
- Mobile support
|
||||
- Depedent fields (see [Field Conditions](/docs/widgets#field-conditions) for more information)
|
||||
|
||||
In this guide, we will walk you through the steps for upgrading to Static CMS v3.
|
||||
|
||||
Please [report any issues](https://github.com/StaticJsCMS/static-cms/issues/new) you encounter while upgrading to Static CMS v3.
|
||||
|
||||
## Installing
|
||||
|
||||
To install the latest version of Static CMS:
|
||||
|
||||
```bash
|
||||
npm install @staticcms/core@^3.0.0
|
||||
```
|
||||
|
||||
Or if you're using yarn:
|
||||
|
||||
```bash
|
||||
yarn add @staticcms/core@^3.0.0
|
||||
```
|
||||
|
||||
If you are using a CDN to load Static CMS, simply change your URLs:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://unpkg.com/@staticcms/app@^3.0.0/dist/main.css" />
|
||||
```
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@staticcms/app@^3.0.0/dist/static-cms-app.js"></script>
|
||||
```
|
||||
|
||||
## Gitea Backend Update <BetaImage />
|
||||
|
||||
While still remaining in beta, the Gitea backend has been evolving. This update switches the authentication mechanism to PKCE auth and improves performance when dealing with multiple file commits.
|
||||
|
||||
To use Gitea with Static CMS v3, you need to update your Gitea instance to at least `v1.20`. You will also need to update your config to match the setup for PKCE authentication. See [Gitea authentication](/docs/gitea-backend#authentication).
|
||||
|
||||
## CMS Events <BetaImage />
|
||||
|
||||
CMS Events have undergone a significant refactor in this update, including adding a new `change` event. You may need to update your config as follows to continue to use them. The `preSave` and `postSave` events along with the new `change` event, now require a `collection` be provided during registration, with an optional `file` if you are targeting a [file collection](/docs/collection-types#file-collections). All events now can handle async handlers as well.
|
||||
|
||||
**Old setup**
|
||||
|
||||
```js
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
handler: ({ entry }) => {
|
||||
return {
|
||||
...entry,
|
||||
data: {
|
||||
...entry.data,
|
||||
title: 'new title',
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**New Setup**
|
||||
|
||||
```js
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
collection: 'posts',
|
||||
handler: ({ data: { entry } }) => {
|
||||
return {
|
||||
...entry.data,
|
||||
title: 'new title',
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
See [CMS Events](/docs/beta-features#registering-to-cms-events) for more details.
|
||||
|
||||
## Other Breaking Changes
|
||||
|
||||
- The following Widget Control component properties have been removed:
|
||||
- `hidden`
|
||||
- `mediaPaths` - Use [useMediaInsert](/docs/custom-widgets#interacting-with-the-media-library) instead.
|
||||
- `openMediaLibrary` - Use [useMediaInsert](/docs/custom-widgets#interacting-with-the-media-library) instead.
|
||||
- `removeInsertedMedia` - Use [useMediaInsert](/docs/custom-widgets#interacting-with-the-media-library) instead.
|
263
packages/docs/content/docs/migration-guide-v4.mdx
Normal file
263
packages/docs/content/docs/migration-guide-v4.mdx
Normal file
@ -0,0 +1,263 @@
|
||||
---
|
||||
group: Migration
|
||||
title: How to Upgrade to v4
|
||||
weight: 101
|
||||
---
|
||||
|
||||
Static CMS v4 introduces:
|
||||
|
||||
- [Custom themes](/docs/custom-theme)
|
||||
- [Editorial Workflow](/docs/editorial-workflow) <BetaImage />
|
||||
- [Open Authoring](/docs/open-authoring) (Github backend only) <BetaImage />
|
||||
|
||||
In this guide, we will walk you through the steps for upgrading to Static CMS v4.
|
||||
|
||||
Please [report any issues](https://github.com/StaticJsCMS/static-cms/issues/new) you encounter while upgrading to Static CMS v4.
|
||||
|
||||
## Installing
|
||||
|
||||
To install the latest version of Static CMS:
|
||||
|
||||
```bash
|
||||
npm install @staticcms/core@^4.0.0
|
||||
```
|
||||
|
||||
Or if you are using yarn:
|
||||
|
||||
```bash
|
||||
yarn add @staticcms/core@^4.0.0
|
||||
```
|
||||
|
||||
If you are using a CDN to load Static CMS, simply change your URLs:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://unpkg.com/@staticcms/app@^4.0.0/dist/main.css" />
|
||||
```
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@staticcms/app@^4.0.0/dist/static-cms-app.js"></script>
|
||||
```
|
||||
|
||||
## View Filters
|
||||
|
||||
The `view_filters` configuration option has been slightly changed, as we now allow a [default filter option](/docs/collection-overview#view-filters). Also each filter now requires a unique name.
|
||||
|
||||
**Old setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_filters:
|
||||
- label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
```
|
||||
|
||||
```js
|
||||
view_filters: [
|
||||
{
|
||||
label: "Alice's and Bob's Posts",
|
||||
field: 'author',
|
||||
pattern: 'Alice|Bob',
|
||||
},
|
||||
{
|
||||
label: 'Posts published in 2020',
|
||||
field: 'date',
|
||||
pattern: '2020',
|
||||
},
|
||||
{
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
pattern: true,
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
**New setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_filters:
|
||||
fields:
|
||||
- name: alice-and-bob
|
||||
label: "Alice's and Bob's Posts"
|
||||
field: author
|
||||
pattern: 'Alice|Bob'
|
||||
- name: posts-2020
|
||||
label: 'Posts published in 2020'
|
||||
field: date
|
||||
pattern: '2020'
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
```
|
||||
|
||||
```js
|
||||
view_filters: {
|
||||
fields: [
|
||||
{
|
||||
name: 'alice-and-bob',
|
||||
label: "Alice's and Bob's Posts",
|
||||
field: 'author',
|
||||
pattern: 'Alice|Bob',
|
||||
},
|
||||
{
|
||||
name: 'posts-2020',
|
||||
label: 'Posts published in 2020',
|
||||
field: 'date',
|
||||
pattern: '2020',
|
||||
},
|
||||
{
|
||||
name: 'drafts',
|
||||
label: 'Drafts',
|
||||
field: 'draft',
|
||||
pattern: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## View Groups
|
||||
|
||||
The `view_groups` configuration option has been slightly changed, as we now allow a [default grouping option](/docs/collection-overview#view-groups). Also each group now requires a unique name.
|
||||
|
||||
**Old setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_groups:
|
||||
- label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- label: Drafts
|
||||
field: draft
|
||||
```
|
||||
|
||||
```js
|
||||
view_groups: [
|
||||
{
|
||||
label: "Year",
|
||||
field: "date",
|
||||
pattern: "\\d{4}
|
||||
},
|
||||
{
|
||||
label: "Drafts",
|
||||
field: "draft"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
**New setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
view_groups:
|
||||
groups:
|
||||
- name: by-year
|
||||
label: Year
|
||||
field: date
|
||||
# groups items based on the value matched by the pattern
|
||||
pattern: \d{4}
|
||||
- name: drafts
|
||||
label: Drafts
|
||||
field: draft
|
||||
```
|
||||
|
||||
```js
|
||||
view_groups: {
|
||||
groups: [
|
||||
{
|
||||
name: "by-year",
|
||||
label: "Year",
|
||||
field: "date",
|
||||
pattern: "\\d{4}
|
||||
},
|
||||
{
|
||||
name: "drafts",
|
||||
label: "Drafts",
|
||||
field: "draft"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Theme
|
||||
|
||||
The `theme` prop has been removed from:
|
||||
|
||||
- Custom widget [control components](/docs/custom-widgets#control-component) and [preview components](/docs/custom-widgets#preview-component)
|
||||
- [Custom previews](/docs/custom-previews#editor-preview)
|
||||
- [Custom collection card previews](/docs/custom-previews#collection-card-preview)
|
||||
- [Custom collection field previews](/docs/custom-previews#collection-field-preview)
|
||||
- [Shortcode control components](/docs/widget-markdown#shortcodes)
|
||||
|
||||
The new [useTheme hook](/docs/custom-theme#usetheme-hook) should be instead to get the colors of the current theme.
|
||||
|
||||
## Date Template Transformation
|
||||
|
||||
The date template transformation now uses [date-fns tokens](https://date-fns.org/docs/format) instead of momentjs.
|
||||
|
||||
## List / Object Filter Rules
|
||||
|
||||
Previously, when using [Filtered Folder Collections](/docs/collection-types#filtered-folder-collections), specifying a `list` field, Static CMS would search the values of the list to find a match. Now the default behavior is to match the JSON formatted version of the list's value. To match values inside the list, simply add `.*` to the end of your filter field.
|
||||
|
||||
Object fields are also now matched against the JSON formatted version of their values.
|
||||
|
||||
**Old setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
filter:
|
||||
field: list_field
|
||||
value: some_value
|
||||
```
|
||||
|
||||
```js
|
||||
filter: {
|
||||
field: 'list_field',
|
||||
value: 'some_value'
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
**New setup**
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
filter:
|
||||
field: list_field.*
|
||||
value: some_value
|
||||
```
|
||||
|
||||
```js
|
||||
filter: {
|
||||
field: 'list_field.*',
|
||||
value: 'some_value'
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## i18n Config
|
||||
|
||||
For i18n, the setting `defaultLocale` has been renamed to `default_locale`.
|
||||
|
||||
## Type Changes (TypeScript)
|
||||
|
||||
The `StringOrTextField` type has been split into `StringField` and `TextField`.
|
107
packages/docs/content/docs/open-authoring.mdx
Normal file
107
packages/docs/content/docs/open-authoring.mdx
Normal file
@ -0,0 +1,107 @@
|
||||
---
|
||||
group: Workflow
|
||||
weight: 20
|
||||
title: Open Authoring
|
||||
beta: true
|
||||
---
|
||||
|
||||
<Alert severity="warning">
|
||||
Open Authoring is only available with the [GitHub backend](/docs/github-backend) and must be used with the [Editorial Workflow](/docs/editorial-workflow).
|
||||
</Alert>
|
||||
|
||||
When using the [GitHub backend](/docs/github-backend), you can use Static CMS to accept contributions from GitHub users without giving them access to your repository. When they make changes in the CMS, the CMS forks your repository for them behind the scenes, and all the changes are made to the fork. When the contributor is ready to submit their changes, they can set their draft as ready for review in the CMS. This triggers a pull request to your repository, which makes it appear in the Dashboard for maintainers.
|
||||
|
||||
At the same time, any contributors who _do_ have write access to the repository can continue to use Static CMS normally.
|
||||
|
||||
## Requirements
|
||||
|
||||
- You must use the [GitHub backend](/docs/github-backend).
|
||||
|
||||
**Note that the [Git Gateway backend](/docs/git-gateway-backend) does _not_ support Open Authoring, even when the underlying repo is on GitHub.**
|
||||
|
||||
- For private GitHub repos the user must have `read` access on the repo, and you must explicitly set the auth_scope to `repo`, for example:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
backend:
|
||||
name: github
|
||||
repo: owner-name/private-repo-name # path to private repo
|
||||
auth_scope: repo # this is needed to fork the private repo
|
||||
open_authoring: true
|
||||
```
|
||||
|
||||
```js
|
||||
backend: {
|
||||
name: "github",
|
||||
repo: "owner-name/private-repo-name", // path to private repo
|
||||
auth_scope: "repo", // this is needed to fork the private repo
|
||||
open_authoring: true
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Enabling Open Authoring
|
||||
|
||||
1. [Enable the editorial workflow](/docs/editorial-workflow) by setting `publish_mode` to `editorial_workflow` in your `config.yml`.
|
||||
2. Set `open_authoring` to `true` in the `backend` section of your `config.yml`, as follows:
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
backend:
|
||||
name: github
|
||||
repo: owner-name/repo-name # Path to your GitHub repository
|
||||
open_authoring: true
|
||||
```
|
||||
|
||||
```js
|
||||
backend: {
|
||||
name: "github",
|
||||
repo: "owner-name/repo-name", // Path to your GitHub repository
|
||||
open_authoring: true
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Usage
|
||||
|
||||
When a user logs into Static CMS who does not have write access to your repo, the CMS asks for permission to create a fork of your repo (or uses their existing fork, if they already have one). They are then presented with the normal CMS interface. The published content shown is from the original repo, so it stays up-to-date as changes are made.
|
||||
|
||||
On the editorial workflow screen, the normal three columns are replaced by two columns instead — `Draft` and `Ready to Review`.
|
||||
|
||||
When they make changes to content in the CMS, the changes are made to a branch on their fork. In the editorial workflow screen, they see only their own pending changes. Once they are ready to submit their changes, they can move the card into the "Ready To Review" column to create a pull request. When the entry is published (by a repository maintainer via their Static CMS UI), Static CMS deletes the branch, closes the PR and removes the card from the user's editorial workflow screen. Open Authoring users cannot publish entries through the CMS.
|
||||
|
||||
Users who _do_ have write access to the original repository continue to use the CMS normally.
|
||||
|
||||
## Alternative for external contributors with Git Gateway
|
||||
|
||||
[As noted above](#requirements), Open Authoring does not work with the Git Gateway backend. However, you can use Git Gateway on a site with Netlify Identity that has [open registration](https://www.netlify.com/docs/identity/#adding-identity-users). This lets users create accounts on your site and log into the CMS. There are a few differences, including the following:
|
||||
|
||||
- Users do not need to know about GitHub or create a GitHub account. Instead, they use Netlify Identity accounts that are created on your site and managed by you.
|
||||
- The CMS applies users' changes directly to your repo, not to a fork. (If you use the editorial workflow, you can use features like [GitHub's protected branches](https://help.github.com/en/articles/about-protected-branches) or [Netlify's locked deploys](https://www.netlify.com/docs/locked-deploys/) to prevent users from publishing directly to your site from the CMS.)
|
||||
- There is no distinction between users with write access to the repo and users without — all editorial workflow entries are visible from within the CMS and can be published with the CMS.
|
||||
|
||||
## Linking to specific entries in the CMS
|
||||
|
||||
Open authoring often includes some sort of "Edit this page" link on the live site. Static CMS supports this via the **edit** path:
|
||||
|
||||
```js
|
||||
/#/edit/{collectionName}/{entryName}
|
||||
```
|
||||
|
||||
For the entry named "general" in the "settings" file collection
|
||||
|
||||
```html
|
||||
https://www.example.com/path-to-cms/#/edit/settings/general
|
||||
```
|
||||
|
||||
For blog post "test.md" in the "posts" folder collection
|
||||
|
||||
```html
|
||||
https://www.example.com/path-to-cms/#/edit/posts/test
|
||||
```
|
||||
|
||||
- **`collectionName`**: the name of the collection as entered in the CMS config.
|
||||
- **`entryName`** _(for [file collections](/docs/collection-types/#file-collections)_: the `name` of the entry from the CMS config.
|
||||
- **`entryName`** _(for [folder collections](/docs/collection-types/#folder-collections)_: the filename, sans extension (the slug).
|
@ -41,15 +41,15 @@ You can add Static CMS [to an existing site](/docs/add-to-your-site/), but the q
|
||||
|
||||
After clicking one of those buttons, authenticate with GitHub and choose a repository name. Netlify then automatically creates a clone of the repository in your GitHub account. Next, it builds and deploys the new site on Netlify, bringing you to the site dashboard after completing the build.
|
||||
|
||||
**Note for GitLab and Bitbucket users:** Static CMS supports GitLab and Bitbucket repositories, but won't work with the Deploy to Netlify buttons above without additional configuration (See [GitLab](/docs/gitlab-backend) or [Bitbucket](/docs/bitbucket-backend) respectively).
|
||||
**Note for GitLab and Bitbucket users:** Static CMS supports GitLab and Bitbucket repositories, but will not work with the Deploy to Netlify buttons above without additional configuration (See [GitLab](/docs/gitlab-backend) or [Bitbucket](/docs/bitbucket-backend) respectively).
|
||||
|
||||
## Access Static CMS
|
||||
|
||||
1. The template deploy process sends you an invitation to your new site, sent from `no-reply@netlify.com`.
|
||||

|
||||

|
||||
2. Wait for the deployment to complete, then click the link to accept the invite. Your site will open with a prompt to create a password.
|
||||

|
||||
3. Enter a password, sign in, and you'll go to Static CMS. (For future visits, you can go straight to `<yoursiteaddress.com>/admin/`.)
|
||||
3. Enter a password, sign in, and you will go to Static CMS. (For future visits, you can go straight to `<yoursiteaddress.com>/admin/`.)
|
||||
|
||||
Try adding and editing posts, or changing the content of the Products page. When you save, the changes are pushed immediately to your Git repository, triggering a build on Netlify, and updating the content on your site. Check out the configuration code by visiting your site repo.
|
||||
|
||||
|
@ -8,7 +8,7 @@ weight: 60
|
||||
|
||||
You can use the `test-repo` backend to try out Static CMS without connecting to a Git repo. With this backend, you can write and publish content normally, but any changes will disappear when you reload the page. This backend powers the Static CMS [demo site](https://demo.staticcms.org/).
|
||||
|
||||
**Note:** The `test-repo` backend can't access your local file system, nor does it connect to a Git repo, thus you won't see any existing files while using it.
|
||||
**Note:** The `test-repo` backend cannot access your local file system, nor does it connect to a Git repo, thus you will not see any existing files while using it.
|
||||
|
||||
To enable this backend, set your backend name to `test-repo` in your Static CMS `config` file.
|
||||
|
||||
|
@ -14,12 +14,12 @@ If you are using a package manager like Yarn or NPM, use their standard procedur
|
||||
|
||||
If you are using Static CMS through a CDN like Unpkg, then that depends on the version tag you are using. You can find the version tag in the `/admin/index.html` file of your site.
|
||||
|
||||
- (Recommended) If you use `^3.0.0`, Static CMS does all updates except major versions automatically.
|
||||
- It upgrades to `3.0.1`, `3.1.0`, `3.1.1`.
|
||||
- It does not upgrade to `3.0.0` or higher.
|
||||
- (Recommended) If you use `^4.0.0`, Static CMS does all updates except major versions automatically.
|
||||
- It upgrades to `4.0.1`, `4.1.0`, `4.1.1`.
|
||||
- It does not upgrade to `4.0.0` or higher.
|
||||
- It does not upgrade to beta versions.
|
||||
|
||||
- If you use `~3.0.0`, Static CMS will do only patch updates automatically.
|
||||
- It upgrades `3.0.1`, `3.0.2`.
|
||||
- It does not upgrade to `3.1.0` or higher.
|
||||
- If you use `~4.0.0`, Static CMS will do only patch updates automatically.
|
||||
- It upgrades `4.0.1`, `4.0.2`.
|
||||
- It does not upgrade to `4.1.0` or higher.
|
||||
- It does not upgrade beta versions.
|
||||
|
@ -14,9 +14,11 @@ The boolean widget translates a toggle switch input to a `true` or `false` value
|
||||
|
||||
For common options, see [Common widget options](/docs/widgets#common-widget-options).
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------- | ------- | ------- | ------------------------------------------- |
|
||||
| default | boolean | `false` | _Optional_. The default value for the field |
|
||||
| Name | Type | Default | Description |
|
||||
| ------- | ------- | ------- | --------------------------------------------- |
|
||||
| default | boolean | `false` | _Optional_. The default value for the field |
|
||||
| prefix | string | `''` | _Optional_. Text to show before toggle switch |
|
||||
| suffix | string | `''` | _Optional_. Text to show after toggle switch |
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -17,9 +17,9 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| Name | Type | Default | Description |
|
||||
| ----------- | ---------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| default | string | `Current Date and Time` | _Optional_. The default value for the field. Accepts a datetime string, or an empty string to accept blank input. |
|
||||
| format | string | `yyyy-MM-dd'T'HH:mm:ss.SSSXXX` | _Optional_. Sets storage format. Accepts [date-fns tokens](https://date-fns.org/v2.29.3/docs/format) |
|
||||
| date_format | string<br />\| boolean | `true` | _Optional_. Sets date display format in UI.<ul><li>`string` - Accepts [date-fns tokens](https://date-fns.org/v2.29.3/docs/format)</li><li>`true` - Uses default locale format</li><li>`false` - If `time_format` is `true` or a string, then date picker is hidden</li></ul> |
|
||||
| time_format | string<br />\| boolean | `true` | _Optional_. Sets time display format in UI.<ul><li>`string` - Accepts [date-fns tokens](https://date-fns.org/v2.29.3/docs/format)</li><li>`true` - Uses default locale format</li><li>`false` - Hides the time picker</li></ul> |
|
||||
| format | string | `yyyy-MM-dd'T'HH:mm:ss.SSSXXX` | _Optional_. Sets storage format. Accepts [date-fns tokens](https://date-fns.org/docs/format) |
|
||||
| date_format | string<br />\| boolean | `true` | _Optional_. Sets date display format in UI.<ul><li>`string` - Accepts [date-fns tokens](https://date-fns.org/docs/format)</li><li>`true` - Uses default locale format</li><li>`false` - If `time_format` is `true` or a string, then date picker is hidden</li></ul> |
|
||||
| time_format | string<br />\| boolean | `true` | _Optional_. Sets time display format in UI.<ul><li>`string` - Accepts [date-fns tokens](https://date-fns.org/docs/format)</li><li>`true` - Uses default locale format</li><li>`false` - Hides the time picker</li></ul> |
|
||||
| picker_utc | boolean | `false` | _Optional_. <ul><li>`true` - The datetime picker will display times in UTC</li><li>`false` - The datetime picker will display times in the user's local timezone</li></ul> When using date-only formats, it can be helpful to set this to `true` so users in all timezones will see the same date in the datetime picker |
|
||||
|
||||
## Examples
|
||||
|
@ -19,7 +19,7 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| default | string | `[ <default from the child fields> ]` | _Optional_. The default values for fields. Also accepts an array of items |
|
||||
| allow_add | boolean | `true` | _Optional_. `false` - Hides the button to add additional items. Ignored if both `fields` and `types` are not defined |
|
||||
| collapsed | boolean | `true` | _Optional_. `true` - The list and entries collapse by default. Ignored if both `fields` and `types` are not defined |
|
||||
| summary | string | | _Optional_. The label displayed on collapsed entries. _Ignored for single field lists._ |
|
||||
| summary | string | | _Optional_. The label displayed on collapsed entries. Can use [Template Transformations](/docs/collection-overview#template-transformations). _Ignored for single field lists._ |
|
||||
| label_singular | string | `label` | _Optional_. The text to show on the add button |
|
||||
| fields | list of widgets | [] | _Optional_. A nested list of multiple widget fields to be included in each repeatable iteration |
|
||||
| min | number | | _Optional_. Minimum number of items in the list |
|
||||
|
@ -10,7 +10,7 @@ weight: 19
|
||||
|
||||
The markdown widget provides a full fledged text editor allowing users to format text with features such as headings and blockquotes. Users can change their editing view with a handy toggle button.
|
||||
|
||||
_Please note:_ If you want to use your markdown editor to fill a markdown file contents after its frontmatter, you'll have to name the field `body` so Static CMS recognizes it and saves the file accordingly.
|
||||
_Please note:_ If you want to use your markdown editor to fill a markdown file contents after its frontmatter, you will have to name the field `body` so Static CMS recognizes it and saves the file accordingly.
|
||||
|
||||
## Widget Options
|
||||
|
||||
|
@ -21,6 +21,8 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| min | number | | _Optional_. Minimum value accepted. If a pattern is provided (see [Common widget options](/docs/widgets#common-widget-options)), min is ignored during validation, but is still applied to the input |
|
||||
| max | number | | _Optional_. Maximum value accepted. If a pattern is provided (see [Common widget options](/docs/widgets#common-widget-options)), max is ignored during validation, but is still applied to the input |
|
||||
| step | number | `1` | _Optional_. Size of steps when stepping up or down in input |
|
||||
| prefix | string | `''` | _Optional_. Text to show before number input |
|
||||
| suffix | string | `''` | _Optional_. Text to show after number input |
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -14,11 +14,11 @@ The object widget allows you to group multiple widgets together, nested under a
|
||||
|
||||
For common options, see [Common widget options](/docs/widgets#common-widget-options).
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --------- | ------- | ------- | ------------------------------------------------------------ |
|
||||
| fields | boolean | `false` | A nested list of widget fields to include in your widget |
|
||||
| collapsed | boolean | `false` | _Optional_. Collapse the widget's content by default |
|
||||
| summary | string | `value` | _Optional_. The label displayed when the object is collapsed |
|
||||
| Name | Type | Default | Description |
|
||||
| --------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| fields | boolean | `false` | A nested list of widget fields to include in your widget |
|
||||
| collapsed | boolean | `false` | _Optional_. Collapse the widget's content by default |
|
||||
| summary | string | `value` | _Optional_. The label displayed when the object is collapsed. Can use [Template Transformations](/docs/collection-overview#template-transformations) |
|
||||
|
||||
_Please note:_ A default value cannot be set directly on an object widget. Instead you can set defaults within each sub-field's configuration
|
||||
|
||||
@ -42,7 +42,7 @@ fields:
|
||||
label: 'Birthdate'
|
||||
widget: 'date'
|
||||
default: ''
|
||||
format: 'MM/DD/YYYY'
|
||||
format: 'MM/dd/yyyy'
|
||||
- name: 'address'
|
||||
label: 'Address'
|
||||
widget: 'object'
|
||||
@ -81,7 +81,7 @@ fields: [
|
||||
label: 'Birthdate',
|
||||
widget: 'date',
|
||||
default: '',
|
||||
format: 'MM/DD/YYYY'
|
||||
format: 'MM/dd/yyyy'
|
||||
},
|
||||
{
|
||||
name: 'address',
|
||||
|
@ -8,7 +8,7 @@ weight: 22
|
||||
- **UI:** Text input with search result dropdown
|
||||
- **Data type:** Data type of the value pulled from the related collection item
|
||||
|
||||
The relation widget allows you to reference items from another collection. It provides a search input with a list of entries from the collection you're referencing, and the list automatically updates with matched entries based on what you've typed.
|
||||
The relation widget allows you to reference items from another collection. It provides a search input with a list of entries from the collection you are referencing, and the list automatically updates with matched entries based on what you have typed.
|
||||
|
||||
## Widget Options
|
||||
|
||||
|
@ -17,6 +17,8 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| Name | Type | Default | Description |
|
||||
| ------- | ------ | ------- | ------------------------------------------------------------- |
|
||||
| default | string | `''` | _Optional_. The default value for the field. Accepts a string |
|
||||
| prefix | string | `''` | _Optional_. Text to show before string input |
|
||||
| suffix | string | `''` | _Optional_. Text to show after string input |
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -45,7 +45,7 @@ The following options are available on all fields:
|
||||
| required | boolean | `true` | _Optional_. Specify as `false` to make a field optional |
|
||||
| hint | string | | _Optional_. Adds helper text directly below a widget. Useful for including instructions. Accepts markdown for bold, italic, strikethrough, and links. |
|
||||
| pattern | list of strings | | _Optional_. Adds field validation by specifying a list with a [regex pattern](https://regexr.com/) and an error message; more extensive validation can be achieved with [custom widgets](/docs/custom-widgets/#advanced-field-validation) |
|
||||
| i18n | boolean<br />\| 'translate'<br />\| 'duplicate'<br />\| 'none' | | _Optional_. <BetaImage /><ul><li>`translate` - Allows translation of the field</li><li>`duplicate` - Duplicates the value from the default locale</li><li>`true` - Accept parent values as default</li><li>`none` or `false` - Exclude field from translations</li></ul> |
|
||||
| i18n | boolean<br />\| 'translate'<br />\| 'duplicate'<br />\| 'none' | | _Optional_. <ul><li>`translate` - Allows translation of the field</li><li>`duplicate` - Duplicates the value from the default locale</li><li>`true` - Accept parent values as default</li><li>`none` or `false` - Exclude field from translations</li></ul> |
|
||||
| condition | FilterRule<br />\| List of FilterRules | | _Optional_. See [Field Conditions](#field-conditions) |
|
||||
|
||||
## Example Widget
|
||||
|
@ -168,13 +168,13 @@ _____
|
||||
|
||||
> Do: View the fields.
|
||||
|
||||
> Don't: With this next command, we'll view the fields.
|
||||
> Don't: With this next command, we will view the fields.
|
||||
|
||||
### Address the reader as "you"
|
||||
|
||||
> Do: You can create a Deployment by …
|
||||
|
||||
> Don't: We'll create a Deployment by …
|
||||
> Don't: We will create a Deployment by …
|
||||
_____
|
||||
|
||||
> Do: In the preceding output, you can see…
|
||||
@ -201,7 +201,7 @@ Exception: Use "etc." for et cetera.
|
||||
|
||||
### Avoid using "we"
|
||||
|
||||
Using "we" in a sentence can be confusing, because the reader might not know whether they're part of the "we" you're describing.
|
||||
Using "we" in a sentence can be confusing, because the reader might not know whether they are part of the "we" you are describing.
|
||||
|
||||
> Do: Version 1.4 includes …
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
],
|
||||
"call_to_action": {
|
||||
"title": "Getting started is simple and free.",
|
||||
"subtitle": "Choose a template that's pre-configured with a static site generator and deploys to a global CDN in one click.",
|
||||
"subtitle": "Choose a template that is pre-configured with a static site generator and deploys to a global CDN in one click.",
|
||||
"button_text": "Get Started",
|
||||
"url": "/docs/start-with-a-template/"
|
||||
},
|
||||
@ -37,14 +37,14 @@
|
||||
"description": "The web-based app includes rich-text editing, real-time previews, and drag-and-drop media uploads."
|
||||
},
|
||||
{
|
||||
"image": "/img/your-content-your-way.webp",
|
||||
"title": "Your content, your way",
|
||||
"description": "Static CMS can integrate with most major static site generators and git repository providers."
|
||||
"image": "/img/intuitive-workflow-for-content-teams.svg",
|
||||
"title": "Intuitive workflow for content teams",
|
||||
"description": "Writers and editors can easily manage content from draft to review to publish across any number of custom content types."
|
||||
},
|
||||
{
|
||||
"image": "/img/instant-access-without-github-account.svg",
|
||||
"title": "Instant access without GitHub account",
|
||||
"description": "With Git Gateway, you can add CMS access for any team member — even if they don't have a GitHub account."
|
||||
"description": "With Git Gateway, you can add CMS access for any team member — even if they do not have a GitHub account."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -13,6 +13,10 @@
|
||||
"name": "Backends",
|
||||
"title": "Backends"
|
||||
},
|
||||
{
|
||||
"name": "Workflow",
|
||||
"title": "Workflow"
|
||||
},
|
||||
{
|
||||
"name": "Collections",
|
||||
"title": "Collections"
|
||||
|
@ -1,10 +1,41 @@
|
||||
{
|
||||
"releases": [
|
||||
{
|
||||
"date": "2024-01-03T10:00:00.000Z",
|
||||
"version": "v4.0.0",
|
||||
"type": "major",
|
||||
"description": "Editorial workflow, open authoring and theming"
|
||||
},
|
||||
{
|
||||
"date": "2024-01-02T11:00:00.000Z",
|
||||
"version": "v4.0.0-beta.17",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2024-01-02T10:00:00.000Z",
|
||||
"version": "v3.4.8",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-12-21T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.16",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-12-13T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.15",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-12-11T11:00:00.000Z",
|
||||
"version": "v4.0.0-beta.13",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-12-11T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.12",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-12-11T10:00:00.000Z",
|
||||
"version": "v3.4.7",
|
||||
@ -15,11 +46,71 @@
|
||||
"version": "v3.4.6",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-17T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.11",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T15:00:00.000Z",
|
||||
"version": "v4.0.0-beta.10",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T14:00:00.000Z",
|
||||
"version": "v4.0.0-beta.9",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T13:00:00.000Z",
|
||||
"version": "v4.0.0-beta.8",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T12:00:00.000Z",
|
||||
"version": "v4.0.0-beta.7",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T11:00:00.000Z",
|
||||
"version": "v4.0.0-beta.6",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-16T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.5",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-08T11:00:00.000Z",
|
||||
"version": "v4.0.0-beta.4",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-08T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.3",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-07T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.2",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-07T11:00:00.000Z",
|
||||
"version": "v3.4.5",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-02T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.1",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-11-01T10:00:00.000Z",
|
||||
"version": "v4.0.0-beta.0",
|
||||
"type": "pre"
|
||||
},
|
||||
{
|
||||
"date": "2023-10-31T11:00:00.000Z",
|
||||
"version": "v3.4.4",
|
||||
|
@ -1,13 +1,14 @@
|
||||
const withPWA = require('next-pwa')({
|
||||
publicExcludes: ['!bulletins/**/*'],
|
||||
dest: 'public'
|
||||
dest: 'public',
|
||||
});
|
||||
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.ANALYZE === 'true'
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
});
|
||||
|
||||
const redirects = [
|
||||
{ source: '/docs', destination: '/docs/intro', permanent: true },
|
||||
{ source: '/chat', destination: 'https://discord.gg/ZWJM9pBMjj', permanent: true },
|
||||
];
|
||||
|
||||
@ -28,7 +29,7 @@ let config = {
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
config = withPWA(config);
|
||||
@ -36,4 +37,4 @@ if (process.env.NODE_ENV === 'production') {
|
||||
config = withBundleAnalyzer(config);
|
||||
}
|
||||
|
||||
module.exports = config
|
||||
module.exports = config;
|
||||
|
@ -14,14 +14,14 @@
|
||||
"lint": "run-p -c --aggregate-output \"lint:*\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "11.10.6",
|
||||
"@emotion/styled": "11.10.6",
|
||||
"@mui/icons-material": "5.11.16",
|
||||
"@mui/material": "5.11.16",
|
||||
"date-fns": "2.29.3",
|
||||
"@emotion/react": "11.11.1",
|
||||
"@emotion/styled": "11.11.0",
|
||||
"@mui/icons-material": "5.14.12",
|
||||
"@mui/material": "5.14.12",
|
||||
"date-fns": "2.30.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
"next": "13.2.4",
|
||||
"next": "14.0.1",
|
||||
"next-mdx-remote": "4.4.1",
|
||||
"next-pwa": "5.6.0",
|
||||
"prismjs": "1.29.0",
|
||||
@ -30,31 +30,30 @@
|
||||
"react-schemaorg": "2.0.0",
|
||||
"remark-gfm": "3.0.1",
|
||||
"schema-dts": "1.1.2",
|
||||
"yaml": "2.2.2"
|
||||
"yaml": "2.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.21.4",
|
||||
"@emotion/eslint-plugin": "11.10.0",
|
||||
"@next/bundle-analyzer": "13.2.4",
|
||||
"@next/eslint-plugin-next": "13.2.4",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/node": "18.16.14",
|
||||
"@types/prettier": "2.7.2",
|
||||
"@types/prismjs": "1.26.0",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.1",
|
||||
"@typescript-eslint/parser": "5.59.1",
|
||||
"@babel/eslint-parser": "7.21.3",
|
||||
"eslint": "8.39.0",
|
||||
"eslint-config-next": "13.2.4",
|
||||
"eslint-config-prettier": "8.8.0",
|
||||
"@babel/core": "7.23.0",
|
||||
"@babel/eslint-parser": "7.22.15",
|
||||
"@emotion/eslint-plugin": "11.11.0",
|
||||
"@next/bundle-analyzer": "13.5.4",
|
||||
"@next/eslint-plugin-next": "13.5.4",
|
||||
"@types/js-yaml": "4.0.6",
|
||||
"@types/node": "18.17.19",
|
||||
"@types/prismjs": "1.26.1",
|
||||
"@types/react": "18.2.25",
|
||||
"@types/react-dom": "18.2.10",
|
||||
"@typescript-eslint/eslint-plugin": "6.7.4",
|
||||
"@typescript-eslint/parser": "6.7.4",
|
||||
"eslint": "8.50.0",
|
||||
"eslint-config-next": "14.0.1",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-plugin-babel": "5.3.1",
|
||||
"eslint-plugin-unicorn": "46.0.1",
|
||||
"eslint-plugin-unicorn": "48.0.1",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.8.8",
|
||||
"typescript": "5.0.4",
|
||||
"webpack": "5.80.0"
|
||||
"prettier": "3.0.3",
|
||||
"typescript": "5.2.2",
|
||||
"webpack": "5.88.2"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.ts": "prettier --write",
|
||||
|
@ -1 +1 @@
|
||||
<svg width="318" height="198" viewBox="0 0 318 198" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>editor</title><defs><rect id="b" width="300" height="180" rx="6"/><filter x="-6%" y="-7.8%" width="112%" filterUnits="objectBoundingBox" id="a"><feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.147843071 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feOffset dy="3" in="SourceAlpha" result="shadowOffsetOuter2"/><feGaussianBlur stdDeviation="4.5" in="shadowOffsetOuter2" result="shadowBlurOuter2"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0974298007 0" in="shadowBlurOuter2" result="shadowMatrixOuter2"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="shadowMatrixOuter2"/></feMerge></filter><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c"><stop stop-color="#4779DD" offset="0%"/><stop stop-color="#3A69C7" offset="100%"/></linearGradient></defs><g transform="translate(9 6)" fill="none" fill-rule="evenodd"><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill="#FFF" xlink:href="#b"/><path d="M0 19h149v161H6c-3.3137 0-6-2.6863-6-6V19z" fill="#EFF0F4"/><path fill="#AEB1BD" d="M10 31h18v4H10z"/><path fill="#FFF" d="M10 39h129v12H10z"/><path fill="#D4D6DD" d="M16 43h44v4H16z"/><path fill="#AEB1BD" d="M10 59h10v4H10z"/><path fill="#FFF" d="M10 67h129v12H10z"/><path fill="#D4D6DD" d="M16 71h26v4H16z"/><path fill="#AEB1BD" d="M10 87h35v4H10z"/><path fill="#FFF9E5" d="M10 95h42v27.7686H10z"/><circle fill="#FFC500" cx="31" cy="110.4463" r="7.8099"/><path d="M10 110.1683c4.6101 2.4917 9.3585 3.7375 14.245 3.7375 7.33 0 10.2112-5.0507 15.7083-5.0507 3.6648 0 7.6803 1.5082 12.0467 4.5246v9.3889H10v-12.6003z" fill="#D4D6DD"/><path d="M10 115.257c4.6503-2.702 8.896-4.0531 12.7373-4.0531 5.7618 0 11.322 4.9766 15.525 4.9766 2.8018 0 7.3811-2.196 13.7377-6.588v13.1761H10v-7.5116z" fill="#9AA1AE"/><path fill="#AEB1BD" d="M10 131h10v4H10z"/><path fill="#FFF" d="M10 139h129v41H10z"/><path fill="#D4D6DD" d="M16 145h117v4H16zm0 6h117v4H16zm0 6h83v4H16zm0 10h117v4H16zm0 6h43v4H16z"/><path fill="#9AA1AE" d="M61 172h2v6h-2z"/><path fill="#AEB1BD" d="M179 31h91v8h-91z"/><path fill="#D4D6DD" d="M213 42h24v4h-24z"/><path fill="#FFF9E5" d="M164 56h121v80H164z"/><circle fill="#FFC500" cx="224.5" cy="100.5" r="22.5"/><path d="M164 99.6992c13.2815 7.1784 26.9613 10.7676 41.0393 10.7676 21.117 0 29.4178-14.5508 45.2548-14.5508 10.558 0 22.1266 4.345 34.7059 13.0352V136H164V99.6992z" fill="#D4D6DD"/><path d="M164 114.3594c13.3973-7.7845 25.6291-11.6768 36.6955-11.6768 16.5995 0 32.6183 14.3374 44.7266 14.3374 8.0722 0 21.2648-6.3266 39.5779-18.98V136H164v-21.6406z" fill="#9AA1AE"/><path fill="#D4D6DD" d="M164 145h121v4H164zm0 6h121v4H164zm0 6h85.8376v4H164zm0 10h121v4H164zm0 6h44.4701v4H164z"/><path fill="#9AA1AE" d="M210 172h2v6h-2z"/><path d="M6 0h288c3.3137 0 6 2.6863 6 6v13H0V6c0-3.3137 2.6863-6 6-6z" fill="url(#c)"/></g></svg>
|
||||
<svg width="318" height="198" viewBox="0 0 318 198" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>editor</title><defs><rect id="b" width="300" height="180" rx="6"/><filter x="-6%" y="-7.8%" width="112%" filterUnits="objectBoundingBox" id="a"><feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.147843071 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feOffset dy="3" in="SourceAlpha" result="shadowOffsetOuter2"/><feGaussianBlur stdDeviation="4.5" in="shadowOffsetOuter2" result="shadowBlurOuter2"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0974298007 0" in="shadowBlurOuter2" result="shadowMatrixOuter2"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="shadowMatrixOuter2"/></feMerge></filter><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c"><stop stop-color="#4779DD" offset="0%"/><stop stop-color="#3A69C7" offset="100%"/></linearGradient></defs><g transform="translate(9 6)" fill="none" fill-rule="evenodd"><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill="#FFF" xlink:href="#b"/><path d="M0 19h149v161H6c-3.3137 0-6-2.6863-6-6V19z" fill="#EFF0F4"/><path fill="#AEB1BD" d="M10 31h18v4H10z"/><path fill="#FFF" d="M10 39h129v12H10z"/><path fill="#D4D6DD" d="M16 43h44v4H16z"/><path fill="#AEB1BD" d="M10 59h10v4H10z"/><path fill="#FFF" d="M10 67h129v12H10z"/><path fill="#D4D6DD" d="M16 71h26v4H16z"/><path fill="#AEB1BD" d="M10 87h35v4H10z"/><path fill="#FFF9E5" d="M10 95h42v27.7686H10z"/><circle fill="#FFC500" cx="31" cy="110.4463" r="7.8099"/><path d="M10 110.1683c4.6101 2.4917 9.3585 3.7375 14.245 3.7375 7.33 0 10.2112-5.0507 15.7083-5.0507 3.6648 0 7.6803 1.5082 12.0467 4.5246v9.3889H10v-12.6003z" fill="#D4D6DD"/><path d="M10 115.257c4.6503-2.702 8.896-4.0531 12.7373-4.0531 5.7618 0 11.322 4.9766 15.525 4.9766 2.8018 0 7.3811-2.196 13.7377-6.588v13.1761H10v-7.5116z" fill="#9AA1AE"/><path fill="#AEB1BD" d="M10 131h10v4H10z"/><path fill="#FFF" d="M10 139h129v41H10z"/><path fill="#D4D6DD" d="M16 145h117v4H16zm0 6h117v4H16zm0 6h83v4H16zm0 10h117v4H16zm0 6h43v4H16z"/><path fill="#9AA1AE" d="M61 172h2v6h-2z"/><path fill="#AEB1BD" d="M179 31h91v8h-91z"/><path fill="#D4D6DD" d="M213 42h24v4h-24z"/><path fill="#FFF9E5" d="M164 56h121v80H164z"/><circle fill="#FFC500" cx="224.5" cy="100.5" r="22.5"/><path d="M164 99.6992c13.2815 7.1784 26.9613 10.7676 41.0393 10.7676 21.117 0 29.4178-14.5508 45.2548-14.5508 10.558 0 22.1266 4.345 34.7059 13.0352V136H164V99.6992z" fill="#D4D6DD"/><path d="M164 114.3594c13.3973-7.7845 25.6291-11.6768 36.6955-11.6768 16.5995 0 32.6183 14.3374 44.7266 14.3374 8.0722 0 21.2648-6.3266 39.5779-18.98V136H164v-21.6406z" fill="#9AA1AE"/><path fill="#D4D6DD" d="M164 145h121v4H164zm0 6h121v4H164zm0 6h85.8376v4H164zm0 10h121v4H164zm0 6h44.4701v4H164z"/><path fill="#9AA1AE" d="M210 172h2v6h-2z"/><path d="M6 0h288c3.3137 0 6 2.6863 6 6v13H0V6c0-3.3137 2.6863-6 6-6z" fill="url(#c)"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.1 KiB |
@ -92,10 +92,13 @@ const useIntersectionObserver = (setActiveId: (activeId: string) => void) => {
|
||||
}
|
||||
|
||||
const callback: IntersectionObserverCallback = headings => {
|
||||
headingElementsRef.current = headings.reduce((map, headingElement) => {
|
||||
map[headingElement.target.id] = headingElement;
|
||||
return map;
|
||||
}, headingElementsRef.current as Record<string, IntersectionObserverEntry>);
|
||||
headingElementsRef.current = headings.reduce(
|
||||
(map, headingElement) => {
|
||||
map[headingElement.target.id] = headingElement;
|
||||
return map;
|
||||
},
|
||||
headingElementsRef.current as Record<string, IntersectionObserverEntry>,
|
||||
);
|
||||
|
||||
// Get all headings that are currently visible on the page
|
||||
const visibleHeadings: IntersectionObserverEntry[] = [];
|
||||
@ -148,6 +151,11 @@ const StyledNav = styled('nav')(
|
||||
overflow-y: auto;
|
||||
top: 16px;
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
${theme.breakpoints.between('md', 'lg')} {
|
||||
top: 24px;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import IconButton from '@mui/material/IconButton';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Link from 'next/link';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import releases from '../../lib/releases';
|
||||
import Logo from './Logo';
|
||||
@ -19,7 +19,7 @@ import SponsorButton from './SponsorButton';
|
||||
import type { PaletteMode } from '@mui/material';
|
||||
import type { ButtonTypeMap } from '@mui/material/Button';
|
||||
import type { ExtendButtonBase } from '@mui/material/ButtonBase';
|
||||
import type { DocsGroup, MenuItem, SearchablePage } from '../../interface';
|
||||
import type { DocsGroup, MenuItem, MenuLink, SearchablePage } from '../../interface';
|
||||
|
||||
const StyledAppBar = styled(AppBar)(
|
||||
({ theme }) => `
|
||||
@ -55,7 +55,7 @@ const StyledGithubLink = styled('a')(
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
${theme.breakpoints.down('lg')} {
|
||||
${theme.breakpoints.down(1300)} {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
@ -104,6 +104,14 @@ const StyledDesktopLink = styled(Button)(
|
||||
`,
|
||||
) as ExtendButtonBase<ButtonTypeMap<{}, 'a'>>;
|
||||
|
||||
const STATIC_CMS_DOMAIN = 'staticcms.org';
|
||||
const DEFAULT_DEMO_SITE = 'demo.staticcms.org';
|
||||
const STATIC_CMS_DOMAIN_REGEX = /staticcms\.org$/g;
|
||||
|
||||
function createDemoUrl(subdomain?: string): string {
|
||||
return `https://${subdomain ? subdomain : ''}${DEFAULT_DEMO_SITE}/`;
|
||||
}
|
||||
|
||||
interface HeaderProps {
|
||||
mode: PaletteMode;
|
||||
docsGroups: DocsGroup[];
|
||||
@ -115,6 +123,18 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
const theme = useTheme();
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
|
||||
const [demoUrl, setDemoUrl] = useState(createDemoUrl());
|
||||
useEffect(() => {
|
||||
if (
|
||||
typeof window === 'undefined' ||
|
||||
!window.location.host.endsWith(STATIC_CMS_DOMAIN) ||
|
||||
window.location.host === `www.${STATIC_CMS_DOMAIN}`
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setDemoUrl(createDemoUrl(window.location.host.replace(STATIC_CMS_DOMAIN_REGEX, '')));
|
||||
}, []);
|
||||
|
||||
const handleDrawerToggle = useCallback(() => {
|
||||
setMobileOpen(!mobileOpen);
|
||||
}, [mobileOpen]);
|
||||
@ -142,12 +162,17 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
title: 'Examples',
|
||||
url: '/docs/examples',
|
||||
},
|
||||
{
|
||||
title: 'Demo',
|
||||
url: demoUrl,
|
||||
target: '_blank',
|
||||
},
|
||||
{
|
||||
title: 'Community',
|
||||
url: '/community',
|
||||
},
|
||||
],
|
||||
[docsGroups],
|
||||
[demoUrl, docsGroups],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -198,14 +223,21 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
</StyledIconsWrapper>
|
||||
{items.map(item => {
|
||||
let url = '#';
|
||||
let target: MenuLink['target'];
|
||||
if ('url' in item) {
|
||||
url = item.url;
|
||||
target = item.target;
|
||||
} else if (item.groups.length > 0 && item.groups[0].links.length > 0) {
|
||||
url = item.groups[0].links[0].url;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledDesktopLink key={`desktop-${item.title}-${url}`} component={Link} href={url}>
|
||||
<StyledDesktopLink
|
||||
key={`desktop-${item.title}-${url}`}
|
||||
component={Link}
|
||||
href={url}
|
||||
target={target}
|
||||
>
|
||||
{item.title}
|
||||
</StyledDesktopLink>
|
||||
);
|
||||
|
@ -66,7 +66,7 @@ export interface HomepageData {
|
||||
export interface Release {
|
||||
readonly date: string;
|
||||
readonly version: string;
|
||||
readonly type: 'major' | 'minor' | 'patch';
|
||||
readonly type: 'major' | 'minor' | 'patch' | 'pre';
|
||||
readonly description?: string;
|
||||
}
|
||||
|
||||
@ -136,6 +136,7 @@ export interface MenuLink {
|
||||
readonly url: string;
|
||||
readonly beta?: boolean;
|
||||
readonly deprecated?: boolean;
|
||||
readonly target?: '_blank';
|
||||
}
|
||||
|
||||
export interface MenuLinkSubGroup {
|
||||
|
@ -129,18 +129,21 @@ export function fetchDocsContent(): [DocsPage[], DocsGroup[]] {
|
||||
},
|
||||
);
|
||||
|
||||
const pagesByGroup: Record<string, DocsGroupLink[]> = allDocsData.reduce((acc, doc) => {
|
||||
if (!(doc.data.group in acc)) {
|
||||
acc[doc.data.group] = [];
|
||||
}
|
||||
acc[doc.data.group].push({
|
||||
title: doc.data.title,
|
||||
slug: doc.data.slug,
|
||||
beta: doc.data.beta ?? false,
|
||||
deprecated: doc.data.deprecated ?? false,
|
||||
});
|
||||
return acc;
|
||||
}, {} as Record<string, DocsGroupLink[]>);
|
||||
const pagesByGroup: Record<string, DocsGroupLink[]> = allDocsData.reduce(
|
||||
(acc, doc) => {
|
||||
if (!(doc.data.group in acc)) {
|
||||
acc[doc.data.group] = [];
|
||||
}
|
||||
acc[doc.data.group].push({
|
||||
title: doc.data.title,
|
||||
slug: doc.data.slug,
|
||||
beta: doc.data.beta ?? false,
|
||||
deprecated: doc.data.deprecated ?? false,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, DocsGroupLink[]>,
|
||||
);
|
||||
|
||||
const docsGroups: DocsGroup[] = menu.docs.map(group => ({
|
||||
...group,
|
||||
|
@ -251,7 +251,10 @@ const StyledFeatureText = styled('div')`
|
||||
const Home = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const majorMinorThemes = useMemo(() => releases.filter(r => r.type !== 'patch'), []);
|
||||
const majorMinorReleases = useMemo(
|
||||
() => releases.filter(r => ['major', 'minor'].includes(r.type)),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<Page url="/" docsGroups={docsGroups} searchablePages={searchablePages} fullWidth>
|
||||
@ -328,11 +331,11 @@ const Home = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
<Container>
|
||||
<StyledReleasesSectionContent>
|
||||
{[...Array(3)].map((_, index) => {
|
||||
if (index >= majorMinorThemes.length) {
|
||||
if (index >= majorMinorReleases.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const release = majorMinorThemes[index];
|
||||
const release = majorMinorReleases[index];
|
||||
return (
|
||||
<CardActionArea
|
||||
key={release.version}
|
||||
|
@ -6,6 +6,7 @@ import { styled } from '@mui/material/styles';
|
||||
import format from 'date-fns/format';
|
||||
import parseISO from 'date-fns/parseISO';
|
||||
import Link from 'next/link';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import Container from '../components/layout/Container';
|
||||
import Page from '../components/layout/Page';
|
||||
@ -94,7 +95,33 @@ const StyledLink = styled(Link)(
|
||||
`,
|
||||
);
|
||||
|
||||
function getVersionNumber(version: string): number {
|
||||
return +version.replace('v', '');
|
||||
}
|
||||
|
||||
function isNextVersion(latestMajorVersionNumber: number, version: string): boolean {
|
||||
if (getVersionNumber(version) > latestMajorVersionNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMajorVersion(version: string): string {
|
||||
return version.split('.')[0];
|
||||
}
|
||||
|
||||
const Releases = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
const latestMajorVersion = useMemo(
|
||||
() => getMajorVersion((releaseData.find(r => r.type === 'major') ?? releaseData[0]).version),
|
||||
[],
|
||||
);
|
||||
|
||||
const latestMajorVersionNumber = useMemo(
|
||||
() => getVersionNumber(latestMajorVersion),
|
||||
[latestMajorVersion],
|
||||
);
|
||||
|
||||
return (
|
||||
<Page url="/releases" docsGroups={docsGroups} searchablePages={searchablePages} fullWidth>
|
||||
<StyledReleaseContent>
|
||||
@ -125,31 +152,50 @@ const Releases = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
</Container>
|
||||
<Container>
|
||||
<StyledReleaseLinksContent>
|
||||
{releaseData.map(release => (
|
||||
<StyledReleaseSection key={release.version}>
|
||||
<Typography variant="h3" color="primary.main">
|
||||
<strong>{release.version}</strong>
|
||||
|
||||
<Box component="small" sx={{ fontSize: '16px', opacity: 0.75 }}>
|
||||
{format(parseISO(release.date), 'MMM dd, yyyy')}
|
||||
</Box>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
component="div"
|
||||
color="inherit"
|
||||
sx={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
{isNotEmpty(release.description) ? release.description : null}
|
||||
<StyledLink
|
||||
href={`${config.repo_url}/releases/tag/${release.version}`}
|
||||
target="_blank"
|
||||
{releaseData.map(release => {
|
||||
const majorVersion = getMajorVersion(release.version);
|
||||
const isNext = isNextVersion(latestMajorVersionNumber, majorVersion);
|
||||
|
||||
return (
|
||||
<StyledReleaseSection key={release.version}>
|
||||
<Typography variant="h3" color="primary.main">
|
||||
<strong>{release.version}</strong>
|
||||
|
||||
<Box component="small" sx={{ fontSize: '16px', opacity: 0.75 }}>
|
||||
{format(parseISO(release.date), 'MMM dd, yyyy')}
|
||||
</Box>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
component="div"
|
||||
color="inherit"
|
||||
sx={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
Changelog
|
||||
</StyledLink>
|
||||
</Typography>
|
||||
</StyledReleaseSection>
|
||||
))}
|
||||
{isNotEmpty(release.description) ? release.description : null}
|
||||
<Box sx={{ display: 'flex', gap: '8px' }}>
|
||||
<StyledLink
|
||||
href={`${config.repo_url}/releases/tag/${release.version}`}
|
||||
target="_blank"
|
||||
>
|
||||
Changelog
|
||||
</StyledLink>
|
||||
<StyledLink
|
||||
href={`https://${
|
||||
isNext
|
||||
? 'next'
|
||||
: majorVersion !== latestMajorVersion
|
||||
? majorVersion
|
||||
: 'www'
|
||||
}.staticcms.org/docs`}
|
||||
target={majorVersion !== latestMajorVersion ? '_blank' : undefined}
|
||||
>
|
||||
Docs
|
||||
</StyledLink>
|
||||
</Box>
|
||||
</Typography>
|
||||
</StyledReleaseSection>
|
||||
);
|
||||
})}
|
||||
</StyledReleaseLinksContent>
|
||||
</Container>
|
||||
</StyledReleaseLinks>
|
||||
|
Reference in New Issue
Block a user