diff --git a/CHANGELOG.md b/CHANGELOG.md index f182b21..7b031a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,24 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [0.2.0](https://github.com/eea/volto-quote-block/compare/0.1.2...0.2.0) + +- refactor(quote): Rename sourceInfo field to extra [`51a9e32`](https://github.com/eea/volto-quote-block/commit/51a9e329e6d0a8b1caaadd42ccad1bd54e862210) +- Upgrade footnotes registry to work with volto-slate-footnotes 5.x [`3261f27`](https://github.com/eea/volto-quote-block/commit/3261f27d8749a022171ecdf8c854da832c40a2b9) +- Move reversed option to layout fieldset [`f0a94ac`](https://github.com/eea/volto-quote-block/commit/f0a94ac92820adc661030b095dc91fe048791e26) +- Fix schema [`f27fc86`](https://github.com/eea/volto-quote-block/commit/f27fc86025a004adc700f4f8ba36a080626a94af) +- Add volto-slate back [`a518905`](https://github.com/eea/volto-quote-block/commit/a518905f5a7a98213db0fd99396334dd2dbacef2) +- Use attached image widget [`c6acaa0`](https://github.com/eea/volto-quote-block/commit/c6acaa08ab9d985c963debff78e4d989b90556ac) +- Add footnotes support [`c63729c`](https://github.com/eea/volto-quote-block/commit/c63729cafce78dfe98d875d70214b3d8fd6c1f11) +- Prettier fix [`e4dd69a`](https://github.com/eea/volto-quote-block/commit/e4dd69a3051da854435093dc30f8048a650798a2) +- Remove usememo [`b5880a5`](https://github.com/eea/volto-quote-block/commit/b5880a5a1cf5c9889ec4c211c60f51986fd6255d) +- Update quote + add testimonial quote variation [`b248fa1`](https://github.com/eea/volto-quote-block/commit/b248fa1ed2adcd59050e907784bac126a74e145f) + #### [0.1.2](https://github.com/eea/volto-quote-block/compare/0.1.1...0.1.2) -- Disable Blockquote template for now and fix reversed pullquote [`c1a665a`](https://github.com/eea/volto-quote-block/commit/c1a665a32218baa39d12e4d987ad12b0249ab571) +> 17 May 2022 + +- Disable Blockquote template for now and fix reversed pullquote [`#2`](https://github.com/eea/volto-quote-block/pull/2) #### [0.1.1](https://github.com/eea/volto-quote-block/compare/0.1.0...0.1.1) diff --git a/package.json b/package.json index dc311a8..108b006 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-quote-block", - "version": "0.1.2", + "version": "0.2.0", "description": "@eeacms/volto-quote-block: Volto add-on", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", @@ -17,11 +17,13 @@ "url": "git@github.com:eea/volto-quote-block.git" }, "addons": [ + "@eeacms/volto-object-widget", "volto-slate" ], "dependencies": { "@plone/scripts": "*", - "volto-slate": "*" + "volto-slate": "*", + "@eeacms/volto-object-widget": "*" }, "devDependencies": { "@cypress/code-coverage": "^3.9.5", diff --git a/src/Blocks/Quote/Edit.jsx b/src/Blocks/Quote/Edit.jsx index 91eb511..9b64cda 100644 --- a/src/Blocks/Quote/Edit.jsx +++ b/src/Blocks/Quote/Edit.jsx @@ -1,6 +1,5 @@ import React from 'react'; -import { SidebarPortal } from '@plone/volto/components'; -import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; +import { BlockDataForm, SidebarPortal } from '@plone/volto/components'; import View from './View'; import getSchema from './schema'; @@ -16,7 +15,8 @@ const Edit = (props) => { - { diff --git a/src/Blocks/Quote/View.jsx b/src/Blocks/Quote/View.jsx index 1a18bb7..3777afd 100644 --- a/src/Blocks/Quote/View.jsx +++ b/src/Blocks/Quote/View.jsx @@ -1,26 +1,13 @@ import React from 'react'; -import config from '@plone/volto/registry'; +import { withBlockExtensions } from '@plone/volto/helpers'; import './styles.less'; const View = (props) => { - const { data, mode, block, onChangeBlock } = props; - const { template = 'default' } = data; - - const Quote = - config.blocks.blocksConfig.quote.templates[template]?.view || (() => ''); - - React.useEffect(() => { - if (mode === 'edit' && !template) { - onChangeBlock(block, { - ...data, - template: 'default', - }); - } - /* eslint-disable-next-line */ - }, []); + const { variation } = props; + const Quote = variation?.view; return ; }; -export default View; +export default withBlockExtensions(View); diff --git a/src/Blocks/Quote/index.js b/src/Blocks/Quote/index.js index cd9c8e8..c0bef8f 100644 --- a/src/Blocks/Quote/index.js +++ b/src/Blocks/Quote/index.js @@ -1,7 +1,7 @@ import quoteSVG from '@plone/volto/icons/quote.svg'; import QuoteEdit from './Edit'; import QuoteView from './View'; -import PullquoteView from './templates/Pullquote/Pullquote'; +import QuoteVariations from './variations'; export default (config) => { config.blocks.blocksConfig.quote = { @@ -11,16 +11,7 @@ export default (config) => { group: 'text', edit: QuoteEdit, view: QuoteView, - templates: { - default: { - title: 'Quote', - view: PullquoteView, - icons: { - openQuote: 'quote left', - closeQuote: 'quote right', - }, - }, - }, + variations: QuoteVariations, blockHasOwnFocusManagement: true, restricted: false, mostUsed: false, @@ -30,5 +21,12 @@ export default (config) => { view: [], }, }; + + // Footnotes + config.settings.blocksWithFootnotesSupport = { + ...(config.settings.blocksWithFootnotesSupport || {}), + quote: ['value', 'source', 'extra', 'title'], + }; + return config; }; diff --git a/src/Blocks/Quote/schema.js b/src/Blocks/Quote/schema.js index d373936..b81f4cb 100644 --- a/src/Blocks/Quote/schema.js +++ b/src/Blocks/Quote/schema.js @@ -2,67 +2,43 @@ import config from '@plone/volto/registry'; export default (props) => { const { position } = props.data; - const templatesConfig = config.blocks.blocksConfig.quote?.templates; - const templates = Object.keys(templatesConfig).map((template) => [ - template, - templatesConfig[template].title || template, - ]); - const schema = - templatesConfig[props.data?.template || 'default']?.schema || []; - const templateSchema = typeof schema === 'function' ? schema(props) : schema; - const defaultFieldset = - templateSchema.fieldsets?.filter( - (fieldset) => fieldset.id === 'default', - )[0] || {}; + const variations = config.blocks.blocksConfig.quote.variations; + return { - title: templateSchema.title || 'Quote', + title: 'Quote', fieldsets: [ { id: 'default', title: 'Default', fields: [ - 'template', + 'variation', ...(position && ['left', 'right'].includes(position) - ? ['quote'] + ? ['value'] : []), - 'reversed', - 'position', 'source', - 'metadata', - ...(defaultFieldset?.fields || []), + 'extra', ], }, - ...(templateSchema.fieldsets?.filter( - (fieldset) => fieldset.id !== 'default', - ) || []), ], properties: { - template: { - title: 'Template', - choices: templates, - }, - reversed: { - title: 'Reversed', - type: 'boolean', - }, - position: { - title: 'Alignment', - widget: 'align', + variation: { + title: 'Variation', + choices: variations.map((extension) => [extension.id, extension.title]), + defaultValue: 'default', }, - quote: { + value: { title: 'Quote', - widget: 'slate_richtext', + widget: 'slate', }, source: { title: 'Source', - widget: 'slate_richtext', + widget: 'slate', }, - metadata: { + extra: { title: 'Extra info', - widget: 'slate_richtext', + widget: 'slate', }, - ...(templateSchema.properties || {}), }, - required: [...(templateSchema.required || [])], + required: [], }; }; diff --git a/src/Blocks/Quote/styles.less b/src/Blocks/Quote/styles.less index edbaf13..5608425 100644 --- a/src/Blocks/Quote/styles.less +++ b/src/Blocks/Quote/styles.less @@ -1,7 +1,7 @@ -.eea.blockquote .quote > *:not(.meta) { - margin-bottom: 0; +.quote { + width: 100%; } -.eea.pullquote .quotes { - flex-flow: column; +div.quote { + margin-bottom: 1em; } diff --git a/src/Blocks/Quote/templates/Blockquote/Blockquote.jsx b/src/Blocks/Quote/templates/Blockquote/Blockquote.jsx deleted file mode 100644 index 650cb3c..0000000 --- a/src/Blocks/Quote/templates/Blockquote/Blockquote.jsx +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import cx from 'classnames'; -import { Message } from 'semantic-ui-react'; -import config from '@plone/volto/registry'; -import SlateEditor from 'volto-slate/editor/SlateEditor'; -import { handleKey } from 'volto-slate/blocks/Text/keyboard'; -import { saveSlateBlockSelection } from 'volto-slate/actions'; -import { - createSlateParagraph, - isFloated, - serializeText, - textNotEmpty, -} from '@eeacms/volto-quote-block/helpers'; - -import '@eeacms/volto-quote-block/less/blockquote.less'; - -const BlockquoteWrapper = (props) => { - const { children, index, block, mode, handleKeyDown } = props; - return mode === 'edit' ? ( -
{ - handleKeyDown(e, index, block, props.blockNode.current); - }} - style={{ outline: 'none' }} - // The tabIndex is required for the keyboard navigation - /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ - tabIndex={0} - > - {children} -
- ) : ( - children - ); -}; - -const Blockquote = (props) => { - const { - data, - mode, - index, - block, - selected, - properties, - onAddBlock, - onChangeBlock, - onFocusNextBlock, - onFocusPreviousBlock, - onSelectBlock, - } = props; - const { slate } = config.settings; - const { quote, source, metadata, position = null, reversed = false } = data; - const floated = isFloated(position); - const withInfo = textNotEmpty(source || metadata); - - const withBlockProperties = React.useCallback( - (editor) => { - editor.getBlockProps = () => props; - return editor; - }, - [props], - ); - - const handleFocus = React.useCallback(() => { - if (!selected) { - onSelectBlock(block); - } - }, [onSelectBlock, selected, block]); - - const handleKeyDown = React.useCallback( - ( - e, - index, - block, - node, - { - disableEnter = false, - disableArrowUp = false, - disableArrowDown = false, - } = {}, - ) => { - if (mode === 'edit' && !floated) return; - const isMultipleSelection = e.shiftKey; - if (e.key === 'ArrowUp' && !disableArrowUp) { - onFocusPreviousBlock(block, node, isMultipleSelection); - e.preventDefault(); - } - if (e.key === 'ArrowDown' && !disableArrowDown) { - onFocusNextBlock(block, node, isMultipleSelection); - e.preventDefault(); - } - if ((e.key === 'Return' || e.key === 'Enter') && !disableEnter) { - onAddBlock(config.settings.defaultBlockType, index + 1); - e.preventDefault(); - } - }, - [onAddBlock, onFocusPreviousBlock, onFocusNextBlock, mode, floated], - ); - - return ( - - {mode === 'edit' && floated && ( - - Click here to edit blockquote. - - )} -
-

- {mode === 'edit' && !floated ? ( - { - onChangeBlock(block, { - ...data, - quote, - }); - }} - block={block} - onFocus={handleFocus} - onKeyDown={handleKey} - selected={selected} - placeholder="Add quote" - slateSettings={slate} - /> - ) : ( - serializeText(quote) - )} -

- {withInfo && ( -
- {source &&

{serializeText(source)}

} - {metadata &&

{serializeText(metadata)}

} -
- )} -
-
- ); -}; - -export default connect( - () => { - return {}; - }, - { - saveSlateBlockSelection, - }, -)(Blockquote); diff --git a/src/Blocks/Quote/templates/Pullquote/Pullquote.jsx b/src/Blocks/Quote/variations/DefaultQuote.jsx similarity index 55% rename from src/Blocks/Quote/templates/Pullquote/Pullquote.jsx rename to src/Blocks/Quote/variations/DefaultQuote.jsx index 14b12b3..2e446d5 100644 --- a/src/Blocks/Quote/templates/Pullquote/Pullquote.jsx +++ b/src/Blocks/Quote/variations/DefaultQuote.jsx @@ -1,21 +1,16 @@ import React from 'react'; -import { connect } from 'react-redux'; import cx from 'classnames'; import { Icon, Message } from 'semantic-ui-react'; import config from '@plone/volto/registry'; import SlateEditor from 'volto-slate/editor/SlateEditor'; import { handleKey } from 'volto-slate/blocks/Text/keyboard'; -import { saveSlateBlockSelection } from 'volto-slate/actions'; import { createSlateParagraph, isFloated, serializeText, - textNotEmpty, } from '@eeacms/volto-quote-block/helpers'; -import '@eeacms/volto-quote-block/less/pullquote.less'; - -const PullquoteWrapper = (props) => { +const QuoteWrapper = (props) => { const { children, index, block, mode, handleKeyDown } = props; return mode === 'edit' ? (
{ ); }; -const Pullquote = (props) => { +const Quote = (props) => { const { slate } = config.settings; - const { icons } = config.blocks.blocksConfig.quote.templates.default || {}; + const { icons } = {}; const { data, mode, @@ -51,9 +46,8 @@ const Pullquote = (props) => { onFocusPreviousBlock, onSelectBlock, } = props; - const { quote, source, metadata, position = null, reversed = false } = data; + const { value, source, extra, position = null, reversed = false } = data; const floated = isFloated(position); - const withInfo = textNotEmpty(source || metadata); const withBlockProperties = React.useCallback( (editor) => { @@ -99,75 +93,85 @@ const Pullquote = (props) => { ); return ( - + {mode === 'edit' && floated && ( Click here to edit quote. )}
- {mode === 'edit' && !floated ? ( - - { - onChangeBlock(block, { - ...data, - quote, - }); - }} - block={block} - onFocus={handleFocus} - onKeyDown={handleKey} - selected={selected} - placeholder="Add quote" - slateSettings={slate} - /> - - ) : ( - - {serializeText(quote)} - - )} - {withInfo && ( -
- {source &&

{serializeText(source)}

} - {metadata &&

{serializeText(metadata)}

} -
- )} +
+ {reversed && source && ( + {serializeText(source)} + )} + {reversed && extra && ( + {serializeText(extra)} + )} + {mode === 'edit' && !floated ? ( + + { + onChangeBlock(block, { + ...data, + value, + }); + }} + block={block} + onFocus={handleFocus} + onKeyDown={handleKey} + selected={selected} + placeholder="Add quote" + slateSettings={slate} + /> + + ) : ( + {serializeText(value)} + )} + {!reversed && source && ( + {serializeText(source)} + )} + {!reversed && extra && ( + {serializeText(extra)} + )} +
-
+ ); }; -Pullquote.Quote = ({ children, icons, as: As, ...rest }) => ( +Quote.Quote = ({ children, as: As, ...rest }) => (
- + {As ? ( {children} ) : ( -

{children}

+
{children}
)} - + +
+); + +Quote.Source = ({ children, ...rest }) => ( +
+ {children} +
+); + +Quote.SourceInfo = ({ children, ...rest }) => ( +
+ {children}
); -export default connect( - () => { - return {}; - }, - { - saveSlateBlockSelection, - }, -)(Pullquote); +export default Quote; diff --git a/src/Blocks/Quote/variations/TestimonialQuote.jsx b/src/Blocks/Quote/variations/TestimonialQuote.jsx new file mode 100644 index 0000000..a3863d3 --- /dev/null +++ b/src/Blocks/Quote/variations/TestimonialQuote.jsx @@ -0,0 +1,191 @@ +import React from 'react'; +import { Grid, Card, Image } from 'semantic-ui-react'; +import config from '@plone/volto/registry'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers'; +import SlateEditor from 'volto-slate/editor/SlateEditor'; +import { handleKey } from 'volto-slate/blocks/Text/keyboard'; +import { + createSlateParagraph, + serializeText, +} from '@eeacms/volto-quote-block/helpers'; +import Quote from './DefaultQuote'; + +import DefaultImageSVG from '@plone/volto/components/manage/Blocks/Listing/default-image.svg'; + +function Divider({ ...rest }) { + return
; +} + +const TestimonialWrapper = (props) => { + const { children, index, block, mode, handleKeyDown } = props; + return mode === 'edit' ? ( +
{ + handleKeyDown(e, index, block, props.blockNode.current); + }} + style={{ outline: 'none' }} + // The tabIndex is required for the keyboard navigation + /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ + tabIndex={0} + > + {children} +
+ ) : ( + children + ); +}; + +const Testimonial = (props) => { + const { slate } = config.settings; + const { + data, + mode, + index, + block, + selected, + properties, + onAddBlock, + onChangeBlock, + onFocusNextBlock, + onFocusPreviousBlock, + onSelectBlock, + } = props; + const { value, source, extra, image, title } = data; + + const withBlockProperties = React.useCallback( + (editor) => { + editor.getBlockProps = () => props; + return editor; + }, + [props], + ); + + const handleFocus = React.useCallback(() => { + if (!selected) { + onSelectBlock(block); + } + }, [onSelectBlock, selected, block]); + + const handleKeyDown = React.useCallback( + ( + e, + index, + block, + node, + { + disableEnter = false, + disableArrowUp = false, + disableArrowDown = false, + } = {}, + ) => { + const isMultipleSelection = e.shiftKey; + if (e.key === 'ArrowUp' && !disableArrowUp) { + onFocusPreviousBlock(block, node, isMultipleSelection); + e.preventDefault(); + } + if (e.key === 'ArrowDown' && !disableArrowDown) { + onFocusNextBlock(block, node, isMultipleSelection); + e.preventDefault(); + } + if ((e.key === 'Return' || e.key === 'Enter') && !disableEnter) { + onAddBlock(config.settings.defaultBlockType, index + 1); + } + }, + [onAddBlock, onFocusPreviousBlock, onFocusNextBlock], + ); + + return ( + +
+ + + + + {title && ( + {serializeText(title)} + )} + {mode === 'edit' ? ( + + { + onChangeBlock(block, { + ...data, + value, + }); + }} + block={block} + onFocus={handleFocus} + onKeyDown={handleKey} + selected={selected} + placeholder="Add quote" + slateSettings={slate} + /> + + ) : ( + {serializeText(value)} + )} + + + +
+
+ ); +}; + +Testimonial.Avatar = ({ children, ...rest }) => { + const { title, description } = rest; + return ( + +
+ + card image + {title || description ? ( + + {title && {serializeText(title)}} + {description && ( + + {serializeText(description)} + + )} + + ) : ( + '' + )} + +
+
+ ); +}; + +Testimonial.Content = ({ children }) => { + return ( + +
{children}
+
+ ); +}; + +Testimonial.Title = ({ children }) =>

{children}

; +Testimonial.Quote = ({ children }) => ( +
+
+ {children} +
+
+); + +export default Testimonial; diff --git a/src/Blocks/Quote/variations/index.js b/src/Blocks/Quote/variations/index.js new file mode 100644 index 0000000..15bfc4d --- /dev/null +++ b/src/Blocks/Quote/variations/index.js @@ -0,0 +1,65 @@ +import DefaultQuote from './DefaultQuote'; +import TestimonialQuote from './TestimonialQuote'; + +export default [ + { + id: 'default', + title: 'Quote (default)', + view: DefaultQuote, + isDefault: true, + schemaEnhancer: (props) => { + const { schema } = props; + return { + ...schema, + fieldsets: [ + ...schema.fieldsets, + { id: 'layout', title: 'Layout', fields: ['position', 'reversed'] }, + ], + properties: { + ...schema.properties, + position: { + title: 'Alignment', + widget: 'align', + }, + reversed: { + title: 'Reversed', + type: 'boolean', + }, + }, + }; + }, + }, + { + id: 'testimonial', + title: 'Testimonial quote', + view: TestimonialQuote, + isDefault: true, + schemaEnhancer: (props) => { + const { schema } = props; + return { + ...schema, + fieldsets: [ + ...schema.fieldsets, + { + id: 'testimonial', + title: 'Testimonial', + fields: ['title', 'image'], + }, + ], + properties: { + ...schema.properties, + title: { + title: 'Title', + widget: 'slate', + }, + image: { + title: 'Image', + widget: 'attachedimage', + mode: 'image', + return: 'single', + }, + }, + }; + }, + }, +]; diff --git a/src/SlatePlugins/Quote/Quote.jsx b/src/SlatePlugins/Quote/Quote.jsx deleted file mode 100644 index 1033cc7..0000000 --- a/src/SlatePlugins/Quote/Quote.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import templates from './templates'; - -function Quote(props) { - const data = props.element.data || {}; - const QuoteElement = templates[data.template || 'default'].view; - - return ; -} - -export default Quote; diff --git a/src/SlatePlugins/Quote/extensions.js b/src/SlatePlugins/Quote/extensions.js deleted file mode 100644 index 9b80c5b..0000000 --- a/src/SlatePlugins/Quote/extensions.js +++ /dev/null @@ -1,45 +0,0 @@ -import { nanoid } from 'volto-slate/utils'; -import { Transforms } from 'slate'; - -export const withBlockquote = (editor) => { - const { normalizeNode, isInline } = editor; - - editor.isInline = (element) => { - return element.type === 'blockquote' ? true : isInline(element); - }; - - editor.normalizeNode = (entry) => { - const [node, path] = entry; - - if (node.type === 'blockquote' && !node.data?.uid) { - Transforms.setNodes( - editor, - { - data: { - uid: nanoid(5), - }, - }, - { - at: path, - }, - ); - } - return normalizeNode(entry); - }; - - return editor; -}; - -// will replace existing uid with a new one -// this will be usefull when copy/pase items have the same uid -export const withBeforeInsertFragment = (editor) => { - const { beforeInsertFragment } = editor; - editor.beforeInsertFragment = (parsed) => { - if (parsed?.[0]?.children?.[0]?.data?.uid) { - parsed[0].children[0].data.uid = nanoid(5); - } - return beforeInsertFragment ? beforeInsertFragment(parsed) : parsed; - }; - - return editor; -}; diff --git a/src/SlatePlugins/Quote/index.js b/src/SlatePlugins/Quote/index.js deleted file mode 100644 index 6f32613..0000000 --- a/src/SlatePlugins/Quote/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import { defineMessages } from 'react-intl'; -import { makeInlineElementPlugin } from 'volto-slate/components/ElementEditor'; -import Quote from './Quote'; -import quoteSchema from './schema'; -import { withBlockquote, withBeforeInsertFragment } from './extensions'; - -import quoteIcon from '@plone/volto/icons/quote.svg'; - -const messages = defineMessages({ - edit: { - id: 'Edit quote', - defaultMessage: 'Edit quote', - }, - delete: { - id: 'Remove quote', - defaultMessage: 'Remove quote', - }, -}); - -export default (config) => { - const opts = { - title: 'Quote', - pluginId: 'blockquote', - elementType: 'blockquote', - element: Quote, - isInlineElement: true, - editSchema: quoteSchema, - extensions: [withBlockquote, withBeforeInsertFragment], - hasValue: (formData) => !!formData, - toolbarButtonIcon: quoteIcon, - messages, - }; - - const [installQuote] = makeInlineElementPlugin(opts); - config = installQuote(config); - - config.settings.slateQuote = { - icons: { - openQuote: 'quote left', - closeQuote: 'quote right', - }, - }; - - return config; -}; diff --git a/src/SlatePlugins/Quote/schema.js b/src/SlatePlugins/Quote/schema.js deleted file mode 100644 index d938f90..0000000 --- a/src/SlatePlugins/Quote/schema.js +++ /dev/null @@ -1,34 +0,0 @@ -export default { - title: 'Quote', - fieldsets: [ - { - id: 'default', - title: 'Properties', - fields: ['reversed', 'position', 'source', 'metadata'], - }, - ], - properties: { - // template: { - // title: 'Template', - // choices: [['default', 'Default']], - // default: 'default', - // }, - reversed: { - title: 'Reversed', - type: 'boolean', - }, - position: { - title: 'Alignment', - widget: 'align', - }, - source: { - title: 'Source', - widget: 'slate_richtext', - }, - metadata: { - title: 'Extra info', - widget: 'slate_richtext', - }, - }, - required: [], -}; diff --git a/src/SlatePlugins/Quote/templates/default/View.jsx b/src/SlatePlugins/Quote/templates/default/View.jsx deleted file mode 100644 index 29434df..0000000 --- a/src/SlatePlugins/Quote/templates/default/View.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import cx from 'classnames'; -import { Icon } from 'semantic-ui-react'; -import config from '@plone/volto/registry'; -import { serializeText } from '@eeacms/volto-quote-block/helpers'; - -import '@eeacms/volto-quote-block/less/pullquote.less'; - -const Pullquote = ({ children, element }) => { - const { source, metadata, position = null, reversed = false } = - element?.data || {}; - - return ( -
- {children} - {(source || metadata) && ( -
- {source &&

{serializeText(source)}

} - {metadata &&

{serializeText(metadata)}

} -
- )} -
- ); -}; - -Pullquote.Quote = ({ children, as: As, ...rest }) => ( -
- - {As ? ( - - {children} - - ) : ( -

{children}

- )} - -
-); - -export default Pullquote; diff --git a/src/SlatePlugins/Quote/templates/index.js b/src/SlatePlugins/Quote/templates/index.js deleted file mode 100644 index 73f81f1..0000000 --- a/src/SlatePlugins/Quote/templates/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultQuote from './default/View'; - -export default { - default: { - view: DefaultQuote, - }, -}; diff --git a/src/SlatePlugins/index.js b/src/SlatePlugins/index.js deleted file mode 100644 index 7c259ea..0000000 --- a/src/SlatePlugins/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import installQuotePlugin from './Quote'; - -export default (config) => { - return [installQuotePlugin].reduce((acc, apply) => apply(acc), config); -}; diff --git a/src/helpers.js b/src/helpers.js index c29d4fe..5b5de1c 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,9 +1,6 @@ import { isArray } from 'lodash'; import config from '@plone/volto/registry'; -import { - serializeNodes, - serializeNodesToText, -} from 'volto-slate/editor/render'; +import { serializeNodes } from 'volto-slate/editor/render'; export const createSlateParagraph = (text) => { return isArray(text) ? text : config.settings.slate.defaultValue(); @@ -16,10 +13,3 @@ export const serializeText = (text) => { export const isFloated = (position) => { return position && ['left', 'right'].includes(position); }; - -export const textNotEmpty = (text) => { - if (text && isArray(text) && serializeNodesToText(text).length > 0) - return true; - if (text && typeof text === 'string' && text.length > 0) return true; - return false; -}; diff --git a/src/less/blockquote.less b/src/less/blockquote.less deleted file mode 100644 index e98b761..0000000 --- a/src/less/blockquote.less +++ /dev/null @@ -1,132 +0,0 @@ -@import './globals.less'; - -@addon: 'volto-addons'; -@addontype: 'quoteBlock'; -@addonelement: 'blockquote'; - -.loadAddonVariables(); - -/******************************* - Blockquote -*******************************/ - -#page-edit { - .eea.blockquote { - .author, - .meta { - margin-bottom: 0; - - > * { - margin-bottom: 0; - } - } - } -} - -.eea.blockquote { - display: flex; - flex-flow: column; - padding: @mobileQuotePadding; - border: @calloutBorder; - border-left: @mobileBlockquoteBorderLeft; - margin: 0; - border-radius: @calloutBorderRadius; - box-shadow: @calloutBoxShadow; - - .quote { - margin: @quoteMargin; - color: @quoteColor; - font-size: @mobileQuoteFontSize; - } - - .author { - margin: @authorMargin; - color: @authorTextColor; - font-size: @mobileAuthorFontSize; - font-weight: @authorFontWeight; - text-align: @authorTextAlign; - } - - .meta { - font-size: @mobileMetaFontSize; - font-weight: @metaFontWeight; - text-align: @metaTextAlign; - } - - &.with-info { - .quote { - margin: @quoteWithInfoMargin; - } - } - - &.reversed { - flex-flow: column-reverse; - - .quote { - margin: @quoteReversedMargin; - } - - .info.wrapper { - margin-bottom: 1.25rem; - } - - .author { - text-align: @authorReversedTextAlign; - } - - .meta { - text-align: @metaReversedTextAlign; - } - } -} - -@media only screen and (min-width: @tabletBreakpoint) { - .eea.blockquote { - padding: @tabletQuotePadding; - border-left: @tabletBlockquoteBorderLeft; - - .quote { - font-size: @tabletQuoteFontSize; - } - - .author { - font-size: @tabletAuthorFontSize; - } - - .meta { - font-size: @tabletMetaFontSize; - } - } - - .eea.blockquote.left { - width: @maxWidthOnFloat; - margin: @blockquoteFloatLeftMargin; - float: left; - } - - .eea.blockquote.right { - width: @maxWidthOnFloat; - margin: @blockquoteFloatRightMargin; - float: right; - } -} - -@media only screen and (min-width: @computerBreakpoint) { - .eea.blockquote { - padding: @computerQuotePadding; - - .quote { - font-size: @computerQuoteFontSize; - } - - .author { - font-size: @computerAuthorFontSize; - } - - .meta { - font-size: @computerMetaFontSize; - } - } -} - -.loadAddonVariables(); diff --git a/src/less/blockquote.variables b/src/less/blockquote.variables deleted file mode 100644 index ed438f6..0000000 --- a/src/less/blockquote.variables +++ /dev/null @@ -1,46 +0,0 @@ -/******************************* - Blockquote -*******************************/ -/* Body */ -@mobileBlockquoteBorderLeft : @5px solid @secondaryColor; -@tabletBlockquoteBorderLeft : @10px solid @secondaryColor; -@blockquoteFloatLeftMargin : @largeGap @largeGap @largeGap 0; -@blockquoteFloatRightMargin : @largeGap 0 @largeGap @largeGap; -@maxWidthOnFloat : 50%; - -/* Quote */ -@mobileQuotePadding : 0 0.5rem; -@tabletQuotePadding : 0 1rem; -@computerQuotePadding : 0 1.25rem; -@quoteMargin : 0; -@quoteWithInfoMargin : 0 0 1.25rem 0; -@quoteReversedMargin : 0; -@quoteColor : #2E3E4C; -@mobileQuoteFontSize : 1rem; -@tabletQuoteFontSize : @h6; -@computerQuoteFontSize : @h5; - -/* Author */ -@authorTextColor : #00928F; -@authorTextAlign : left; -@authorReversedTextAlign : left; -@mobileAuthorFontSize : 1rem; -@tabletAuthorFontSize : @h6; -@computerAuthorFontSize : @h5; -@authorFontWeight : @bold; -@authorMargin : 0; - -/* Meta */ -@metaTextAlign : left; -@metaReversedTextAlign : left; -@mobileMetaFontSize : 1rem; -@tabletMetaFontSize : @h6; -@computerMetaFontSize : @h5; -@metaFontWeight : 400; -@metaMargin : 0; - -/* Callout */ -@calloutBorder : none; -@calloutBoxShadow : none; -@calloutBorderRadius : 0; -@calloutPadding : 0; diff --git a/src/less/globals.less b/src/less/globals.less deleted file mode 100644 index 4271fc7..0000000 --- a/src/less/globals.less +++ /dev/null @@ -1,81 +0,0 @@ -@import (multiple, reference, optional) '../../theme.config'; - -/* Enables customization of addons */ -.loadAddonOverrides() { - @import (optional) - '@{siteFolder}/../addons/@{addon}/@{addontype}s/@{addonelement}.overrides'; -} - -/* Helper to load variables */ -.loadAddonVariables() { - @import (optional) '@{addonelement}.variables'; - @import (optional) - '@{siteFolder}/../addons/@{addon}/@{addontype}s/@{addonelement}.variables'; -} - -@type: extra; -@element: custom; - -/*------------------- - Exact Pixel Values ---------------------*/ -/* - These are used to specify exact pixel values in em - for things like borders that remain constantly - sized as emSize adjusts - - Since there are many more sizes than names for sizes, - these are named by their original pixel values. - -*/ - -@1px: unit((1 / @emSize), rem); -@2px: unit((2 / @emSize), rem); -@3px: unit((3 / @emSize), rem); -@4px: unit((4 / @emSize), rem); -@5px: unit((5 / @emSize), rem); -@6px: unit((6 / @emSize), rem); -@7px: unit((7 / @emSize), rem); -@8px: unit((8 / @emSize), rem); -@9px: unit((9 / @emSize), rem); -@10px: unit((10 / @emSize), rem); -@11px: unit((11 / @emSize), rem); -@12px: unit((12 / @emSize), rem); -@13px: unit((13 / @emSize), rem); -@14px: unit((14 / @emSize), rem); -@15px: unit((15 / @emSize), rem); -@16px: unit((16 / @emSize), rem); -@17px: unit((17 / @emSize), rem); -@18px: unit((18 / @emSize), rem); -@19px: unit((19 / @emSize), rem); -@20px: unit((20 / @emSize), rem); - -@h1: unit((48 / 16), rem); -@h2: unit((40 / 16), rem); -@h3: unit((36 / 16), rem); -@h4: unit((24 / 16), rem); -@h5: unit((20 / 16), rem); -@h6: unit((18 / 16), rem); - -@bold: 600; -@normal: normal; - -/*-------------------------- - Gaps / Paddings / Margins ----------------------------*/ - -@tinyGap: unit((12 / @emSize), rem); -@mediumGap: unit((16 / @emSize), rem); -@largeGap: unit((20 / @emSize), rem); -@bigGap: unit((24 / @emSize), rem); -@hugeGap: unit((28 / @emSize), rem); - -@squareTiny: @tinyGap @tinyGap; -@squareMedium: @mediumGap @mediumGap; -@squareLarge: @largeGap @largeGap; -@squareBig: @bigGap @bigGap; - -@rectangleTiny: @tinyGap @mediumGap; -@rectangleMedium: @mediumGap @largeGap; -@rectangleLarge: @largeGap @bigGap; -@rectangleBig: @bigGap @hugeGap; diff --git a/src/less/pullquote.less b/src/less/pullquote.less deleted file mode 100644 index 96042d2..0000000 --- a/src/less/pullquote.less +++ /dev/null @@ -1,117 +0,0 @@ -@import './globals.less'; - -@addon: 'volto-addons'; -@addontype: 'quoteBlock'; -@addonelement: 'pullquote'; - -.loadAddonVariables(); - -/******************************* - Pullquote -*******************************/ - -#page-edit { - .eea.pullquote { - .author, - .meta { - > * { - margin-bottom: 0; - } - } - } -} - -.eea.pullquote { - display: flex; - flex-flow: column; - padding: @pullquotePadding; - margin: @pullquoteMargin; - hyphens: @contentWordBreakHyphens; - word-break: @contentWordBreak; - - .quotes.wrapper { - display: flex; - - .quote:not(.icon) { - padding: @mobileQuotePadding; - margin: 0; - text-indent: @mobileQuoteIconSize; - } - - i.icon { - display: flex; - align-items: flex-end; - color: @quoteIconColor; - font-size: @mobileQuoteIconSize; - line-height: @mobileQuoteIconSize; - } - - i.icomn:first-child { - align-self: flex-start; - } - - i.icon:last-child { - align-self: flex-end; - } - } - - .author { - margin: @authorMargin; - color: @authorTextColor; - font-size: @authorFontSize; - font-weight: @authorFontWeight; - text-align: @authorTextAlign; - } - - .meta { - font-size: @metaFontSize; - font-weight: @metaFontWeight; - text-align: @metaTextAlign; - } - - i.icon.quote.left:before { - content: @openQuote; - } - - i.icon.quote.right:before { - content: @closeQuote; - } - - &.reversed { - flex-flow: column-reverse; - - .info.wrapper { - margin-bottom: 1rem; - } - } -} - -@media only screen and (min-width: @tabletBreakpoint) { - .eea.pullquote { - .quotes.wrapper { - .quote:not(.icon) { - padding: @tabletQuotePadding; - text-indent: @tabletQuoteIconSize; - } - - i.icon { - font-size: @tabletQuoteIconSize; - line-height: @tabletQuoteIconSize; - } - } - } - - .eea.pullquote.left { - width: @maxWidthOnFloat; - padding: @pullquoteFloatLeftPadding; - float: left; - } - - .eea.pullquote.right { - width: @maxWidthOnFloat; - padding: @pullquoteFloatRightPadding; - float: right; - } -} - -.loadAddonVariables(); diff --git a/src/less/pullquote.variables b/src/less/pullquote.variables deleted file mode 100644 index e69207d..0000000 --- a/src/less/pullquote.variables +++ /dev/null @@ -1,38 +0,0 @@ -/******************************* - Pullquote -*******************************/ - -/* Body */ -@pullquotePadding : @largeGap 0; -@pullquoteFloatLeftPadding : @largeGap @largeGap @largeGap 0; -@pullquoteFloatRightPadding : @largeGap 0 @largeGap @largeGap; -@pullquoteMargin : 0; -@maxWidthOnFloat : 50%; -@contentWordBreak : break-word; -@contentWordBreakHyphens : manual; - -/* Quote paragraph */ -@mobileQuotePadding : 0; -@tabletQuotePadding : 0.5rem 0 0.5rem; - -/* Author */ -@authorTextColor : #00928F; -@authorTextAlign : right; -@authorReversedTextAlign : left; -@authorFontWeight : @bold; -@authorFontSize : 1.25rem; -@authorMargin : 0; - -/* Metadata */ -@metaTextAlign : right; -@metaReversedTextAlign : left; -@metaFontWeight : @normal; -@metaFontSize : 1rem; - -/* Icon */ -@mobileQuoteIconSize : 2rem; -@tabletQuoteIconSize : 3rem; -@quoteIconColor : @secondaryColor; -@quoteDownIconFloat : right; -@openQuote : open-quote; -@closeQuote : close-quote; \ No newline at end of file