feat: markdown widget docs and basic editor stylings (#226)
This commit is contained in:
parent
6602f37495
commit
e191e6d691
@ -56,7 +56,7 @@ collections:
|
|||||||
required: false
|
required: false
|
||||||
- label: Body
|
- label: Body
|
||||||
name: body
|
name: body
|
||||||
widget: mdx
|
widget: markdown
|
||||||
hint: Main content goes here.
|
hint: Main content goes here.
|
||||||
- name: faq
|
- name: faq
|
||||||
label: FAQ
|
label: FAQ
|
||||||
|
@ -77,7 +77,12 @@ import {
|
|||||||
UnorderedListElement,
|
UnorderedListElement,
|
||||||
} from './components/nodes/list';
|
} from './components/nodes/list';
|
||||||
import ParagraphElement from './components/nodes/paragraph/ParagraphElement';
|
import ParagraphElement from './components/nodes/paragraph/ParagraphElement';
|
||||||
import { TableCellElement, TableElement, TableRowElement } from './components/nodes/table';
|
import {
|
||||||
|
TableCellElement,
|
||||||
|
TableElement,
|
||||||
|
TableHeaderCellElement,
|
||||||
|
TableRowElement,
|
||||||
|
} from './components/nodes/table';
|
||||||
import { Toolbar } from './components/toolbar';
|
import { Toolbar } from './components/toolbar';
|
||||||
import editableProps from './editableProps';
|
import editableProps from './editableProps';
|
||||||
import { createMdPlugins, ELEMENT_SHORTCODE } from './plateTypes';
|
import { createMdPlugins, ELEMENT_SHORTCODE } from './plateTypes';
|
||||||
@ -152,7 +157,7 @@ const PlateEditor: FC<PlateEditorProps> = ({
|
|||||||
[ELEMENT_PARAGRAPH]: ParagraphElement,
|
[ELEMENT_PARAGRAPH]: ParagraphElement,
|
||||||
[ELEMENT_TABLE]: TableElement,
|
[ELEMENT_TABLE]: TableElement,
|
||||||
[ELEMENT_TR]: TableRowElement,
|
[ELEMENT_TR]: TableRowElement,
|
||||||
[ELEMENT_TH]: TableCellElement,
|
[ELEMENT_TH]: TableHeaderCellElement,
|
||||||
[ELEMENT_TD]: TableCellElement,
|
[ELEMENT_TD]: TableCellElement,
|
||||||
[ELEMENT_BLOCKQUOTE]: BlockquoteElement,
|
[ELEMENT_BLOCKQUOTE]: BlockquoteElement,
|
||||||
[ELEMENT_CODE_BLOCK]: CodeBlockElement,
|
[ELEMENT_CODE_BLOCK]: CodeBlockElement,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import Box from '@mui/system/Box';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { MdBlockquoteElement, MdValue } from '@staticcms/markdown';
|
import type { MdBlockquoteElement, MdValue } from '@staticcms/markdown';
|
||||||
@ -7,7 +8,14 @@ import type { FC } from 'react';
|
|||||||
const BlockquoteElement: FC<PlateRenderElementProps<MdValue, MdBlockquoteElement>> = ({
|
const BlockquoteElement: FC<PlateRenderElementProps<MdValue, MdBlockquoteElement>> = ({
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
return <blockquote>{children}</blockquote>;
|
return (
|
||||||
|
<Box
|
||||||
|
component="blockquote"
|
||||||
|
sx={{ borderLeft: '2px solid rgba(209,213,219,0.5)', marginLeft: '8px', paddingLeft: '8px' }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BlockquoteElement;
|
export default BlockquoteElement;
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
|
import Box from '@mui/material/Box';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { MdTableCellElement, MdValue } from '@staticcms/markdown';
|
import type { MdTableCellElement, MdValue } from '@staticcms/markdown';
|
||||||
import type { PlateRenderElementProps } from '@udecode/plate';
|
import type { PlateRenderElementProps } from '@udecode/plate';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
const TableCellElement: FC<PlateRenderElementProps<MdValue, MdTableCellElement>> = ({
|
const TableHeaderCellElement: FC<PlateRenderElementProps<MdValue, MdTableCellElement>> = ({
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
nodeProps,
|
nodeProps,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<td {...attributes} {...nodeProps}>
|
<Box
|
||||||
|
component="td"
|
||||||
|
{...attributes}
|
||||||
|
{...nodeProps}
|
||||||
|
sx={{
|
||||||
|
padding: '8px',
|
||||||
|
'&:not(:last-of-type)': {
|
||||||
|
borderRight: '1px solid rgba(209,213,219,0.5)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
</td>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TableCellElement;
|
export default TableHeaderCellElement;
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import type { MdTableCellElement, MdValue } from '@staticcms/markdown';
|
||||||
|
import type { PlateRenderElementProps } from '@udecode/plate';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
const TableHeaderCellElement: FC<PlateRenderElementProps<MdValue, MdTableCellElement>> = ({
|
||||||
|
attributes,
|
||||||
|
children,
|
||||||
|
nodeProps,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
component="th"
|
||||||
|
{...attributes}
|
||||||
|
{...nodeProps}
|
||||||
|
sx={{
|
||||||
|
padding: '8px',
|
||||||
|
background: 'rgb(244,245,247)',
|
||||||
|
textAlign: 'left',
|
||||||
|
'&:not(:last-of-type)': {
|
||||||
|
borderRight: '1px solid rgba(209,213,219,0.5)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>{children}</div>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeaderCellElement;
|
@ -1,2 +1,2 @@
|
|||||||
// eslint-disable-next-line import/prefer-default-export
|
|
||||||
export { default as TableCellElement } from './TableCellElement';
|
export { default as TableCellElement } from './TableCellElement';
|
||||||
|
export { default as TableHeaderCellElement } from './TableHeaderCellElement';
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import Box from '@mui/system/Box';
|
||||||
import { useSelectedCells } from '@udecode/plate';
|
import { useSelectedCells } from '@udecode/plate';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@ -13,9 +14,19 @@ const TableElement: FC<PlateRenderElementProps<MdValue, MdTableElement>> = ({
|
|||||||
useSelectedCells();
|
useSelectedCells();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table {...attributes} {...nodeProps}>
|
<Box
|
||||||
<tbody>{children}</tbody>
|
component="table"
|
||||||
</table>
|
{...attributes}
|
||||||
|
{...nodeProps}
|
||||||
|
sx={{ border: '1px solid rgba(209,213,219,0.75)', borderCollapse: 'collapse' }}
|
||||||
|
>
|
||||||
|
{children ? (
|
||||||
|
<>
|
||||||
|
<thead key="thead">{children[0]}</thead>
|
||||||
|
<tbody key="tbody">{children.slice(1)}</tbody>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Box from '@mui/system/Box';
|
||||||
|
|
||||||
import type { PlateRenderElementProps } from '@udecode/plate';
|
import type { PlateRenderElementProps } from '@udecode/plate';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@ -10,9 +11,18 @@ const TableRowElement: FC<PlateRenderElementProps<MdValue, MdTableRowElement>> =
|
|||||||
nodeProps,
|
nodeProps,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<tr {...attributes} {...nodeProps}>
|
<Box
|
||||||
|
component="tr"
|
||||||
|
{...attributes}
|
||||||
|
{...nodeProps}
|
||||||
|
sx={{
|
||||||
|
'&:only-of-type, &:not(:last-of-type)': {
|
||||||
|
borderBottom: '1px solid rgba(209,213,219,0.5)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</tr>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,62 +54,71 @@ This would render as:
|
|||||||
|
|
||||||
_Please note:_ The markdown widget outputs a raw markdown string. Your static site generator may or may not render the markdown to HTML automatically. Consult with your static site generator's documentation for more information about rendering markdown.
|
_Please note:_ The markdown widget outputs a raw markdown string. Your static site generator may or may not render the markdown to HTML automatically. Consult with your static site generator's documentation for more information about rendering markdown.
|
||||||
|
|
||||||
## Customization
|
## Shortcodes
|
||||||
|
|
||||||
Several customization options are available for the markdown editor. You can register the options by calling `setMarkdownEditorOptions` (also available on the global `window.CMS`).
|
Shortcodes can be added to customize the Markdown editor via `registerShortcode`.
|
||||||
|
|
||||||
### Available Options
|
### Usage
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
<CodeTabs>
|
||||||
| --------------- | ---------------------------- | ----------------------------------- | --------------------------------------------------------------------------- |
|
|
||||||
| initialEditType | 'markdown'<br />\| 'wysiwyg' | `'wysiwyg'` | _Optional_. Sets which editor view that is active when the editor is loaded |
|
|
||||||
| height | string | `'600px'` | _Optional_. Specify the height of the editor |
|
|
||||||
| toolbarItems | factory of list of strings | See [Toolbar Items](#toolbar-items) | _Optional_. See [Toolbar Items](#toolbar-items) |
|
|
||||||
| plugins | list of plugin factories | | _Optional_. See [Plugins](#plugins) |
|
|
||||||
|
|
||||||
### Toolbar Items
|
|
||||||
|
|
||||||
`toolbarItems` accepts a factory function that returns a list of toolbar buttons for the editor. See the [ToastUI Editor toolbar docs](https://github.com/nhn/tui.editor/blob/master/docs/en/toolbar.md).
|
|
||||||
|
|
||||||
#### Default Value
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
[
|
CMS.registerShortcode('youtube', {
|
||||||
['heading', 'bold', 'italic', 'strike'],
|
label: 'YouTube',
|
||||||
['hr', 'quote'],
|
openTag: '[',
|
||||||
['ul', 'ol', 'task', 'indent', 'outdent'],
|
closeTag: ']',
|
||||||
['table', imageToolbarButton, 'link'],
|
separator: '|',
|
||||||
['code', 'codeblock'],
|
toProps: args => {
|
||||||
];
|
if (args.length > 0) {
|
||||||
|
return { src: args[0] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { src: '' };
|
||||||
|
},
|
||||||
|
toArgs: ({ src }) => {
|
||||||
|
return [src];
|
||||||
|
},
|
||||||
|
control: ({ src, onChange }) => {
|
||||||
|
return h('span', {}, [
|
||||||
|
h('input', {
|
||||||
|
key: 'control-input',
|
||||||
|
value: src,
|
||||||
|
onChange: event => {
|
||||||
|
onChange({ src: event.target.value });
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
'iframe',
|
||||||
|
{
|
||||||
|
key: 'control-preview',
|
||||||
|
width: '420',
|
||||||
|
height: '315',
|
||||||
|
src: `https://www.youtube.com/embed/${src}`,
|
||||||
|
},
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
preview: ({ src }) => {
|
||||||
|
return h(
|
||||||
|
'span',
|
||||||
|
{},
|
||||||
|
h(
|
||||||
|
'iframe',
|
||||||
|
{
|
||||||
|
width: '420',
|
||||||
|
height: '315',
|
||||||
|
src: `https://www.youtube.com/embed/${src}`,
|
||||||
|
},
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Factory Props
|
```markdown
|
||||||
|
[youtube|p6h-rYSVX90]
|
||||||
| Name | Type | Description |
|
|
||||||
| ------------------ | ------------------ | ----------------------------------------------------------- |
|
|
||||||
| imageToolbarButton | ToolbarItemOptions | An image insert button tied into Static CMS's media library |
|
|
||||||
|
|
||||||
### Plugins
|
|
||||||
|
|
||||||
`plugins` accepts a list of factory functions that returns a plugin for the editor. See the [ToastUI Editor plugins docs](https://github.com/nhn/tui.editor/blob/master/docs/en/plugin.md).
|
|
||||||
|
|
||||||
#### Default Value
|
|
||||||
|
|
||||||
```js
|
|
||||||
[imagePlugin];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Factory Props
|
</CodeTabs>
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
| ------ | ----------------------- | ---------------------------------------------------------------------------------------------- |
|
|
||||||
| config | Config | The current Static CMS config. See [configuration options](/docs/configuration-options) |
|
|
||||||
| field | MarkdownField | The field configuration for the current Markdown widget. See [Widget Options](#widget-options) |
|
|
||||||
| media | MediaHolder | See [Media Holder](#media-holder) |
|
|
||||||
| mode | 'editor'<br />\| 'preview' | Specifies if your plugin is running in the markdown editor or the markdown preview |
|
|
||||||
|
|
||||||
##### Media Holder
|
|
||||||
|
|
||||||
Media holder is a javascript class that holds the loaded media assets (images or files) that are present in the markdown content. It exposes a method called `getMedia` that takes a `url` and returns the loaded image or file as an blob asset.
|
|
||||||
|
|
||||||
This is utilized by the `imagePlugin` to be able to render images present in the markdown that are currently only available in backend or are not yet persisted to the backend.
|
|
||||||
|
@ -55,6 +55,11 @@ const supportedLanguages: Record<string, CodeLanguage> = {
|
|||||||
grammar: Prism.languages.javascript,
|
grammar: Prism.languages.javascript,
|
||||||
language: 'javascript',
|
language: 'javascript',
|
||||||
},
|
},
|
||||||
|
'language-markdown': {
|
||||||
|
title: 'Markdown',
|
||||||
|
grammar: Prism.languages.markdown,
|
||||||
|
language: 'markdown',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TabData {
|
interface TabData {
|
||||||
|
@ -97,7 +97,9 @@ const SearchModal: FC<SearchModalProps> = ({ open, onClose, searchablePages }) =
|
|||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
setCanFocus(true);
|
setCanFocus(true);
|
||||||
onClose();
|
setTimeout(() => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
}, [onClose]);
|
}, [onClose]);
|
||||||
|
|
||||||
const handleSearchChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
const handleSearchChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
@ -24,6 +24,7 @@ require('prismjs/components/prism-json');
|
|||||||
require('prismjs/components/prism-toml');
|
require('prismjs/components/prism-toml');
|
||||||
require('prismjs/components/prism-markup-templating');
|
require('prismjs/components/prism-markup-templating');
|
||||||
require('prismjs/components/prism-handlebars');
|
require('prismjs/components/prism-handlebars');
|
||||||
|
require('prismjs/components/prism-markdown');
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
const [mode, setMode] = useState<PaletteMode>('dark');
|
const [mode, setMode] = useState<PaletteMode>('dark');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user