mirror of
https://github.com/strapi/strapi.git
synced 2025-09-03 05:39:36 +00:00
Remove old components
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
b31c6e3e7d
commit
0bbc99a331
@ -12,7 +12,6 @@ const FileWrapper = styled(Row)`
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 26px;
|
width: 26px;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
// TODO
|
|
||||||
background: ${({ theme }) => theme.colors.neutral100};
|
background: ${({ theme }) => theme.colors.neutral100};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
import styled, { css } from 'styled-components';
|
|
||||||
|
|
||||||
const sizes = {
|
|
||||||
small: '35px',
|
|
||||||
big: '127px',
|
|
||||||
margin: '20px',
|
|
||||||
};
|
|
||||||
const max = 4;
|
|
||||||
|
|
||||||
const StyledMediaPreviewList = styled.div`
|
|
||||||
position: relative;
|
|
||||||
height: ${sizes.small};
|
|
||||||
> div {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
${createCSS()};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
function createCSS() {
|
|
||||||
let styles = '';
|
|
||||||
|
|
||||||
for (let i = 0; i <= max; i += 1) {
|
|
||||||
styles += `
|
|
||||||
&:nth-of-type(${i}) {
|
|
||||||
left: calc( ${sizes.margin} * ${i - 1});
|
|
||||||
z-index: ${i};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return css`
|
|
||||||
${styles}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MediaPreviewItem = styled.div`
|
|
||||||
width: ${sizes.small};
|
|
||||||
height: ${sizes.small};
|
|
||||||
div {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: calc(${sizes.small} / 2);
|
|
||||||
background-color: #f3f3f4;
|
|
||||||
border: 1px solid #f3f3f4;
|
|
||||||
}
|
|
||||||
&.hoverable {
|
|
||||||
:hover {
|
|
||||||
z-index: ${max + 1};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const MediaPreviewFile = styled(MediaPreviewItem)`
|
|
||||||
span {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
position: relative;
|
|
||||||
background-color: #f3f3f4;
|
|
||||||
color: #333740;
|
|
||||||
text-align: center;
|
|
||||||
line-height: ${sizes.small};
|
|
||||||
border: 1px solid white;
|
|
||||||
span {
|
|
||||||
display: block;
|
|
||||||
padding: 0 3px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
i,
|
|
||||||
svg {
|
|
||||||
position: absolute;
|
|
||||||
left: 1px;
|
|
||||||
top: -1px;
|
|
||||||
font-size: 15px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
&:before {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
line-height: 35px;
|
|
||||||
background: #f3f3f4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div + span {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
left: 120%;
|
|
||||||
bottom: -10px;
|
|
||||||
max-width: 150px;
|
|
||||||
color: #333740;
|
|
||||||
}
|
|
||||||
&.hoverable {
|
|
||||||
:hover {
|
|
||||||
div + span {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const MediaPreviewText = styled(MediaPreviewItem)`
|
|
||||||
div {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #333740;
|
|
||||||
text-align: center;
|
|
||||||
line-height: ${sizes.small};
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const MediaPreviewImage = styled(MediaPreviewItem)`
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
object-fit: cover;
|
|
||||||
background-color: #fafafb;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
position: relative;
|
|
||||||
&::before {
|
|
||||||
content: '-';
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: white;
|
|
||||||
color: transparent;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div + img {
|
|
||||||
display: none;
|
|
||||||
width: ${sizes.big};
|
|
||||||
height: ${sizes.big};
|
|
||||||
border-radius: calc(${sizes.big} / 2);
|
|
||||||
margin-top: calc(${`-${sizes.big}`} - ${sizes.small} - 5px);
|
|
||||||
margin-left: calc((${sizes.small} - ${sizes.big}) / 2);
|
|
||||||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hoverable {
|
|
||||||
:hover {
|
|
||||||
div {
|
|
||||||
&::before {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div + img {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export {
|
|
||||||
MediaPreviewFile,
|
|
||||||
MediaPreviewImage,
|
|
||||||
MediaPreviewItem,
|
|
||||||
MediaPreviewText,
|
|
||||||
StyledMediaPreviewList,
|
|
||||||
};
|
|
@ -1,110 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { get, isArray, includes, isEmpty } from 'lodash';
|
|
||||||
import { getFileExtension, prefixFileUrlWithBackendUrl } from '@strapi/helper-plugin';
|
|
||||||
import DefaultIcon from '../../icons/Na';
|
|
||||||
import {
|
|
||||||
StyledMediaPreviewList,
|
|
||||||
MediaPreviewFile,
|
|
||||||
MediaPreviewImage,
|
|
||||||
MediaPreviewItem,
|
|
||||||
MediaPreviewText,
|
|
||||||
} from './StyledMediaPreviewList';
|
|
||||||
|
|
||||||
const IMAGE_PREVIEW_COUNT = 3;
|
|
||||||
|
|
||||||
function MediaPreviewList({ hoverable, files }) {
|
|
||||||
const renderImage = image => {
|
|
||||||
const { name, size, url } = image;
|
|
||||||
const thumbnail = get(image, ['formats', 'thumbnail', 'url'], null);
|
|
||||||
const fileUrl = thumbnail || url;
|
|
||||||
|
|
||||||
if (!thumbnail && size > 20000) {
|
|
||||||
return renderFile(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MediaPreviewImage className={hoverable ? 'hoverable' : ''}>
|
|
||||||
<div>
|
|
||||||
<img src={prefixFileUrlWithBackendUrl(fileUrl)} alt={`${name}`} />
|
|
||||||
</div>
|
|
||||||
<img src={prefixFileUrlWithBackendUrl(fileUrl)} alt={`${name}`} />
|
|
||||||
</MediaPreviewImage>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderFile = file => {
|
|
||||||
const { ext, name } = file;
|
|
||||||
const fileExtension = getFileExtension(ext);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MediaPreviewFile className={hoverable ? 'hoverable' : ''}>
|
|
||||||
{fileExtension ? (
|
|
||||||
<div>
|
|
||||||
<span>{fileExtension}</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<MediaPreviewItem>
|
|
||||||
<DefaultIcon />
|
|
||||||
</MediaPreviewItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<span>{name}</span>
|
|
||||||
</MediaPreviewFile>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderItem = file => {
|
|
||||||
const { mime } = file;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment key={JSON.stringify(file)}>
|
|
||||||
{includes(mime, 'image') ? renderImage(file) : renderFile(file)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderText = count => {
|
|
||||||
return (
|
|
||||||
<MediaPreviewText>
|
|
||||||
<div>
|
|
||||||
<span>+{count}</span>
|
|
||||||
</div>
|
|
||||||
</MediaPreviewText>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderMultipleItems = files => {
|
|
||||||
return files.map((file, index) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={JSON.stringify(file)}>
|
|
||||||
{index === IMAGE_PREVIEW_COUNT && files.length > IMAGE_PREVIEW_COUNT + 1
|
|
||||||
? renderText(files.length - IMAGE_PREVIEW_COUNT)
|
|
||||||
: renderItem(file)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return !!files && !isEmpty(files) ? (
|
|
||||||
<StyledMediaPreviewList>
|
|
||||||
{!isArray(files) ? renderItem(files) : renderMultipleItems(files)}
|
|
||||||
</StyledMediaPreviewList>
|
|
||||||
) : (
|
|
||||||
<MediaPreviewItem>
|
|
||||||
<DefaultIcon />
|
|
||||||
</MediaPreviewItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaPreviewList.defaultProps = {
|
|
||||||
hoverable: true,
|
|
||||||
files: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
MediaPreviewList.propTypes = {
|
|
||||||
hoverable: PropTypes.bool,
|
|
||||||
files: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MediaPreviewList;
|
|
@ -1,7 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
const CountWrapper = styled.div`
|
|
||||||
padding-top: 0.3rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default CountWrapper;
|
|
@ -1,123 +0,0 @@
|
|||||||
import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react';
|
|
||||||
import { Text, Padded } from '@buffetjs/core';
|
|
||||||
import { LoadingIndicator, Tooltip } from '@buffetjs/styles';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { axiosInstance } from '../../../core/utils';
|
|
||||||
import { getDisplayedValue, getRequestUrl } from '../../utils';
|
|
||||||
|
|
||||||
const RelationPreviewTooltip = ({
|
|
||||||
tooltipId,
|
|
||||||
rowId,
|
|
||||||
mainField,
|
|
||||||
name,
|
|
||||||
queryInfos: { endPoint },
|
|
||||||
size,
|
|
||||||
}) => {
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [relationData, setRelationData] = useState([]);
|
|
||||||
const tooltipRef = useRef();
|
|
||||||
|
|
||||||
const fetchRelationData = useCallback(
|
|
||||||
async source => {
|
|
||||||
const requestURL = getRequestUrl(`${endPoint}/${rowId}/${name}`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: { results },
|
|
||||||
} = await axiosInstance.get(requestURL, { cancelToken: source.token });
|
|
||||||
|
|
||||||
setRelationData(results);
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (err) {
|
|
||||||
if (axios.isCancel(err)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error({ err });
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[endPoint, name, rowId]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const CancelToken = axios.CancelToken;
|
|
||||||
const source = CancelToken.source();
|
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
fetchRelationData(source);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
|
|
||||||
source.cancel('Operation canceled by the user.');
|
|
||||||
};
|
|
||||||
}, [fetchRelationData]);
|
|
||||||
|
|
||||||
const getValueToDisplay = useCallback(
|
|
||||||
item => {
|
|
||||||
return getDisplayedValue(mainField.schema.type, item[mainField.name], mainField.name);
|
|
||||||
},
|
|
||||||
[mainField]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Used to update the position after the loader
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!isLoading && tooltipRef.current) {
|
|
||||||
// A react-tooltip uncaught error is triggered when updatePosition is called in firefox.
|
|
||||||
// https://github.com/wwayne/react-tooltip/issues/619
|
|
||||||
try {
|
|
||||||
tooltipRef.current.updatePosition();
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [isLoading]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip ref={tooltipRef} id={tooltipId}>
|
|
||||||
<div>
|
|
||||||
{isLoading ? (
|
|
||||||
<Padded left right size="sm">
|
|
||||||
<LoadingIndicator borderWidth="3px" size="2rem" />
|
|
||||||
</Padded>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{relationData.map(item => (
|
|
||||||
<Padded key={item.id} top bottom size="xs">
|
|
||||||
<Text ellipsis color="white">
|
|
||||||
{getValueToDisplay(item)}
|
|
||||||
</Text>
|
|
||||||
</Padded>
|
|
||||||
))}
|
|
||||||
{size > 10 && (
|
|
||||||
<Padded top size="xs">
|
|
||||||
<Text color="white">[...]</Text>
|
|
||||||
</Padded>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
RelationPreviewTooltip.propTypes = {
|
|
||||||
tooltipId: PropTypes.string.isRequired,
|
|
||||||
mainField: PropTypes.exact({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
schema: PropTypes.shape({
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
size: PropTypes.number.isRequired,
|
|
||||||
rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
||||||
queryInfos: PropTypes.shape({
|
|
||||||
endPoint: PropTypes.string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RelationPreviewTooltip;
|
|
@ -1,111 +0,0 @@
|
|||||||
import React, { memo, useState, useMemo } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Flex, Padded, Count } from '@buffetjs/core';
|
|
||||||
import { Tooltip } from '@buffetjs/styles';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import { getTrad } from '../../utils';
|
|
||||||
import Truncate from '../Truncate';
|
|
||||||
import Truncated from '../Truncated';
|
|
||||||
import CountWrapper from './CountWrapper';
|
|
||||||
import RelationPreviewTooltip from './RelationPreviewTooltip';
|
|
||||||
|
|
||||||
const RelationPreviewList = ({
|
|
||||||
options: {
|
|
||||||
metadatas: { mainField },
|
|
||||||
relationType,
|
|
||||||
value,
|
|
||||||
rowId,
|
|
||||||
cellId,
|
|
||||||
name,
|
|
||||||
queryInfos,
|
|
||||||
},
|
|
||||||
}) => {
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const [tooltipIsDisplayed, setDisplayTooltip] = useState(false);
|
|
||||||
const isSingle = ['oneWay', 'oneToOne', 'manyToOne'].includes(relationType);
|
|
||||||
const tooltipId = useMemo(() => `${rowId}-${cellId}`, [rowId, cellId]);
|
|
||||||
const valueToDisplay = value ? value[mainField.name] : '-';
|
|
||||||
|
|
||||||
if (value === undefined) {
|
|
||||||
return (
|
|
||||||
<Truncate>
|
|
||||||
<Truncated>-</Truncated>
|
|
||||||
</Truncate>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSingle) {
|
|
||||||
return (
|
|
||||||
<Truncate>
|
|
||||||
<Truncated>
|
|
||||||
<span data-for={tooltipId} data-tip={valueToDisplay}>
|
|
||||||
{valueToDisplay}
|
|
||||||
</span>
|
|
||||||
</Truncated>
|
|
||||||
<Tooltip id={tooltipId} />
|
|
||||||
</Truncate>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const size = value ? value.count : 0;
|
|
||||||
|
|
||||||
const handleTooltipToggle = () => {
|
|
||||||
setDisplayTooltip(prev => !prev);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Truncate style={{ maxWidth: 'fit-content' }}>
|
|
||||||
<Flex
|
|
||||||
// This is useful to avoid the render of every tooltips of the list at the same time.
|
|
||||||
// https://github.com/wwayne/react-tooltip/issues/524
|
|
||||||
onMouseEnter={handleTooltipToggle}
|
|
||||||
onMouseLeave={handleTooltipToggle}
|
|
||||||
data-for={tooltipId}
|
|
||||||
data-tip={JSON.stringify(value)}
|
|
||||||
>
|
|
||||||
<CountWrapper>
|
|
||||||
<Count count={size} />
|
|
||||||
</CountWrapper>
|
|
||||||
<Padded left size="xs" />
|
|
||||||
<Truncated>
|
|
||||||
{formatMessage({
|
|
||||||
id: getTrad(
|
|
||||||
size > 1 ? 'containers.ListPage.items.plural' : 'containers.ListPage.items.singular'
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
</Truncated>
|
|
||||||
</Flex>
|
|
||||||
{size > 0 && tooltipIsDisplayed && (
|
|
||||||
<RelationPreviewTooltip
|
|
||||||
name={name}
|
|
||||||
rowId={rowId}
|
|
||||||
tooltipId={tooltipId}
|
|
||||||
value={value}
|
|
||||||
mainField={mainField}
|
|
||||||
queryInfos={queryInfos}
|
|
||||||
size={size}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Truncate>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
RelationPreviewList.propTypes = {
|
|
||||||
options: PropTypes.shape({
|
|
||||||
cellId: PropTypes.string.isRequired,
|
|
||||||
metadatas: PropTypes.shape({
|
|
||||||
mainField: PropTypes.object.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
relationType: PropTypes.string,
|
|
||||||
rowId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
||||||
type: PropTypes.string,
|
|
||||||
queryInfos: PropTypes.shape({
|
|
||||||
endPoint: PropTypes.string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
value: PropTypes.any,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(RelationPreviewList);
|
|
@ -1,5 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
const Truncate = styled.div``;
|
|
||||||
|
|
||||||
export default Truncate;
|
|
@ -1,10 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
const Truncated = styled.p`
|
|
||||||
overflow-x: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-bottom: 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default Truncated;
|
|
Loading…
x
Reference in New Issue
Block a user