diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RelationDPState/index.js b/packages/strapi-plugin-content-manager/admin/src/components/RelationDPState/index.js index 0252b84d32..fed7289d68 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RelationDPState/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RelationDPState/index.js @@ -1,21 +1,28 @@ import styled from 'styled-components'; const RelationDPState = styled.div` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + margin: auto; &:before { content: ''; display: flex; width: 6px; height: 6px; - margin-bottom: 1px; - margin-left: 10px; + margin-top: ${({ marginTop }) => marginTop}; + margin-left: ${({ marginLeft }) => marginLeft}; + margin-bottom: ${({ marginBottom }) => marginBottom}; + margin-right: ${({ marginRight }) => marginRight}; border-radius: 50%; background-color: ${({ theme, isDraft }) => isDraft ? theme.main.colors.mediumBlue : theme.main.colors.green}; } `; +RelationDPState.defaultProps = { + marginLeft: '10px', + marginRight: '0', + marginTop: '0', + marginBottom: '1px', +}; + export default RelationDPState; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/components.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/components.js index 214c3bbe91..8a54a94910 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/components.js @@ -92,6 +92,7 @@ const Li = styled.li` > div { width: 90%; > a { + flex-grow: 2; max-width: 100%; color: rgb(35, 56, 77); } @@ -143,7 +144,7 @@ const Li = styled.li` const Span = styled.span` display: block; - max-width: 100%; + max-width: calc(100% - 10px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js index 5a4bf9c4b6..e3c680d1b8 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js @@ -9,6 +9,7 @@ import ListItem from './ListItem'; function SelectMany({ addRelation, + components, mainField, name, hasDraftAndPublish, @@ -57,6 +58,8 @@ function SelectMany({ return ( <> { + const Component = components.ClearIndicator; + + return ( + + + + ); +}; + +export default ClearIndicator; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/DropdownIndicator.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/DropdownIndicator.js new file mode 100644 index 0000000000..628b29aa46 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/DropdownIndicator.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Flex } from '@buffetjs/core'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; + +const Wrapper = styled(Flex)` + height: 100%; + width: 32px; + background: #fafafb; + > svg { + align-self: center; + font-size: 11px; + color: #b3b5b9; + } +`; + +const DropdownIndicator = ({ selectProps: { menuIsOpen } }) => { + const icon = menuIsOpen ? 'caret-up' : 'caret-down'; + + return ( + + + + ); +}; + +DropdownIndicator.propTypes = { + selectProps: PropTypes.shape({ + menuIsOpen: PropTypes.bool.isRequired, + }).isRequired, +}; + +Wrapper.defaultProps = { + flexDirection: 'column', + justifyContent: 'center', +}; + +export default DropdownIndicator; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/IndicatorSeparator.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/IndicatorSeparator.js new file mode 100644 index 0000000000..458dd41265 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/IndicatorSeparator.js @@ -0,0 +1,3 @@ +const IndicatorSeparator = () => null; + +export default IndicatorSeparator; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/Option.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/Option.js new file mode 100644 index 0000000000..feefa8e701 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/Option.js @@ -0,0 +1,52 @@ +import React from 'react'; +import styled from 'styled-components'; +import { components } from 'react-select'; +import PropTypes from 'prop-types'; +import { get, isEmpty } from 'lodash'; +import { Flex, Text } from '@buffetjs/core'; +import RelationDPState from '../RelationDPState'; + +const TextGrow = styled(Text)` + flex-grow: 2; +`; + +const Option = props => { + const Component = components.Option; + const hasDraftAndPublish = props.selectProps.hasDraftAndPublish; + const isDraft = isEmpty(get(props, 'data.value.published_at')); + + if (hasDraftAndPublish) { + return ( + + + + + + {props.label} + + + + ); + } + + return ( + + {props.label} + + ); +}; + +Option.propTypes = { + label: PropTypes.string.isRequired, + selectProps: PropTypes.shape({ + hasDraftAndPublish: PropTypes.bool, + }).isRequired, +}; + +export default Option; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/components.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/components.js index e79afd371d..4d09ffd16e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/components.js @@ -1,132 +1,14 @@ import styled from 'styled-components'; +import { Text } from '@buffetjs/core'; -const Wrapper = styled.div` - position: relative; - margin-bottom: 27px; - label { - width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 1.3rem; - font-weight: 500; - } +const BaselineAlignment = styled.div` + padding-top: 1px; +`; - nav + div { - height: 34px; - background-color: white; - margin-top: 5px; - > div { - min-height: 34px; - height: 100%; - border: 1px solid #e3e9f3; - border-radius: 3px; - box-shadow: 0 1px 1px 0 rgba(104, 118, 142, 0.05); - flex-wrap: initial; - padding: 0 10px; - - /* Arrow */ - &:before { - content: '\f0d7'; - position: absolute; - top: 5px; - right: 10px; - font-family: 'FontAwesome'; - font-size: 14px; - font-weight: 800; - color: #aaa; - } - > div { - padding: 0; - &:first-of-type { - /* Placeholder */ - > div span { - color: #aaa; - } - } - } - div:last-of-type { - span { - display: none; - & + div { - display: none; - } - } - svg { - width: 15px; - margin-right: 6px; - } - } - span { - font-size: 13px; - line-height: 34px; - color: #333740; - } - :hover { - cursor: pointer; - border-color: #e3e9f3; - &:before { - color: #666; - } - } - } - span[aria-live='polite'] + div { - &:before { - transform: rotate(180deg); - top: 4px; - } - & + div { - z-index: 2; - height: fit-content; - padding: 0; - margin-top: -2px; - border-top-left-radius: 0; - border-top-right-radius: 0; - &:before { - content: ''; - } - div { - width: 100%; - } - > div { - max-height: 200px; - height: fit-content; - div { - height: 36px; - cursor: pointer; - } - } - } - } +const A = styled(Text)` + &:hover { + text-decoration: underline; } `; -const Nav = styled.nav` - > div { - display: flex; - - justify-content: space-between; - - a { - color: #007eff !important; - font-size: 1.3rem; - - &:hover { - text-decoration: underline !important; - cursor: pointer; - } - } - } - .description { - color: #9ea7b8; - font-family: 'Lato'; - font-size: 1.2rem; - margin-top: -5px; - max-width: 100%; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } -`; - -export { Nav, Wrapper }; +export { A, BaselineAlignment }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js index 14524e5e2f..448706e8b9 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js @@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl'; import { Link, useLocation } from 'react-router-dom'; import { cloneDeep, findIndex, get, isArray, isEmpty, set, has } from 'lodash'; import { request } from 'strapi-helper-plugin'; +import { Flex, Text, Padded } from '@buffetjs/core'; import pluginId from '../../pluginId'; import useDataManager from '../../hooks/useDataManager'; import useEditView from '../../hooks/useEditView'; @@ -12,8 +13,12 @@ import { getFieldName } from '../../utils'; import NotAllowedInput from '../NotAllowedInput'; import SelectOne from '../SelectOne'; import SelectMany from '../SelectMany'; -import { Nav, Wrapper } from './components'; -import { connect, select } from './utils'; +import ClearIndicator from './ClearIndicator'; +import DropdownIndicator from './DropdownIndicator'; +import IndicatorSeparator from './IndicatorSeparator'; +import Option from './Option'; +import { A, BaselineAlignment } from './components'; +import { connect, select, styles } from './utils'; function SelectWrapper({ componentUid, @@ -189,24 +194,14 @@ function SelectWrapper({ targetModel ) ? null : ( - + + {msg => {msg}} + ); const Component = isSingle ? SelectOne : SelectMany; const associationsLength = isArray(value) ? value.length : 0; - const customStyles = { - option: provided => { - return { - ...provided, - maxWidth: '100% !important', - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }; - }, - }; - const isDisabled = useMemo(() => { if (isMorph) { return true; @@ -228,54 +223,63 @@ function SelectWrapper({ } return ( - - - { - addRelation({ target: { name, value } }); - }} - hasDraftAndPublish={hasDraftAndPublish} - id={name} - isDisabled={isDisabled} - isLoading={isLoading} - isClearable - mainField={mainField} - move={moveRelation} - name={name} - options={filteredOptions} - onChange={value => { - onChange({ target: { name, value: value ? value.value : value } }); - }} - onInputChange={onInputChange} - onMenuClose={() => { - setState(prevState => ({ ...prevState, _contains: '' })); - }} - onMenuScrollToBottom={onMenuScrollToBottom} - onRemove={onRemoveRelation} - placeholder={ - isEmpty(placeholder) ? ( - - ) : ( - placeholder - ) - } - styles={customStyles} - targetModel={targetModel} - value={value} - /> -
- + + + + + {label} + {!isSingle && ` (${associationsLength})`} + + {isSingle && link} + + {!isEmpty(description) && ( + + + + {description} + + + )} + + + + { + addRelation({ target: { name, value } }); + }} + components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }} + hasDraftAndPublish={hasDraftAndPublish} + id={name} + isDisabled={isDisabled} + isLoading={isLoading} + isClearable + mainField={mainField} + move={moveRelation} + name={name} + options={filteredOptions} + onChange={value => { + onChange({ target: { name, value: value ? value.value : value } }); + }} + onInputChange={onInputChange} + onMenuClose={() => { + setState(prevState => ({ ...prevState, _contains: '' })); + }} + onMenuScrollToBottom={onMenuScrollToBottom} + onRemove={onRemoveRelation} + placeholder={ + isEmpty(placeholder) ? ( + + ) : ( + placeholder + ) + } + styles={styles} + targetModel={targetModel} + value={value} + /> + +
+ ); } diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/index.js index ba5c550759..537c7f6370 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/index.js @@ -1,2 +1,3 @@ export { default as connect } from './connect'; export { default as select } from './select'; +export { default as styles } from './styles'; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/styles.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/styles.js new file mode 100644 index 0000000000..9d909bd129 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/styles.js @@ -0,0 +1,100 @@ +/* eslint-disable indent */ +/* eslint-disable no-nested-ternary */ + +const styles = { + container: base => ({ ...base, background: '#ffffff' }), + control: (base, state) => { + const borderRadiusStyle = state.selectProps.menuIsOpen + ? { + borderBottomLeftRadius: '0 !important', + borderBottomRightRadius: '0 !important', + } + : {}; + + const { + selectProps: { error, value }, + } = state; + + let border; + let borderBottom; + let backgroundColor; + + if (state.isFocused) { + border = '1px solid #78caff !important'; + } else if (error && !value.length) { + border = '1px solid #f64d0a !important'; + } else { + border = '1px solid #e3e9f3 !important'; + } + + if (state.menuIsOpen === true) { + borderBottom = '1px solid #e3e9f3 !important'; + } + + if (state.isDisabled) { + backgroundColor = '#fafafb !important'; + } + + return { + ...base, + fontSize: 13, + height: 34, + minHeight: 34, + border, + outline: 0, + boxShadow: 0, + borderRadius: '2px !important', + ...borderRadiusStyle, + borderBottom, + backgroundColor, + }; + }, + input: base => ({ ...base, marginLeft: 10 }), + menu: base => { + return { + ...base, + width: '100%', + margin: '0', + paddingTop: 0, + borderRadius: '2px !important', + borderTopLeftRadius: '0 !important', + borderTopRightRadius: '0 !important', + border: '1px solid #78caff !important', + boxShadow: 0, + borderTop: '0 !important', + fontSize: '13px', + }; + }, + menuList: base => ({ + ...base, + maxHeight: '112px', + paddingTop: 2, + }), + option: (base, state) => { + return { + ...base, + height: 36, + backgroundColor: state.isSelected ? '#fff' : base.backgroundColor, + color: state.isSelected ? '#007eff' : '#333740', + fontWeight: state.isSelected ? '600' : '400', + cursor: 'pointer', + }; + }, + placeholder: base => ({ + ...base, + marginTop: 0, + marginLeft: 10, + color: '#aaa', + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + maxWidth: 'calc(100% - 32px)', + }), + valueContainer: base => ({ + ...base, + padding: '2px 0px 4px 0px', + lineHeight: '18px', + }), +}; + +export default styles;