diff --git a/Resources/Private/Translations/en/Main.xlf b/Resources/Private/Translations/en/Main.xlf index 8f3a49c5d5..356fb86c4a 100644 --- a/Resources/Private/Translations/en/Main.xlf +++ b/Resources/Private/Translations/en/Main.xlf @@ -380,6 +380,12 @@ Copy node type to clipboard + + The current document does not exist in the dimension + + + This combination of dimensions is not allowed + diff --git a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelector.js b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelector.js index ded65d67da..bbdc813df2 100644 --- a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelector.js +++ b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelector.js @@ -49,7 +49,9 @@ export default class DimensionSelector extends PureComponent { label: presetConfiguration?.label, value: presetName, disallowed: presetConfiguration?.disallowed, - group: presetConfiguration?.group + covered: presetConfiguration?.covered, + group: presetConfiguration?.group, + url: presetConfiguration?.url }; } ); diff --git a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelectorOption.js b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelectorOption.js index e580931b2f..6a250dd61a 100644 --- a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelectorOption.js +++ b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelectorOption.js @@ -3,24 +3,57 @@ import PropTypes from 'prop-types'; import style from './style.module.css'; // eslint-disable-next-line camelcase import SelectBox_Option_SingleLine from '@neos-project/react-ui-components/src/SelectBox_Option_SingleLine/index'; +import mergeClassNames from 'classnames'; +import {neos} from '@neos-project/neos-ui-decorators'; + +@neos(globalRegistry => ({ + i18nRegistry: globalRegistry.get('i18n') +})) export default class DimensionSelectorOption extends PureComponent { static propTypes = { option: PropTypes.shape({ label: PropTypes.string.isRequired, - disallowed: PropTypes.bool - }) + disallowed: PropTypes.bool, + covered: PropTypes.bool, + url: PropTypes.string + }), + i18nRegistry: PropTypes.object.isRequired }; render() { - const {option} = this.props; + const {option, i18nRegistry} = this.props; + const className = mergeClassNames({ + [style.disallowed]: option.disallowed, + [style.notCovered]: !option.covered + }); + + if (!option.disallowed && option.covered && option.url) { + const linkOptions = { + href: option.url, + target: '_blank', + rel: 'noopener noreferrer', + onClick: (event) => event.preventDefault() + } + return ( + + // eslint-disable-next-line camelcase + + ); + } + option.title = option.disallowed ? + i18nRegistry.translate('Neos.Neos.Ui:Main:dimensions.combinationNotAllowed') : + i18nRegistry.translate('Neos.Neos.Ui:Main:dimensions.doesNotExistsInDimension') return ( // eslint-disable-next-line camelcase ); } diff --git a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/index.js b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/index.js index 9b97ddd3db..60c10d1ef6 100644 --- a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/index.js +++ b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/index.js @@ -31,7 +31,9 @@ SelectedPreset.propTypes = { @connect($transform({ contentDimensions: selectors.CR.ContentDimensions.byName, allowedPresets: selectors.CR.ContentDimensions.allowedPresets, - activePresets: selectors.CR.ContentDimensions.activePresets + activePresets: selectors.CR.ContentDimensions.activePresets, + getNodeByContextPath: selectors.CR.Nodes.nodeByContextPath, + documentNode: selectors.CR.Nodes.documentNodeSelector }), { selectPreset: actions.CR.ContentDimensions.selectPreset, setAllowed: actions.CR.ContentDimensions.setAllowed @@ -45,6 +47,8 @@ export default class DimensionSwitcher extends PureComponent { activePresets: PropTypes.object.isRequired, allowedPresets: PropTypes.object.isRequired, selectPreset: PropTypes.func.isRequired, + getNodeByContextPath: PropTypes.func.isRequired, + documentNode: PropTypes.object.isRequired, setAllowed: PropTypes.func.isRequired, i18nRegistry: PropTypes.object.isRequired @@ -62,6 +66,16 @@ export default class DimensionSwitcher extends PureComponent { loadingPresets: {} }; + componentDidMount() { + const activePresets = mapValues( + this.props.activePresets, + dimensionPreset => dimensionPreset.name + ); + this.setState({ + transientPresets: activePresets + }); + } + getDimensionIcon = (dimensionName, contentDimensionsObject) => { const dimensionConfiguration = contentDimensionsObject[dimensionName]; return dimensionConfiguration?.icon || null; @@ -153,11 +167,21 @@ export default class DimensionSwitcher extends PureComponent { this.setState({isOpen: false}); } + createDirectDimensionsLink = (dimensionName, presetName) => { + const {documentNode} = this.props; + + const nodeContextPath = documentNode.properties._path + ';' + dimensionName + '=' + presetName + const uri = new URL(window.location.href); + uri.searchParams.set('node', nodeContextPath); + return uri.toString(); + } + renderSingleDimensionSelector = (dimensionName, contentDimensionsObject) => { const dimensionConfiguration = contentDimensionsObject[dimensionName]; const icon = this.getDimensionIcon(dimensionName, contentDimensionsObject); // First look for active preset in transient state, else take it from activePresets prop const activePreset = this.getEffectivePresets(this.state.transientPresets)[dimensionName]; + return ( { + const [key, value] = entry; + if (value[dimensionKey] !== this.state.transientPresets[dimensionKey]) { + delete variants[key] + } + }); + } + const dimensions = [] + Object.values(variants).forEach(entry => { + dimensions.push(entry[dimensionName]); + }); + + return dimensions; + } + presetsForDimension(dimensionName) { const {contentDimensions, allowedPresets, i18nRegistry} = this.props; const dimensionConfiguration = $get(dimensionName, contentDimensions); - + const documentDimensions = this.getDocumentDimensions(dimensionName); return mapValues(dimensionConfiguration.presets, (presetConfiguration, presetName) => { return Object.assign({}, presetConfiguration, { label: i18nRegistry.translate(presetConfiguration.label), - disallowed: !(allowedPresets[dimensionName] && allowedPresets[dimensionName].includes(presetName)) + disallowed: !(allowedPresets[dimensionName] && allowedPresets[dimensionName].includes(presetName)), + covered: documentDimensions.some(dimension => presetConfiguration.values.includes(dimension)), + url: (Object.keys(contentDimensions).length === 1) ? this.createDirectDimensionsLink(dimensionName, presetName) : null }); }); } diff --git a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/style.module.css b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/style.module.css index 81fd78993d..030bf2173e 100644 --- a/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/style.module.css +++ b/packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/style.module.css @@ -60,8 +60,31 @@ } } -.dimmed { - filter: opacity(50%); +.notCovered { + position: relative; + background-image: repeating-linear-gradient(-45deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 12px, #323232 0, #323232 23px); +} +.notCovered:after { + content: ''; + position: absolute; + height: 100%; + width: 3px; + top: 0px; + left: 0px; + background-color: var(--colors-Warn); +} +.disallowed { + position: relative; + background-color: #323232; +} +.disallowed:after { + content: ''; + position: absolute; + height: 100%; + width: 3px; + top: 0px; + left: 0px; + background-color: var(--colors-Error); } .selectPreset + .selectPreset { diff --git a/packages/react-ui-components/src/ListPreviewElement/style.module.css b/packages/react-ui-components/src/ListPreviewElement/style.module.css index d133fb90c1..c28b9cd066 100644 --- a/packages/react-ui-components/src/ListPreviewElement/style.module.css +++ b/packages/react-ui-components/src/ListPreviewElement/style.module.css @@ -17,6 +17,7 @@ } .listPreviewElement--isHighlighted { background-color: var(--colors-PrimaryBlue) !important; + background-image: none !important; } .listPreviewElement--isHighlighted > span { diff --git a/packages/react-ui-components/src/SelectBox_Option_SingleLine/selectBox_Option_SingleLine.js b/packages/react-ui-components/src/SelectBox_Option_SingleLine/selectBox_Option_SingleLine.js index eb6734b86e..a53e8bf8d0 100644 --- a/packages/react-ui-components/src/SelectBox_Option_SingleLine/selectBox_Option_SingleLine.js +++ b/packages/react-ui-components/src/SelectBox_Option_SingleLine/selectBox_Option_SingleLine.js @@ -3,34 +3,57 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import ListPreviewElement from '../ListPreviewElement'; import mergeClassNames from 'classnames'; +import style from './style.module.css'; class SelectBox_Option_SingleLine extends PureComponent { static propTypes = { option: PropTypes.shape({ label: PropTypes.string.isRequired, icon: PropTypes.string, - disabled: PropTypes.bool + disabled: PropTypes.bool, + title: PropTypes.string }).isRequired, disabled: PropTypes.bool, - className: PropTypes.string + className: PropTypes.string, + + icon: PropTypes.string, + + linkOptions: PropTypes.shape({ + href: PropTypes.string.isRequired, + target: PropTypes.string, + rel: PropTypes.string, + onClick: PropTypes.func + }) } render() { - const {option, className, disabled, icon} = this.props; + const {option, className, disabled, icon, linkOptions} = this.props; const isDisabled = disabled || option.disabled; const finalClassNames = mergeClassNames({ - [className]: className + [className]: className, + [style.linkedItem]: linkOptions + }); + const linkClassname = mergeClassNames({ + [style.dropdownLink]: true, + [style.hasIcon]: (Boolean(option.icon || icon)) }); const previewElementIcon = option.icon ? option.icon : (icon ? icon : null); return ( - {option.label} + {linkOptions ? ( + {option.label} + ) : ( + {option.label} + )} ); } diff --git a/packages/react-ui-components/src/SelectBox_Option_SingleLine/style.module.css b/packages/react-ui-components/src/SelectBox_Option_SingleLine/style.module.css new file mode 100644 index 0000000000..2eab7a22d9 --- /dev/null +++ b/packages/react-ui-components/src/SelectBox_Option_SingleLine/style.module.css @@ -0,0 +1,14 @@ +.dropdownLink { + color: white; + padding: 5px 14px; + display: inline-block; + width: 100%; + +} +.hasIcon { + width: calc(100% - 2em); + padding: 5px 0px; +} +.linkedItem { + padding: 0px !important; +}