Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

Commit

Permalink
Merge pull request #248 from eea/develop
Browse files Browse the repository at this point in the history
Use the new design for StyleMenu
  • Loading branch information
avoinea authored Sep 22, 2022
2 parents f17d2f5 + 0c9644f commit ebdaed1
Show file tree
Hide file tree
Showing 8 changed files with 1,754 additions and 2,206 deletions.
3,525 changes: 1,602 additions & 1,923 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "volto-slate",
"version": "6.3.0",
"version": "6.4.0",
"description": "Slate.js integration with Volto",
"main": "src/index.js",
"author": "European Environment Agency: IDM2 A-Team",
Expand Down
311 changes: 91 additions & 220 deletions src/editor/plugins/StyleMenu/StyleMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,267 +1,138 @@
import React, { useState } from 'react';
import React from 'react';
import { useSlate } from 'slate-react';
import loadable from '@loadable/component';
import { Dropdown } from 'semantic-ui-react';
import { useIntl, defineMessages } from 'react-intl';
import cx from 'classnames';
import { isBlockStyleActive, isInlineStyleActive, toggleStyle } from './utils';
import config from '@plone/volto/registry';

const Select = loadable(() => import('react-select'));
import { ToolbarButton } from 'volto-slate/editor/ui';
import paintSVG from '@plone/volto/icons/paint.svg';

const messages = defineMessages({
allStylesApplied: {
id: 'All Styles Applied',
defaultMessage: 'All Styles Applied',
},
noStyle: {
id: 'No Style',
defaultMessage: 'No Style',
},
fontStyle: {
id: 'Font Style',
defaultMessage: 'Font Style',
inlineStyle: {
id: 'Inline Style',
defaultMessage: 'Inline Style',
},
paragraphStyle: {
id: 'Paragraph Style',
defaultMessage: 'Paragraph Style',
},
additionalStyles: {
id: 'Additional Styles',
defaultMessage: 'Additional Styles',
},
});

// const brownColor = '#826A6A';
const StyleMenuButton = ({ icon, active, ...props }) => (
<ToolbarButton {...props} icon={icon} active={active} />
);

const selectStyles = {
valueContainer: (provided, state) => {
return {
...provided,
padding: '0px',
paddingLeft: '0px',
paddingTop: '0px',
paddingRight: '0px',
paddingDown: '0px',
fontSize: '1rem',
position: 'static',
};
},
input: (provided, state) => {
return {
...provided,
display: 'none',
};
},
dropdownIndicator: (provided, state) => {
return {
...provided,
padding: '0px',
paddingLeft: '0px',
paddingTop: '0px',
paddingRight: '0px',
paddingDown: '0px',
};
},
indicatorsContainer: (provided, state) => {
return {
...provided,
padding: '0px',
paddingLeft: '0px',
paddingTop: '0px',
paddingRight: '0px',
paddingDown: '0px',
};
},
clearIndicator: (provided, state) => {
return {
...provided,
padding: '0px',
paddingLeft: '0px',
paddingTop: '0px',
paddingRight: '0px',
paddingDown: '0px',
};
},
control: (provided, state) => {
return {
...provided,
minHeight: 'auto',
borderWidth: 'unset',
cursor: 'pointer',
marginTop: '0.25rem',
// borderColor: state.isFocused ? brownColor : '#f3f3f3',
// boxShadow: 'unset',
};
},
container: (provided, state) => {
return {
...provided,
marginLeft: '3px',
width: '15rem',
// backgroundColor: state.isFocused ? '#f3f3f3' : 'unset',
};
},
singleValue: (provided, state) => {
return {
paddingLeft: '3px',
fontSize: '1rem',
// color: brownColor,
};
},
option: (provided, state) => {
return {
...provided,
fontSize: '1rem',
cursor: 'pointer',
// color: state.isSelected ? 'white' : brownColor,
};
},
noOptionsMessage: (provided, state) => {
return {
...provided,
fontSize: '1rem',
};
},
group: (provided, state) => {
return {
...provided,
fontSize: '1rem',
};
},
const MenuOpts = ({ editor, toSelect, option }) => {
const isActive = toSelect.includes(option);
return (
<Dropdown.Item
as="span"
active={isActive}
className={cx({ active: isActive })}
{...option}
onClick={(event, selItem) => {
event.stopPropagation();
toggleStyle(editor, {
cssClass: selItem.value,
isBlock: selItem.isBlock,
});
}}
/>
);
};

const StylingsButton = (props) => {
const editor = useSlate();
const intl = useIntl();
const [open, setOpen] = useState(false);

// Converting the settings to a format that is required by react-select.
const rawOpts = [
// Converting the settings to a format that is required by dropdowns.
const inlineOpts = [
...config.settings.slate.styleMenu.inlineStyles.map((def) => {
return { value: def.cssClass, label: def.label, isBlock: false };
return {
value: def.cssClass,
text: def.label,
icon: def.icon,
isBlock: false,
};
}),
];
const blockOpts = [
...config.settings.slate.styleMenu.blockStyles.map((def) => {
return { value: def.cssClass, label: def.label, isBlock: true };
return {
value: def.cssClass,
text: def.label,
icon: def.icon,
isBlock: true,
};
}),
];

// TODO: i18n for the two strings used below
const opts = [
{
label: intl.formatMessage(messages.paragraphStyle),
options: rawOpts.filter((x) => x.isBlock),
},
{
label: intl.formatMessage(messages.fontStyle),
options: rawOpts.filter((x) => !x.isBlock),
},
];

// Calculating the initial selection.
const toSelect = [];
// block styles
for (const val of opts[0].options) {
for (const val of blockOpts) {
const ia = isBlockStyleActive(editor, val.value);
if (ia) {
toSelect.push(val);
}
}
// inline styles
for (const val of opts[1].options) {
for (const val of inlineOpts) {
const ia = isInlineStyleActive(editor, val.value);
if (ia) {
toSelect.push(val);
}
}

return rawOpts.length > 0 ? (
<Select
options={opts}
const menuItemProps = {
toSelect,
editor,
};
const showMenu = inlineOpts.length || blockOpts.length;
return showMenu ? (
<Dropdown
id="style-menu"
multiple
value={toSelect}
menuIsOpen={open}
onBlur={() => {
setOpen(false);
}}
isMulti={true}
styles={selectStyles}
placeholder={intl.formatMessage(messages.noStyle)}
hideSelectedOptions={false}
noOptionsMessage={({ inputValue }) =>
intl.formatMessage(messages.allStylesApplied)
disabled={config.settings.slate.styleMenu.disabled ?? false}
additionLabel={intl.formatMessage(messages.additionalStyles)}
trigger={
<StyleMenuButton
title={intl.formatMessage(messages.additionalStyles)}
icon={paintSVG}
active={toSelect.length > 0}
/>
}
components={{
// Shows the most relevant part of the selection as a simple string of text.
// TODO: show all the styles selected with commas between them and
// ellipsis just at the end of the MultiValue right side limit
MultiValue: (props) => {
const val = props.getValue();

if (props.index === 0) {
const cond = val.length > 1;
const lbl = val[props.index].label + '...';
const lbl2 = val[props.index].label;
return <>{cond ? lbl : lbl2}</>;
}
>
<Dropdown.Menu>
{inlineOpts.length && (
<>
<Dropdown.Header
content={intl.formatMessage(messages.inlineStyle)}
/>
{inlineOpts.map((option) => (
<MenuOpts {...menuItemProps} option={option} />
))}
</>
)}

return '';
},
Control: (props) => {
const {
children,
cx,
getStyles,
className,
isDisabled,
isFocused,
innerRef,
innerProps,
menuIsOpen,
} = props;
return (
<div
ref={innerRef}
role="presentation"
style={getStyles('control', props)}
className={cx(
{
control: true,
'control--is-disabled': isDisabled,
'control--is-focused': isFocused,
'control--menu-is-open': menuIsOpen,
},
className,
)}
{...innerProps}
// The only difference from the initial React-Select's Control
// component:
onClick={() => {
setOpen(!open);
}}
>
{children}
</div>
);
},
}}
theme={(theme) => {
return {
...theme,
colors: {
...theme.colors,
primary: '#826A6AFF', // 100% opaque @brown
primary75: '#826A6Abf', // 75% opaque @brown
primary50: '#826A6A7f', // 50% opaque @brown
primary25: '#826A6A40', // 25% opaque @brown
},
};
}}
onChange={(selItem, meta) => {
// console.log('meta', meta);
for (const item of rawOpts) {
const isRequested = selItem.includes(item);
toggleStyle(editor, {
cssClass: item.value,
isBlock: item.isBlock,
isRequested,
});
}
}}
></Select>
{blockOpts.length && (
<>
<Dropdown.Header
content={intl.formatMessage(messages.paragraphStyle)}
/>
{blockOpts.map((option) => (
<MenuOpts {...menuItemProps} option={option} />
))}
</>
)}
</Dropdown.Menu>
</Dropdown>
) : (
''
);
Expand Down
Loading

0 comments on commit ebdaed1

Please sign in to comment.