forked from italia/design-comuni-plone-theme
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d4e4a71
commit 5018988
Showing
6 changed files
with
348 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }) => ( | ||
<ToolbarButton {...props} icon={icon} active={active} /> | ||
); | ||
|
||
const MenuOpts = ({ editor, toSelect, option, type }) => { | ||
const isActive = toSelect.includes(option); | ||
|
||
return ( | ||
<Dropdown.Item | ||
as="span" | ||
active={isActive} | ||
className={cx(`${type}-${option.value}`, { active: isActive })} | ||
{...omit(option, ['isBlock'])} | ||
data-isblock={option.isBlock} | ||
onClick={(event, selItem) => { | ||
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) => <Icon name={def.icon} size="24px" />, | ||
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 ? ( | ||
<Dropdown | ||
id="align-menu" | ||
pointing="top left" | ||
multiple | ||
value={toSelect} | ||
additionLabel={intl.formatMessage(messages.align)} | ||
trigger={ | ||
<AlignMenuButton | ||
title={intl.formatMessage(messages.align)} | ||
icon={selectedIcon} | ||
active={toSelect.length > 0} | ||
/> | ||
} | ||
> | ||
<Dropdown.Menu> | ||
{blockOpts.length && | ||
blockOpts.map((option, index) => ( | ||
<MenuOpts | ||
{...menuItemProps} | ||
type="block-align" | ||
option={option} | ||
key={index} | ||
/> | ||
))} | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
) : ( | ||
'' | ||
); | ||
}; | ||
|
||
export default AlignButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <p {...attributes} /*className="callout"*/>aaaa{children}</p>; | ||
}; | ||
|
||
export default function install(config) { | ||
const { slate } = config.settings; | ||
|
||
slate.buttons.align = (props) => ( | ||
<AlignMenu {...props} title="Allineamento" /> | ||
); | ||
|
||
slate.elements['align'] = AlignElement; | ||
slate.toolbarButtons.push('align'); | ||
slate.expandedToolbarButtons.push('align'); | ||
console.log(slate); | ||
|
||
return config; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters