Display content type section UI

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2021-02-10 19:39:05 +01:00
parent 83d414b79b
commit 193b3c207b
7 changed files with 287 additions and 33 deletions

View File

@ -1,4 +1,4 @@
import React, { memo } from 'react';
import React, { memo, useState, useMemo, useCallback } from 'react';
import PropTypes from 'prop-types';
import { Padded, Flex } from '@buffetjs/core';
import CheckboxWithCondition from '../../../CheckboxWithCondition';
@ -6,38 +6,66 @@ import Chevron from '../../../Chevron';
import HiddenAction from '../../../HiddenAction';
import RequiredSign from '../../../RequiredSign';
import RowLabel from '../../../RowLabel';
import RecursiveMatrix from '../SubActionRow';
import Wrapper from './Wrapper';
const ActionRow = ({ name, value, required, propertyActions }) => {
const isActive = true;
const isCollapsable = typeof value === 'object';
const [rowToOpen, setRowToOpen] = useState(null);
const isActive = rowToOpen === name;
const recursiveValues = useMemo(() => {
if (!Array.isArray(value)) {
return [];
}
return value;
}, [value]);
const isCollapsable = recursiveValues.length > 0;
const handleClick = useCallback(() => {
if (isCollapsable) {
setRowToOpen(prev => {
if (prev === name) {
return null;
}
return name;
});
}
}, [isCollapsable, name]);
return (
<Wrapper alignItems="center" isCollapsable={isCollapsable}>
<Flex style={{ flex: 1 }}>
<Padded left size="sm" />
<RowLabel
width="15rem"
onClick={() => console.log('todo')}
isCollapsable={isCollapsable}
label={name}
// TODO
textColor="grey"
>
{required && <RequiredSign>*</RequiredSign>}
<Chevron icon={isActive ? 'caret-up' : 'caret-down'} />
</RowLabel>
<>
<Wrapper alignItems="center" isCollapsable={isCollapsable}>
<Flex style={{ flex: 1 }}>
{propertyActions.map(action => {
if (!action.isActionRelatedToCurrentProperty) {
return <HiddenAction key={action.label} />;
}
<Padded left size="sm" />
<RowLabel
width="15rem"
onClick={handleClick}
isCollapsable={isCollapsable}
label={name}
// TODO
textColor="grey"
>
{required && <RequiredSign>*</RequiredSign>}
<Chevron icon={isActive ? 'caret-up' : 'caret-down'} />
</RowLabel>
<Flex style={{ flex: 1 }}>
{propertyActions.map(action => {
if (!action.isActionRelatedToCurrentProperty) {
return <HiddenAction key={action.label} />;
}
return <CheckboxWithCondition key={action.label} name="todo" />;
})}
return <CheckboxWithCondition key={action.label} name="todo" />;
})}
</Flex>
</Flex>
</Flex>
</Wrapper>
</Wrapper>
{isActive && (
<RecursiveMatrix name={name} propertyActions={propertyActions} values={recursiveValues} />
)}
</>
);
};

View File

@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
const Curve = props => (
<svg
style={{
height: '14px',
transform: 'translate(-3.2px, -1px)',
position: 'relative',
}}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 21.08 21"
{...props}
>
<g>
<path
d="M2.58 2.5q-1.2 16 16 16"
fill="none"
stroke={props.fill}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="5"
/>
</g>
</svg>
);
Curve.defaultProps = {
fill: '#f3f4f4',
};
Curve.propTypes = {
fill: PropTypes.string,
};
export default Curve;

View File

@ -0,0 +1,8 @@
/* eslint-disable indent */
import styled from 'styled-components';
const Wrapper = styled.div`
padding-left: 15px;
`;
export default Wrapper;

View File

@ -0,0 +1,116 @@
import React, { memo, useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { Flex, Text } from '@buffetjs/core';
import styled from 'styled-components';
import CheckboxWithCondition from '../../../CheckboxWithCondition';
import Chevron from '../../../Chevron';
import CollapseLabel from '../../../CollapseLabel';
import HiddenAction from '../../../HiddenAction';
import RequiredSign from '../../../RequiredSign';
import Curve from './Curve';
import { RowStyle, RowWrapper } from './row';
import { LeftBorderTimeline, TopTimeline } from './timeline';
import Wrapper from './Wrapper';
const SubLevelWrapper = styled.div`
padding-bottom: 8px;
`;
const SubActionRow = ({ recursiveLevel, values, propertyActions }) => {
const [rowToOpen, setRowToOpen] = useState(null);
const handleClickToggleSubLevel = useCallback(name => {
setRowToOpen(prev => {
if (prev === name) {
return null;
}
return name;
});
}, []);
const displayedRecursiveValue = useMemo(() => {
if (!rowToOpen) {
return null;
}
return values.find(({ value }) => value === rowToOpen);
}, [rowToOpen, values]);
return (
<Wrapper>
<TopTimeline />
{values.map((value, index) => {
const isVisible = index + 1 < values.length;
const isArrayType = Array.isArray(value.value);
const isSmall = isArrayType || index + 1 === values.length;
const isActive = rowToOpen === value.value;
return (
<LeftBorderTimeline key={value.key} isVisible={isVisible}>
<RowWrapper isSmall={isSmall}>
<Curve fill="#a5d5ff" />
<Flex style={{ flex: 1 }}>
<RowStyle level={recursiveLevel} isActive={isActive} isCollapsable={isArrayType}>
<CollapseLabel
alignItems="center"
isCollapsable={isArrayType}
onClick={() => {
if (isArrayType) {
handleClickToggleSubLevel(value.value);
}
}}
title={value.key}
>
<Text
color={isActive ? 'mediumBlue' : 'grey'}
ellipsis
fontSize="xs"
fontWeight="bold"
lineHeight="20px"
textTransform="uppercase"
>
{value.key}
</Text>
{value.required && <RequiredSign>*</RequiredSign>}
<Chevron icon={isActive ? 'caret-up' : 'caret-down'} />
</CollapseLabel>
</RowStyle>
<Flex style={{ flex: 1 }}>
{propertyActions.map(action => {
if (!action.isActionRelatedToCurrentProperty) {
return <HiddenAction key={action.label} />;
}
return <CheckboxWithCondition key={action.label} name="todo" />;
})}
</Flex>
</Flex>
</RowWrapper>
{displayedRecursiveValue && isActive && (
<SubLevelWrapper>
<SubActionRow
name={displayedRecursiveValue.key}
propertyActions={propertyActions}
recursiveLevel={recursiveLevel + 1}
values={displayedRecursiveValue.value}
/>
</SubLevelWrapper>
)}
</LeftBorderTimeline>
);
})}
</Wrapper>
);
};
SubActionRow.defaultProps = {
recursiveLevel: 0,
};
SubActionRow.propTypes = {
propertyActions: PropTypes.array.isRequired,
recursiveLevel: PropTypes.number,
values: PropTypes.array.isRequired,
};
export default memo(SubActionRow);

View File

@ -0,0 +1,47 @@
import styled from 'styled-components';
import { Flex, Text } from '@buffetjs/core';
import PropTypes from 'prop-types';
import Chevron from '../../../Chevron';
const activeStyle = theme => `
color: ${theme.main.colors.mediumBlue};
${Text} {
color: ${theme.main.colors.mediumBlue};
}
${Chevron} {
display: block;
color: ${theme.main.colors.mediumBlue};
}
`;
const RowStyle = styled.div`
padding-left: ${({ theme }) => theme.main.sizes.paddings.xs};
width: ${({ level }) => 128 - level * 18}px;
${Chevron} {
width: 13px;
}
${({ isCollapsable, theme }) =>
isCollapsable &&
`
${Chevron} {
display: block;
color: ${theme.main.colors.grey};
}
&:hover {
${activeStyle(theme)}
}
`}
${({ isActive, theme }) => isActive && activeStyle(theme)}}
`;
RowStyle.propTypes = {
isActive: PropTypes.bool.isRequired,
isCollapsable: PropTypes.bool.isRequired,
level: PropTypes.number.isRequired,
};
const RowWrapper = styled(Flex)`
height: ${({ isSmall }) => (isSmall ? '28px' : '36px')};
`;
export { RowStyle, RowWrapper };

View File

@ -0,0 +1,15 @@
import styled from 'styled-components';
const LeftBorderTimeline = styled.div`
border-left: ${({ isVisible }) => (isVisible ? '3px solid #a5d5ff' : '3px solid transparent')};
`;
const TopTimeline = styled.div`
padding-top: 8px;
width: 3px;
background-color: #a5d5ff;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
`;
export { LeftBorderTimeline, TopTimeline };

View File

@ -341,6 +341,17 @@ const data = {
{
key: 'media',
value: 'media',
required: true,
},
{
key: 'closing',
value: [
{
key: 'name',
value: [{ key: 'test', value: 'test' }],
},
],
},
],
},
@ -379,10 +390,7 @@ const data = {
{
label: 'Create',
actionId: 'content-manager.explorer.create',
subjects: [
// 'restaurant',
'address',
],
subjects: ['restaurant', 'address'],
applyToProperties: ['fields', 'locales'],
},
{
@ -394,10 +402,7 @@ const data = {
{
label: 'Update',
actionId: 'content-manager.explorer.update',
subjects: [
'address',
// restaurant
],
subjects: ['address', 'restaurant'],
applyToProperties: ['fields'],
},
{