From 5018988eea0e7440a48fdc8321a4e47fce642eae Mon Sep 17 00:00:00 2001 From: Giulia Ghisini Date: Tue, 26 Sep 2023 10:12:16 +0200 Subject: [PATCH] chore: slate config --- src/config/Slate/Alignment/AlignMenu.jsx | 141 +++++++++++++++++++ src/config/Slate/Alignment/index.js | 23 ++++ src/config/Slate/Alignment/utils.js | 166 +++++++++++++++++++++++ src/config/Slate/config.js | 6 + src/config/Slate/dropdownStyle.scss | 9 ++ src/config/italiaConfig.js | 4 +- 6 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 src/config/Slate/Alignment/AlignMenu.jsx create mode 100644 src/config/Slate/Alignment/index.js create mode 100644 src/config/Slate/Alignment/utils.js create mode 100644 src/config/Slate/config.js create mode 100644 src/config/Slate/dropdownStyle.scss diff --git a/src/config/Slate/Alignment/AlignMenu.jsx b/src/config/Slate/Alignment/AlignMenu.jsx new file mode 100644 index 000000000..d7307ca4f --- /dev/null +++ b/src/config/Slate/Alignment/AlignMenu.jsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { useSlate } from 'slate-react'; +import { Dropdown } from 'semantic-ui-react'; +import { useIntl, defineMessages } from 'react-intl'; +import cx from 'classnames'; +import { omit } from 'lodash'; +import { isBlockStyleActive, toggleStyle } from './utils'; + +import { Icon } from '@plone/volto/components'; +import { ToolbarButton } from '@plone/volto-slate/editor/ui'; + +import alignCenterSVG from '@plone/volto/icons/align-center.svg'; +import alignLeftSVG from '@plone/volto/icons/align-left.svg'; +import alignRightSVG from '@plone/volto/icons/align-right.svg'; +import alignJustifySVG from '@plone/volto/icons/align-justify.svg'; + +import '../dropdownStyle.scss'; + +const ALIGN_OPTIONS = [ + { + cssClass: 'text-left', + text: 'Allinea a sinistra', + icon: alignLeftSVG, + }, + { + cssClass: 'text-center', + text: 'Allinea al centro', + icon: alignCenterSVG, + }, + { + cssClass: 'text-right', + text: 'Allinea a destra', + icon: alignRightSVG, + }, + { + cssClass: 'text-justify', + text: 'Allinea il testo giustificato', + icon: alignJustifySVG, + }, +]; + +const messages = defineMessages({ + align: { + id: 'Allineamento', + defaultMessage: 'Allineamento', + }, +}); + +const AlignMenuButton = ({ icon, active, ...props }) => ( + +); + +const MenuOpts = ({ editor, toSelect, option, type }) => { + const isActive = toSelect.includes(option); + + return ( + { + toggleStyle(editor, { + cssClass: selItem.value, + isBlock: selItem.isBlock, + oneOfType: 'align', + }); + }} + /> + ); +}; + +const AlignButton = (props) => { + const editor = useSlate(); + const intl = useIntl(); + + const blockOpts = ALIGN_OPTIONS.map((def) => { + return { + value: def.cssClass, + text: def.label, + icon: (props) => , + isBlock: true, + originalIcon: def.icon, + }; + }); + + // Calculating the initial selection. + const toSelect = []; + let selectedIcon = ALIGN_OPTIONS[0].icon; + + // block styles + for (const val of blockOpts) { + const ia = isBlockStyleActive(editor, val.value); + + if (ia) { + toSelect.push(val); + selectedIcon = val.originalIcon; + } + } + + const menuItemProps = { + toSelect, + editor, + }; + + const showMenu = blockOpts.length; + + return showMenu ? ( + 0} + /> + } + > + + {blockOpts.length && + blockOpts.map((option, index) => ( + + ))} + + + ) : ( + '' + ); +}; + +export default AlignButton; diff --git a/src/config/Slate/Alignment/index.js b/src/config/Slate/Alignment/index.js new file mode 100644 index 000000000..9606f2ee0 --- /dev/null +++ b/src/config/Slate/Alignment/index.js @@ -0,0 +1,23 @@ +import React from 'react'; +import AlignMenu from './AlignMenu'; +//import '@plone/volto-slate/editor/plugins/StyleMenu/style.less'; + +export const AlignElement = ({ attributes, children, element }) => { + console.log(attributes, element); + return

aaaa{children}

; +}; + +export default function install(config) { + const { slate } = config.settings; + + slate.buttons.align = (props) => ( + + ); + + slate.elements['align'] = AlignElement; + slate.toolbarButtons.push('align'); + slate.expandedToolbarButtons.push('align'); + console.log(slate); + + return config; +} diff --git a/src/config/Slate/Alignment/utils.js b/src/config/Slate/Alignment/utils.js new file mode 100644 index 000000000..ce42c5aab --- /dev/null +++ b/src/config/Slate/Alignment/utils.js @@ -0,0 +1,166 @@ +/* eslint no-console: ["error", { allow: ["warn", "error"] }] */ +import { Editor, Transforms } from 'slate'; +import { isBlockActive } from '@plone/volto-slate/utils'; +import config from '@plone/volto/registry'; + +/** + * Toggles a style (e.g. in the StyleMenu plugin). + * @param {Editor} editor + * @param {object} options + * @param {boolean} options.oneOfType Whether the given type is admitted once + */ +export const toggleStyle = (editor, { cssClass, isBlock, oneOfType }) => { + if (isBlock) { + toggleBlockStyle(editor, cssClass, oneOfType); + } else { + toggleInlineStyle(editor, cssClass); + } +}; + +export const toggleBlockStyle = (editor, style, oneOfType) => { + // We have 6 boolean variables which need to be accounted for. + // See https://docs.google.com/spreadsheets/d/1mVeMuqSTMABV2BhoHPrPAFjn7zUksbNgZ9AQK_dcd3U/edit?usp=sharing + const { slate } = config.settings; + + const isListItem = isBlockActive(editor, slate.listItemType); + const isActive = isBlockStyleActive(editor, style); + const wantsList = false; + + if (isListItem && !wantsList) { + toggleBlockStyleAsListItem(editor, style); + } else if (isListItem && wantsList && !isActive) { + // switchListType(editor, format); // this will deconstruct to Volto blocks + } else if (!isListItem && wantsList) { + // changeBlockToList(editor, format); + } else if (!isListItem && !wantsList) { + internalToggleBlockStyle(editor, style); + } else { + console.warn('toggleBlockStyle case not covered, please examine:', { + wantsList, + isActive, + isListItem, + }); + } +}; + +export const toggleInlineStyle = (editor, style) => { + // We have 6 boolean variables which need to be accounted for. + // See https://docs.google.com/spreadsheets/d/1mVeMuqSTMABV2BhoHPrPAFjn7zUksbNgZ9AQK_dcd3U/edit?usp=sharing + const { slate } = config.settings; + + const isListItem = isBlockActive(editor, slate.listItemType); + const isActive = isInlineStyleActive(editor, style); + const wantsList = false; + + if (isListItem && !wantsList) { + toggleInlineStyleAsListItem(editor, style); + } else if (isListItem && wantsList && !isActive) { + // switchListType(editor, format); // this will deconstruct to Volto blocks + } else if (!isListItem && wantsList) { + // changeBlockToList(editor, format); + } else if (!isListItem && !wantsList) { + internalToggleInlineStyle(editor, style); + } else { + console.warn('toggleInlineStyle case not covered, please examine:', { + wantsList, + isActive, + isListItem, + }); + } +}; + +export const isBlockStyleActive = (editor, style) => { + const keyName = `style-${style}`; + const sn = Array.from( + Editor.nodes(editor, { + match: (n) => { + const isStyle = typeof n.styleName === 'string' || n[keyName]; + return !Editor.isEditor(n) && isStyle; + }, + mode: 'all', + }), + ); + + for (const [n] of sn) { + if (typeof n.styleName === 'string') { + if (n.styleName.split(' ').filter((x) => x === style).length > 0) { + return true; + } + } else if ( + n[keyName] && + keyName.split('style-').filter((x) => x === style).length > 0 + ) + return true; + } + return false; +}; + +export const isInlineStyleActive = (editor, style) => { + const m = Editor.marks(editor); + const keyName = `style-${style}`; + if (m && m[keyName]) { + return true; + } + return false; +}; + +export const internalToggleBlockStyle = (editor, style) => { + toggleBlockStyleInSelection(editor, style); +}; + +export const internalToggleInlineStyle = (editor, style) => { + toggleInlineStyleInSelection(editor, style); +}; + +/* + * Applies a block format unto a list item. Will split the list and deconstruct the + * block + */ +export const toggleBlockStyleAsListItem = (editor, style) => { + toggleBlockStyleInSelection(editor, style); +}; + +/* + * Applies an inline style unto a list item. + */ +export const toggleInlineStyleAsListItem = (editor, style) => { + toggleInlineStyleInSelection(editor, style); +}; + +function toggleInlineStyleInSelection(editor, style) { + const m = Editor.marks(editor); + const keyName = 'style-' + style; + + if (m && m[keyName]) { + Editor.removeMark(editor, keyName); + } else { + Editor.addMark(editor, keyName, true); + } +} + +function toggleBlockStyleInSelection(editor, style) { + const sn = Array.from( + Editor.nodes(editor, { + mode: 'highest', + match: (n) => { + return !Editor.isEditor(n); + }, + }), + ); + + for (const [n, p] of sn) { + let cn = n.styleName; + if (typeof n.styleName !== 'string') { + cn = style; + } else if (n.styleName.split(' ').filter((x) => x === style).length > 0) { + cn = cn + .split(' ') + .filter((x) => x !== style) + .join(' '); + } else { + // the style is not set but other styles are set + cn = cn.split(' ').concat(style).join(' '); + } + Transforms.setNodes(editor, { styleName: cn }, { at: p }); + } +} diff --git a/src/config/Slate/config.js b/src/config/Slate/config.js new file mode 100644 index 000000000..b55fb2283 --- /dev/null +++ b/src/config/Slate/config.js @@ -0,0 +1,6 @@ +//config.settings.slate.contextToolbarButtons +import installAlignment from 'design-comuni-plone-theme/config/Slate/Alignment'; + +export default function applyItaliaSlateConfig(config) { + installAlignment(config); +} diff --git a/src/config/Slate/dropdownStyle.scss b/src/config/Slate/dropdownStyle.scss new file mode 100644 index 000000000..fb47383d4 --- /dev/null +++ b/src/config/Slate/dropdownStyle.scss @@ -0,0 +1,9 @@ +.cms-ui .slate-inline-toolbar .ui.dropdown .menu > .item { + &.active { + color: #007eb1; + background-color: lighten(#007eb1, 60); + } + > .icon { + margin-right: 0; + } +} diff --git a/src/config/italiaConfig.js b/src/config/italiaConfig.js index 4d67d298d..7f6612b77 100644 --- a/src/config/italiaConfig.js +++ b/src/config/italiaConfig.js @@ -58,6 +58,7 @@ import bandoSVG from 'design-comuni-plone-theme/icons/bando.svg'; import logSVG from 'design-comuni-plone-theme/icons/log.svg'; import applyRichTextConfig from 'design-comuni-plone-theme/config/RichTextEditor/config'; +import applyItaliaSlateConfig from 'design-comuni-plone-theme/config/Slate/config'; import gdprPrivacyPanelConfig from 'design-comuni-plone-theme/config/volto-gdpr-privacy-defaultPanelConfig.js'; @@ -70,7 +71,8 @@ const ReleaseLog = loadable(() => ); export default function applyConfig(voltoConfig) { - let config = applyRichTextConfig(voltoConfig); + let config = applyRichTextConfig(voltoConfig); //[ToDO]: da rimuovere in favore di slate? + applyItaliaSlateConfig(config); /****************************************************************************** * SETTINGS