diff --git a/package.json b/package.json
index 3fe80dc..ca95248 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,8 @@
},
"dependencies": {
"prismjs": "1.29.0",
- "mermaid": "10.8.0"
+ "mermaid": "10.8.0",
+ "react-gist": "1.2.4"
},
"devDependencies": {
"@plone/scripts": "^3.0.0",
diff --git a/src/components/Blocks/Code/DefaultView.jsx b/src/components/Blocks/Code/DefaultView.jsx
index 98a82ca..a6ff73b 100644
--- a/src/components/Blocks/Code/DefaultView.jsx
+++ b/src/components/Blocks/Code/DefaultView.jsx
@@ -1,9 +1,11 @@
import React from 'react';
import SyntaxHighlighter from '../../SyntaxHighlighter/SyntaxHighlighter';
+import Caption from '../../Caption/Caption';
const CodeView = (props) => {
const { data } = props;
const { code, style, language, lineNbr, showLineNumbers, wrapLongLines } = data;
+ const { caption_title, caption_description } = data;
const styleWrap = wrapLongLines ? 'wrapLongLines' : '';
const className = `code-block-wrapper ${style} ${styleWrap}`;
@@ -16,6 +18,7 @@ const CodeView = (props) => {
)}
+ {caption_title &&
}
>
);
};
diff --git a/src/components/Blocks/Code/Edit.jsx b/src/components/Blocks/Code/Edit.jsx
index d4eb628..5b09ea9 100644
--- a/src/components/Blocks/Code/Edit.jsx
+++ b/src/components/Blocks/Code/Edit.jsx
@@ -3,6 +3,7 @@ import { withBlockExtensions } from '@plone/volto/helpers';
import { SidebarPortal } from '@plone/volto/components';
import config from '@plone/volto/registry';
import CodeBlockData from './Data';
+import Caption from '../../Caption/Caption.jsx';
import Editor from '../../Editor/Editor.tsx';
import { highlight } from 'prismjs/components/prism-core';
@@ -19,7 +20,7 @@ const CodeBlockEdit = (props) => {
}
const allLanguages = config.settings.codeBlock.languages;
const language = allLanguages[data.language].language;
-
+ const { caption_title, caption_description } = data;
const handleChange = (code) => {
setCode(code);
onChangeBlock(block, { ...data, code: code });
@@ -29,6 +30,7 @@ const CodeBlockEdit = (props) => {
handleChange(code)} highlight={(code) => highlight(code, language)} padding={10} preClassName={`code-block-wrapper ${data.style} language-${data.language}`} />
+ {caption_title && }
diff --git a/src/components/Blocks/Code/schema.js b/src/components/Blocks/Code/schema.js
index 1c06138..3a95453 100644
--- a/src/components/Blocks/Code/schema.js
+++ b/src/components/Blocks/Code/schema.js
@@ -27,6 +27,14 @@ const messages = defineMessages({
id: 'Starting Line Number',
defaultMessage: 'Starting Line Number',
},
+ caption_title: {
+ id: 'Title',
+ defaultMessage: 'Title',
+ },
+ caption_description: {
+ id: 'Description',
+ defaultMessage: 'Description',
+ },
});
export const codeSchema = (props) => {
@@ -53,6 +61,11 @@ export const codeSchema = (props) => {
title: 'Default',
fields: ['language', 'style', 'showLineNumbers', 'wrapLongLines', 'lineNbr'],
},
+ {
+ id: 'caption',
+ title: 'Caption',
+ fields: ['caption_title', 'caption_description'],
+ },
],
properties: {
@@ -83,6 +96,13 @@ export const codeSchema = (props) => {
type: 'integer',
default: 1,
},
+ caption_title: {
+ title: props.intl.formatMessage(messages.caption_title),
+ },
+ caption_description: {
+ title: props.intl.formatMessage(messages.caption_description),
+ widget: 'textarea',
+ },
},
required: ['language'],
};
diff --git a/src/components/Blocks/Gist/Data.jsx b/src/components/Blocks/Gist/Data.jsx
new file mode 100644
index 0000000..9408a37
--- /dev/null
+++ b/src/components/Blocks/Gist/Data.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { BlockDataForm } from '@plone/volto/components';
+import { gistSchema } from './schema';
+import { useIntl } from 'react-intl';
+
+const GistBlockData = (props) => {
+ const { data, block, onChangeBlock } = props;
+ const intl = useIntl();
+ const schema = gistSchema({ ...props, intl });
+
+ return (
+ {
+ onChangeBlock(block, {
+ ...data,
+ [id]: value,
+ });
+ }}
+ formData={data}
+ block={block}
+ />
+ );
+};
+
+export default GistBlockData;
diff --git a/src/components/Blocks/Gist/DefaultView.jsx b/src/components/Blocks/Gist/DefaultView.jsx
new file mode 100644
index 0000000..226489c
--- /dev/null
+++ b/src/components/Blocks/Gist/DefaultView.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import Gist from 'react-gist';
+import Caption from '../../Caption/Caption';
+
+const GistView = (props) => {
+ const { file, gistId, caption_title, caption_description } = props;
+ return (
+ <>
+ {gistId && }
+ {caption_title && }
+ >
+ );
+};
+
+export default GistView;
diff --git a/src/components/Blocks/Gist/Edit.jsx b/src/components/Blocks/Gist/Edit.jsx
new file mode 100644
index 0000000..6796727
--- /dev/null
+++ b/src/components/Blocks/Gist/Edit.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { withBlockExtensions } from '@plone/volto/helpers';
+import { SidebarPortal } from '@plone/volto/components';
+import GistBlockData from './Data';
+import View from './DefaultView';
+
+const GistBlockEdit = (props) => {
+ const { data, selected, block } = props;
+ const { gistId, file } = data;
+ const { caption_title, caption_description } = data;
+ return (
+
+ {data && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+ );
+};
+
+export default withBlockExtensions(GistBlockEdit);
diff --git a/src/components/Blocks/Gist/View.jsx b/src/components/Blocks/Gist/View.jsx
new file mode 100644
index 0000000..4b0baa9
--- /dev/null
+++ b/src/components/Blocks/Gist/View.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { withBlockExtensions } from '@plone/volto/helpers';
+import GistView from './DefaultView';
+
+const GistBlockView = (props) => {
+ const { data, block } = props;
+ const { gistId, file, caption_title, caption_description } = data;
+ return (
+
+ {data && }
+
+ );
+};
+
+export default withBlockExtensions(GistBlockView);
diff --git a/src/components/Blocks/Gist/schema.js b/src/components/Blocks/Gist/schema.js
new file mode 100644
index 0000000..cadc1d0
--- /dev/null
+++ b/src/components/Blocks/Gist/schema.js
@@ -0,0 +1,59 @@
+import { defineMessages } from 'react-intl';
+
+const messages = defineMessages({
+ gistBlock: {
+ id: 'Gist Block',
+ defaultMessage: 'Gist Block',
+ },
+ gistId: {
+ id: 'Gist Id',
+ defaultMessage: 'Gist Id',
+ },
+ file: {
+ id: 'File',
+ defaultMessage: 'File',
+ },
+ caption_title: {
+ id: 'Title',
+ defaultMessage: 'Title',
+ },
+ caption_description: {
+ id: 'Description',
+ defaultMessage: 'Description',
+ },
+});
+
+export const gistSchema = (props) => {
+ return {
+ title: props.intl.formatMessage(messages.gistBlock),
+ fieldsets: [
+ {
+ id: 'default',
+ title: 'Default',
+ fields: ['gistId', 'file'],
+ },
+ {
+ id: 'caption',
+ title: 'Caption',
+ fields: ['caption_title', 'caption_description'],
+ },
+ ],
+
+ properties: {
+ gistId: {
+ title: props.intl.formatMessage(messages.gistId),
+ },
+ file: {
+ title: props.intl.formatMessage(messages.file),
+ },
+ caption_title: {
+ title: props.intl.formatMessage(messages.caption_title),
+ },
+ caption_description: {
+ title: props.intl.formatMessage(messages.caption_description),
+ widget: 'textarea',
+ },
+ },
+ required: ['gistId'],
+ };
+};
diff --git a/src/components/Caption/Caption.jsx b/src/components/Caption/Caption.jsx
new file mode 100644
index 0000000..6613fb8
--- /dev/null
+++ b/src/components/Caption/Caption.jsx
@@ -0,0 +1,39 @@
+/**
+ * @module components/Caption
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * Image/video caption component class.
+ * @function Caption
+ * @params {string} title Caption title.
+ * @params {string} description Caption description.
+ * @returns {string} Markup of the component.
+ */
+const Caption = ({ title, description }) => {
+ return (
+
+ {title &&
{title}
}
+ {description && (
+
+ {description.split('\n').map((line, index) => (
+
{line || '\u00A0'}
+ ))}
+
+ )}
+
+ );
+};
+
+/**
+ * Property types.
+ * @property {Object} propTypes Property types.
+ * @static
+ */
+Caption.propTypes = {
+ title: PropTypes.string,
+ description: PropTypes.string,
+};
+
+export default Caption;
diff --git a/src/index.js b/src/index.js
index e96773b..40206b5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,12 +1,18 @@
import codeSVG from '@plone/volto/icons/code.svg';
import showcaseSVG from '@plone/volto/icons/showcase.svg';
-import CodeBlockViewBlock from './components/Blocks/Code/View';
-import CodeBlockEditBlock from './components/Blocks/Code/Edit';
+// Blocks - CodeBlock
+import CodeBlockView from './components/Blocks/Code/View';
+import CodeBlockEdit from './components/Blocks/Code/Edit';
+// Blocks - MermaidBlock
import MermaidBlockEdit from './components/Blocks/Mermaid/Edit';
import MermaidBlockView from './components/Blocks/Mermaid/View';
+// Blocks - GistBlock
+import GistBlockEdit from './components/Blocks/Gist/Edit';
+import GistBlockView from './components/Blocks/Gist/View';
+
import './theme/main.less';
import './theme/theme-dark.less';
import './theme/theme-light.less';
@@ -34,8 +40,8 @@ const applyConfig = (config) => {
title: 'Code Block',
icon: codeSVG,
group: 'text',
- view: CodeBlockViewBlock,
- edit: CodeBlockEditBlock,
+ view: CodeBlockView,
+ edit: CodeBlockEdit,
restricted: false,
mostUsed: false,
sidebarTab: 1,
@@ -57,6 +63,19 @@ const applyConfig = (config) => {
blockHasOwnFocusManagement: true,
};
+ config.blocks.blocksConfig.gistBlock = {
+ id: 'gistBlock',
+ title: 'Gist Block',
+ icon: codeSVG,
+ group: 'text',
+ view: GistBlockView,
+ edit: GistBlockEdit,
+ restricted: false,
+ mostUsed: false,
+ sidebarTab: 1,
+ blockHasOwnFocusManagement: false,
+ };
+
config.settings['codeBlock'] = {
languages: {
plain: { label: 'Plaintext', language: languages.plain },
@@ -76,11 +95,19 @@ const applyConfig = (config) => {
},
};
- // Check for @kitconcept/volto-blocks-grid
- const gridBlock = config.blocks.blocksConfig.__grid;
- if (gridBlock !== undefined) {
- config.blocks.blocksConfig.__grid.gridAllowedBlocks = [...gridBlock.gridAllowedBlocks, 'codeBlock', 'mermaidBlock'];
- }
+ // Add Blocks to gridBlock and accordionBlock
+ ['gridBlock', 'accordion'].forEach((blockId) => {
+ const block = config.blocks.blocksConfig[blockId];
+ if (block !== undefined) {
+ config.blocks.blocksConfig.gridBlock = {
+ ...config.blocks.blocksConfig.gridBlock,
+ blocksConfig: {
+ ...config.blocks.blocksConfig,
+ },
+ allowedBlocks: [...config.blocks.blocksConfig.gridBlock.allowedBlocks, 'codeBlock', 'mermaidBlock', 'gistBlock'],
+ };
+ }
+ });
return config;
};
diff --git a/src/theme/main.less b/src/theme/main.less
index e278d76..e099892 100644
--- a/src/theme/main.less
+++ b/src/theme/main.less
@@ -47,3 +47,49 @@
}
}
}
+
+.block.gist {
+ &.edit {
+ position: relative;
+
+ iframe {
+ width: 100%;
+ height: 100%;
+ }
+
+ .gist.editLayer {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.1);
+ }
+ }
+}
+
+div.codeBlockCaption {
+ margin: 0 5px;
+ color: #000;
+ font-size: 14px;
+ font-weight: 300;
+ line-height: 18px;
+ text-align: left;
+ white-space: initial;
+
+ .title {
+ margin-bottom: 10px;
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 16px;
+ }
+
+ .description {
+ p {
+ margin-bottom: 10px;
+ font-size: 14px;
+ font-weight: 300;
+ line-height: 16px;
+ }
+ }
+}