Improve documentation, better typing on media folder selection
This commit is contained in:
parent
590681d64e
commit
fdd51aefa3
@ -520,8 +520,6 @@ export interface BaseField {
|
||||
hint?: string;
|
||||
pattern?: [string, string];
|
||||
i18n?: boolean | 'translate' | 'duplicate' | 'none';
|
||||
media_folder?: string;
|
||||
public_folder?: string;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
@ -559,7 +557,7 @@ export interface DateTimeField extends BaseField {
|
||||
format?: string;
|
||||
date_format?: boolean | string;
|
||||
time_format?: boolean | string;
|
||||
picker_utc?: boolean; // TODO Reimplement
|
||||
picker_utc?: boolean;
|
||||
}
|
||||
|
||||
export interface FileOrImageField extends BaseField {
|
||||
@ -567,6 +565,8 @@ export interface FileOrImageField extends BaseField {
|
||||
default?: string;
|
||||
|
||||
media_library?: MediaLibrary;
|
||||
media_folder?: string;
|
||||
public_folder?: string;
|
||||
private?: boolean;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,17 @@ import { folderFormatter } from '../formatters';
|
||||
import { joinUrlPath } from '../urlHelper';
|
||||
import { basename, isAbsolutePath } from '.';
|
||||
|
||||
import type { Config, Field, Collection, CollectionFile, Entry } from '../../interface';
|
||||
import type {
|
||||
Config,
|
||||
Field,
|
||||
Collection,
|
||||
CollectionFile,
|
||||
Entry,
|
||||
FileOrImageField,
|
||||
MarkdownField,
|
||||
ListField,
|
||||
ObjectField,
|
||||
} from '../../interface';
|
||||
|
||||
export const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES';
|
||||
|
||||
@ -14,17 +24,28 @@ function getFileField(collectionFiles: CollectionFile[], slug: string | undefine
|
||||
return file;
|
||||
}
|
||||
|
||||
function isMediaField(
|
||||
folderKey: 'media_folder' | 'public_folder',
|
||||
field: Field | undefined,
|
||||
): field is FileOrImageField | MarkdownField {
|
||||
return Boolean(field && folderKey in field);
|
||||
}
|
||||
|
||||
function hasCustomFolder(
|
||||
folderKey: 'media_folder' | 'public_folder',
|
||||
collection: Collection | undefined | null,
|
||||
slug: string | undefined,
|
||||
field: Field | undefined,
|
||||
) {
|
||||
): field is FileOrImageField | MarkdownField {
|
||||
if (!collection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (field && field[folderKey]) {
|
||||
if (!isMediaField(folderKey, field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (field[folderKey]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -47,7 +68,7 @@ function evaluateFolder(
|
||||
config: Config,
|
||||
c: Collection,
|
||||
entryMap: Entry | undefined,
|
||||
field: Field | undefined,
|
||||
field: FileOrImageField | MarkdownField,
|
||||
) {
|
||||
let currentFolder = config[folderKey]!;
|
||||
|
||||
@ -140,12 +161,17 @@ function traverseFields(
|
||||
config: Config,
|
||||
collection: Collection,
|
||||
entryMap: Entry | undefined,
|
||||
field: Field,
|
||||
field: FileOrImageField | MarkdownField | ListField | ObjectField,
|
||||
fields: Field[],
|
||||
currentFolder: string,
|
||||
): string | null {
|
||||
const matchedField = fields.filter(f => f === field)[0];
|
||||
if (matchedField) {
|
||||
const matchedField = fields.filter(f => f === field)[0] as
|
||||
| FileOrImageField
|
||||
| MarkdownField
|
||||
| ListField
|
||||
| ObjectField
|
||||
| undefined;
|
||||
if (matchedField && isMediaField(folderKey, matchedField)) {
|
||||
return folderFormatter(
|
||||
matchedField[folderKey] ? matchedField[folderKey]! : `{{${folderKey}}}`,
|
||||
entryMap,
|
||||
@ -157,13 +183,13 @@ function traverseFields(
|
||||
}
|
||||
|
||||
for (const f of fields) {
|
||||
const field = { ...f };
|
||||
if (!field[folderKey]) {
|
||||
const childField: Field = { ...f };
|
||||
if (isMediaField(folderKey, childField) && !childField[folderKey]) {
|
||||
// add identity template if doesn't exist
|
||||
field[folderKey] = `{{${folderKey}}}`;
|
||||
childField[folderKey] = `{{${folderKey}}}`;
|
||||
}
|
||||
const folder = folderFormatter(
|
||||
field[folderKey]!,
|
||||
isMediaField(folderKey, childField) ? childField[folderKey] ?? '' : '',
|
||||
entryMap,
|
||||
collection,
|
||||
currentFolder,
|
||||
@ -171,24 +197,24 @@ function traverseFields(
|
||||
config.slug,
|
||||
);
|
||||
let fieldFolder = null;
|
||||
if ('fields' in field && field.fields) {
|
||||
if ('fields' in childField && childField.fields) {
|
||||
fieldFolder = traverseFields(
|
||||
folderKey,
|
||||
config,
|
||||
collection,
|
||||
entryMap,
|
||||
field,
|
||||
field.fields,
|
||||
childField,
|
||||
childField.fields,
|
||||
folder,
|
||||
);
|
||||
} else if ('types' in field && field.types) {
|
||||
} else if ('types' in childField && childField.types) {
|
||||
fieldFolder = traverseFields(
|
||||
folderKey,
|
||||
config,
|
||||
collection,
|
||||
entryMap,
|
||||
field,
|
||||
field.types,
|
||||
childField,
|
||||
childField.types,
|
||||
folder,
|
||||
);
|
||||
}
|
||||
@ -209,9 +235,7 @@ export function selectMediaFolder(
|
||||
const name = 'media_folder';
|
||||
let mediaFolder = config[name];
|
||||
|
||||
const customFolder = hasCustomFolder(name, collection, entryMap?.slug, field);
|
||||
|
||||
if (customFolder) {
|
||||
if (hasCustomFolder(name, collection, entryMap?.slug, field)) {
|
||||
const folder = evaluateFolder(name, config, collection!, entryMap, field);
|
||||
if (folder.startsWith('/')) {
|
||||
// return absolute paths as is
|
||||
|
@ -64,12 +64,9 @@ const DateTimeControl = ({
|
||||
const format = field.format;
|
||||
|
||||
// dateFormat and timeFormat are strictly for modifying input field with the date/time pickers
|
||||
const dateFormat: string | boolean = field.date_format ?? false;
|
||||
const dateFormat: string | boolean = field.date_format ?? true;
|
||||
// show time-picker? false hides it, true shows it using default format
|
||||
let timeFormat: string | boolean = field.time_format ?? false;
|
||||
if (typeof timeFormat === 'undefined') {
|
||||
timeFormat = true;
|
||||
}
|
||||
const timeFormat: string | boolean = field.time_format ?? true;
|
||||
|
||||
return {
|
||||
format,
|
||||
|
@ -3,9 +3,10 @@ group: Accounts
|
||||
title: Azure
|
||||
weight: 20
|
||||
---
|
||||
|
||||
For repositories stored on Azure, the `azure` backend allows CMS users to log in directly with their Azure account. Note that all users must have write access to your content repository for this to work.
|
||||
|
||||
## Authentication
|
||||
|
||||
In order to get Static CMS working with Azure DevOps, you need a Tenant Id and an Application Id.
|
||||
|
||||
1. If you do not have an Azure account, [create one here](https://azure.microsoft.com/en-us/free/?WT.mc_id=A261C142F) and make sure to have a credit card linked to the account.
|
||||
|
@ -5,7 +5,9 @@ weight: 20
|
||||
---
|
||||
For repositories stored on Bitbucket, the `bitbucket` backend allows CMS users to log in directly with their Bitbucket account. Note that all users must have write access to your content repository for this to work.
|
||||
|
||||
To enable it:
|
||||
## Authentication
|
||||
|
||||
To enable Bitbucket authentication it:
|
||||
|
||||
1. Follow the authentication provider setup steps in the [Netlify docs](https://www.netlify.com/docs/authentication-providers/#using-an-authentication-provider).
|
||||
2. Add the following lines to your Static CMS `config.yml` file:
|
||||
|
@ -5,6 +5,8 @@ weight: 30
|
||||
---
|
||||
For repositories stored on GitHub, the `github` backend allows CMS users to log in directly with their GitHub account. Note that all users must have push access to your content repository for this to work.
|
||||
|
||||
## Authentication
|
||||
|
||||
Because Github requires a server for authentication, Netlify facilitates basic GitHub authentication.
|
||||
|
||||
To enable basic GitHub authentication:
|
||||
|
@ -7,7 +7,7 @@ For repositories stored on GitLab, the `gitlab` backend allows CMS users to log
|
||||
|
||||
**Note:** GitLab default branch is protected by default, thus typically requires `maintainer` permissions in order for users to have push access.
|
||||
|
||||
## Authorization
|
||||
## Authentication
|
||||
|
||||
With GitLab's PKCE authorization, users can authenticate with GitLab directly from the client. To do this:
|
||||
|
||||
|
@ -6,12 +6,19 @@ weight: 10
|
||||
|
||||
The boolean widget translates a toggle switch input to a true/false value.
|
||||
|
||||
- **Name:** `boolean`
|
||||
- **UI:** toggle switch
|
||||
- **Data type:** boolean
|
||||
- **Options:**
|
||||
- `default`: accepts `true` or `false`; defaults to `false` when `required` is set to `false`
|
||||
- **Example:**
|
||||
```yaml
|
||||
- {label: "Draft", title: "draft", widget: "boolean", default: true}
|
||||
```
|
||||
## Widget options
|
||||
|
||||
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|
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
name: draft
|
||||
label: Draft
|
||||
widget: boolean
|
||||
default: true
|
||||
```
|
||||
|
@ -6,18 +6,21 @@ weight: 11
|
||||
|
||||
The code widget provides a code editor (powered by [Codemirror](https://codemirror.net)) with optional syntax awareness. Can output the raw code value or an object with the selected language and the raw code value.
|
||||
|
||||
- **Name:** `code`
|
||||
- **UI:** code editor
|
||||
- **Data type:** string
|
||||
- **Options:**
|
||||
- `default_language`: optional; default language to use
|
||||
- `allow_language_selection`: optional; defaults to `false`: allows syntax to be changed
|
||||
- `keys`: optional; sets key names for code and lang if outputting an object; defaults to `{ code: 'code', lang: 'lang' }`
|
||||
- `output_code_only`: set to `true` to output the string value only, defaults to `false`
|
||||
## Widget options
|
||||
|
||||
- **Example:**
|
||||
```yaml
|
||||
- label: 'Code'
|
||||
title: 'code'
|
||||
widget: 'code'
|
||||
```
|
||||
For common options, see [Common widget options](/docs/widgets#common-widget-options).
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------------------ | ------- | -------------------------------- | -------------------------------------------------------------------- |
|
||||
| default_language | string | | _Optional_. Default language to use |
|
||||
| allow_language_selection | boolean | `false` | _Optional_. Allows language syntax to be changed |
|
||||
| keys | boolean | `{ code: 'code', lang: 'lang' }` | _Optional_. Sets key names for code and lang if outputting an object |
|
||||
| output_code_only | string | `true` | _Optional_. Set to `true` to output the string value only |
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
name: code
|
||||
label: Code
|
||||
widget: code
|
||||
```
|
||||
|
@ -6,18 +6,31 @@ weight: 12
|
||||
|
||||
The color widget translates a color picker to a color string.
|
||||
|
||||
- **Name:** `color`
|
||||
- **UI:** color picker
|
||||
- **Data type:** string
|
||||
- **Options:**
|
||||
- `default`: accepts a string; defaults to an empty string. Sets the default value
|
||||
- `allow_input`: accepts a boolean, defaults to `false`. Allows manual editing of the color input value
|
||||
- `enable_alpha`: accepts a boolean, defaults to `false`. Enables Alpha editing
|
||||
- **Example:**
|
||||
```yaml
|
||||
- { label: 'Color', title: 'color', widget: 'color' }
|
||||
```
|
||||
- **Example:**
|
||||
```yaml
|
||||
- { label: 'Color', title: 'color', widget: 'color', enable_alpha: true, allow_input: true }
|
||||
```
|
||||
## Widget options
|
||||
|
||||
For common options, see [Common widget options](/docs/widgets#common-widget-options).
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------ | ------- | ------- | ---------------------------------------------------------- |
|
||||
| default | string | `''` | _Optional_. The default value for the field |
|
||||
| allow_input | boolean | `false` | _Optional_. Allows manual editing of the color input value |
|
||||
| enable_alpha | boolean | `false` | _Optional_. Enables Alpha editing |
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
```yaml
|
||||
name: color
|
||||
label: Color
|
||||
widget: color
|
||||
```
|
||||
|
||||
### Kitchen Sink
|
||||
|
||||
```yaml
|
||||
name: color
|
||||
label: Color
|
||||
widget: color
|
||||
enable_alpha: true
|
||||
allow_input: true
|
||||
```
|
||||
|
@ -6,23 +6,49 @@ weight: 13
|
||||
|
||||
The datetime widget translates a datetime picker to a datetime string.
|
||||
|
||||
- **Name:** `datetime`
|
||||
- **UI:** datetime picker
|
||||
- **Data type:** Moment.js-formatted datetime string
|
||||
- **Options:**
|
||||
- `default`: accepts a datetime string, or an empty string to accept blank input; otherwise defaults to current datetime
|
||||
- `format`: sets storage format; accepts Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/); defaults to raw Date object (if supported by output format)
|
||||
- `date_format`: sets date display format in UI; boolean or Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/). If `true` use default locale format.
|
||||
- `time_format`: sets time display format in UI; boolean or Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/). If `true` use default locale format, `false` hides time-picker.
|
||||
- `picker_utc`: _(default: `false`)_ when set to `true`, the datetime picker will display times in UTC. When `false`, the datetime picker will display times in the user's local timezone. 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.
|
||||
- **Example:**
|
||||
```yaml
|
||||
- label: "Start time"
|
||||
title: "start"
|
||||
widget: "datetime"
|
||||
default: ""
|
||||
date_format: "DD.MM.YYYY" # e.g. 24.12.2021
|
||||
time_format: "HH:mm" # e.g. 21:07
|
||||
format: "LLL"
|
||||
picker_utc: false
|
||||
```
|
||||
## Widget options
|
||||
|
||||
For common options, see [Common widget options](/docs/widgets#common-widget-options).
|
||||
|
||||
| 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> |
|
||||
| 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
|
||||
|
||||
### Date Time Picker
|
||||
|
||||
```yaml
|
||||
name: 'datetime'
|
||||
label: 'Datetime'
|
||||
widget: 'datetime'
|
||||
date_format: 'dd.MM.yyyy' # e.g. 24.12.2022
|
||||
time_format: 'HH:mm' # e.g. 21:07
|
||||
format: 'yyyy-MM-dd HH:mm' # e.g. 2022-12-24 21:07
|
||||
```
|
||||
|
||||
### Date Picker
|
||||
|
||||
```yaml
|
||||
name: 'date'
|
||||
label: 'Date'
|
||||
widget: 'datetime'
|
||||
date_format: 'dd.MM.yyyy' # e.g. 24.12.2022
|
||||
time_format: false
|
||||
format: 'yyyy-MM-dd' # e.g. 2022-12-24
|
||||
```
|
||||
|
||||
### Time Picker
|
||||
|
||||
```yaml
|
||||
name: 'date'
|
||||
label: 'Date'
|
||||
widget: 'datetime'
|
||||
date_format: false
|
||||
time_format: 'HH:mm' # e.g. 21:07
|
||||
format: 'HH:mm' # e.g. 21:07
|
||||
```
|
||||
|
@ -4,23 +4,34 @@ title: Overview
|
||||
weight: 0
|
||||
---
|
||||
|
||||
Widgets define the data type and interface for entry fields. Static CMS comes with several built-in widgets. Click the widget names in the sidebar to jump to specific widget details. We're always adding new widgets, and you can also [create your own](/docs/custom-widgets)!
|
||||
Widgets define the data type and interface for entry fields. Static CMS comes with several built-in widgets. Click the widget names in the sidebar to jump to specific widget details. You can also [create your own](/docs/custom-widgets)!
|
||||
|
||||
Widgets are specified as collection fields in the Static CMS `config.yml` file. Note that [YAML syntax](https://en.wikipedia.org/wiki/YAML#Basic_components) allows lists and objects to be written in block or inline style, and the code samples below include a mix of both.
|
||||
|
||||
To see working examples of all of the built-in widgets, try making a 'Kitchen Sink' collection item on the [CMS demo site](https://cms-demo.netlify.com). (No login required: click the login button and the CMS will open.) You can refer to the demo [configuration code](https://github.com/StaticJsCMS/static-cms/blob/main/dev-test/config.yml) to see how each field was configured.
|
||||
To see working examples of all of the built-in widgets, try making a 'Kitchen Sink' collection item on the [CMS demo site](https://static-cms-demo.netlify.com). (No login required: click the login button and the CMS will open.) You can refer to the demo [configuration code](https://github.com/StaticJsCMS/static-cms/blob/main/dev-test/config.yml) to see how each field was configured.
|
||||
|
||||
## Common widget options
|
||||
|
||||
The following options are available on all fields:
|
||||
|
||||
- `required`: specify as `false` to make a field optional; defaults to `true`
|
||||
- `hint`: optionally add helper text directly below a widget. Useful for including instructions. Accepts markdown for bold, italic, strikethrough, and links.
|
||||
- `pattern`: add 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)
|
||||
- **Example:**
|
||||
```yaml
|
||||
label: "Title"
|
||||
title: "title"
|
||||
widget: "string"
|
||||
pattern: ['.{12,}', "Must have at least 12 characters"]
|
||||
```
|
||||
| Name | Type | Default | Description |
|
||||
| ------------- | ----------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | string | | The name of the field |
|
||||
| widget | string | `'string'` | _Optional_. The type of widget to render for the field |
|
||||
| label | string | `name` | _Optional_. The display name of the field |
|
||||
| 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 | string | | _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_. <img src="https://img.shields.io/badge/-Beta%20Feature-blue" alt="Beta Feature" /><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> |
|
||||
| media_folder | string | | _Optional_. Specifies the folder path where uploaded files should be saved, relative to the base of the repo |
|
||||
| public_folder | string | | _Optional_. Specifies the folder path where the files uploaded by the media library will be accessed, relative to the base of the built site |
|
||||
| comment | string | | _Optional_. Adds comment before the field (only supported for yaml) |
|
||||
|
||||
### Example
|
||||
|
||||
```yaml
|
||||
name: title
|
||||
label: Title
|
||||
widget: string
|
||||
pattern: ['.{12,}', 'Must have at least 12 characters']
|
||||
```
|
||||
|
@ -155,6 +155,19 @@ const DocsContent = styled('div')(
|
||||
}
|
||||
}
|
||||
|
||||
& table thead tr th,
|
||||
& table thead tr td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
& table tbody tr td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
& table tbody tr td:last-child {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
& pre {
|
||||
display: block;
|
||||
line-height: 1.25rem;
|
||||
@ -197,8 +210,9 @@ const DocsContent = styled('div')(
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
color: ${theme.palette.text.primary};
|
||||
background-color: ${
|
||||
theme.palette.mode === 'light' ? 'rgba(175,184,193,0.2)' : 'rgba(110,118,129,0.4)'
|
||||
theme.palette.mode === 'light' ? 'rgba(175,184,193,0.2)' : 'rgba(110,118,129,0.75)'
|
||||
};
|
||||
}
|
||||
|
||||
@ -222,59 +236,6 @@ const DocsContent = styled('div')(
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
& table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
border-spacing: 0;
|
||||
margin: 24px 0;
|
||||
border: 1px solid ${theme.palette.text.secondary};
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.editor table {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
& table thead {
|
||||
background: ${theme.palette.background.paper};
|
||||
}
|
||||
|
||||
& table th,
|
||||
& table thead td {
|
||||
font-weight: 700;
|
||||
height: 56px;
|
||||
box-sizing: border-box;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
& table th,
|
||||
& table thead td,
|
||||
& table td {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
& table tr:not(:first-of-type) th,
|
||||
& table tr:not(:first-of-type) thead td,
|
||||
& table tbody tr td {
|
||||
border-top: 1px solid ${theme.palette.text.secondary};
|
||||
}
|
||||
|
||||
& table tr td {
|
||||
background-color: ${theme.palette.background.paper};
|
||||
}
|
||||
|
||||
& table tbody tr td {
|
||||
height: 52px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
& table tbody tr:hover td {
|
||||
background-color: ${theme.palette.background.paper};
|
||||
}
|
||||
|
||||
& ol,
|
||||
& ul {
|
||||
padding: 0 0 0 1.5rem;
|
||||
|
34
website/src/components/docs/components/table/Table.tsx
Normal file
34
website/src/components/docs/components/table/Table.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const StyledTableContainer = styled(TableContainer)(
|
||||
({ theme }) => `
|
||||
& td {
|
||||
color: ${theme.palette.text.secondary};
|
||||
}
|
||||
|
||||
& td:nth-of-type(2) {
|
||||
color:
|
||||
${theme.palette.mode === 'light' ? '#751365' : '#ffb6ec'};
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
interface DocsTableProps {
|
||||
children?: ReactNode | ReactNode[];
|
||||
}
|
||||
|
||||
const DocsTable = ({ children = [] }: DocsTableProps) => {
|
||||
return (
|
||||
<StyledTableContainer>
|
||||
<Table sx={{ width: '100%' }} aria-label="doc table">
|
||||
{children}
|
||||
</Table>
|
||||
</StyledTableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocsTable;
|
13
website/src/components/docs/components/table/TableBody.tsx
Normal file
13
website/src/components/docs/components/table/TableBody.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import MuiTableBody from '@mui/material/TableBody';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TableBodyProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const TableBody = ({ children }: TableBodyProps) => {
|
||||
return <MuiTableBody>{children}</MuiTableBody>;
|
||||
};
|
||||
|
||||
export default TableBody;
|
@ -0,0 +1,37 @@
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TableBodyCellProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const TableBodyCell = ({ children }: TableBodyCellProps) => {
|
||||
return (
|
||||
<TableCell
|
||||
scope="row"
|
||||
sx={{
|
||||
padding: '16px 12px',
|
||||
'&:first-child, &:first-child': {
|
||||
paddingLeft: 0,
|
||||
},
|
||||
'&:last-child, &:last-child': {
|
||||
paddingRight: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
fontSize: '13px',
|
||||
fontFamily: 'Consolas, Menlo, Monaco, Andale Mono, Ubuntu Mono, monospace',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableBodyCell;
|
13
website/src/components/docs/components/table/TableHead.tsx
Normal file
13
website/src/components/docs/components/table/TableHead.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import MuiTableHead from '@mui/material/TableHead';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TableHeadProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const TableHead = ({ children }: TableHeadProps) => {
|
||||
return <MuiTableHead>{children}</MuiTableHead>;
|
||||
};
|
||||
|
||||
export default TableHead;
|
@ -0,0 +1,28 @@
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TableHeaderCellProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const TableHeaderCell = ({ children }: TableHeaderCellProps) => {
|
||||
return (
|
||||
<TableCell
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
padding: '16px 12px',
|
||||
'&:first-child, &:first-child': {
|
||||
paddingLeft: 0,
|
||||
},
|
||||
'&:last-child, &:last-child': {
|
||||
paddingRight: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</TableCell>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableHeaderCell;
|
15
website/src/components/docs/components/table/TableRow.tsx
Normal file
15
website/src/components/docs/components/table/TableRow.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import MuiTableRow from '@mui/material/TableRow';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TableRowProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const TableRow = ({ children }: TableRowProps) => {
|
||||
return (
|
||||
<MuiTableRow sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>{children}</MuiTableRow>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableRow;
|
@ -7,6 +7,11 @@ import remarkGfm from 'remark-gfm';
|
||||
import Blockquote from '../../components/docs/components/Blockquote';
|
||||
import Header2 from '../../components/docs/components/Header2';
|
||||
import Header3 from '../../components/docs/components/Header3';
|
||||
import DocsTable from '../../components/docs/components/table/Table';
|
||||
import TableBody from '../../components/docs/components/table/TableBody';
|
||||
import TableBodyCell from '../../components/docs/components/table/TableBodyCell';
|
||||
import TableHead from '../../components/docs/components/table/TableHead';
|
||||
import TableHeaderCell from '../../components/docs/components/table/TableHeaderCell';
|
||||
import DocsContent from '../../components/docs/DocsContent';
|
||||
import DocsLeftNav from '../../components/docs/DocsLeftNav';
|
||||
import DocsRightNav from '../../components/docs/DocsRightNav';
|
||||
@ -87,7 +92,16 @@ const Docs = ({ docsGroups, title, slug, description = '', source }: DocsProps)
|
||||
<Typography variant="h1">{title}</Typography>
|
||||
<MDXRemote
|
||||
{...source}
|
||||
components={{ h2: Header2, h3: Header3, blockquote: Blockquote }}
|
||||
components={{
|
||||
h2: Header2,
|
||||
h3: Header3,
|
||||
blockquote: Blockquote,
|
||||
table: DocsTable,
|
||||
thead: TableHead,
|
||||
tbody: TableBody,
|
||||
th: TableHeaderCell,
|
||||
td: TableBodyCell,
|
||||
}}
|
||||
/>
|
||||
</DocsContent>
|
||||
</StyledDocsContentWrapper>
|
||||
|
Loading…
x
Reference in New Issue
Block a user