refactor: use one AssetCardBase

This commit is contained in:
Josh 2022-09-27 13:57:30 +01:00
parent 2e44e15bc7
commit 102e4d1c84
5 changed files with 167 additions and 322 deletions

View File

@ -0,0 +1,122 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Box } from '@strapi/design-system/Box';
import {
Card,
CardAction,
CardBadge,
CardBody,
CardCheckbox,
CardContent,
CardHeader,
CardTitle,
CardSubtitle,
} from '@strapi/design-system/Card';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import { useIntl } from 'react-intl';
import { getTrad } from '../../utils';
const Extension = styled.span`
text-transform: uppercase;
`;
const CardActionsContainer = styled(CardAction)``;
const CardContainer = styled(Card)`
${CardActionsContainer} {
display: none;
}
&:hover {
${CardActionsContainer} {
display: block;
}
}
`;
export const AssetCardBase = ({
children,
name,
extension,
selected,
onSelect,
onRemove,
onEdit,
subtitle,
variant,
}) => {
const { formatMessage } = useIntl();
return (
<CardContainer height="100%">
<CardHeader>
{onSelect && <CardCheckbox value={selected} onValueChange={onSelect} />}
{(onRemove || onEdit) && (
<CardActionsContainer position="end">
{onRemove && (
<IconButton
label={formatMessage({
id: getTrad('control-card.remove-selection'),
defaultMessage: 'Remove from selection',
})}
icon={<Trash />}
onClick={onRemove}
/>
)}
{onEdit && (
<IconButton
label={formatMessage({ id: getTrad('control-card.edit'), defaultMessage: 'Edit' })}
icon={<Pencil />}
onClick={onEdit}
/>
)}
</CardActionsContainer>
)}
{children}
</CardHeader>
<CardBody>
<CardContent>
<Box paddingTop={1}>
<CardTitle as="h2">{name}</CardTitle>
</Box>
<CardSubtitle>
<Extension>{extension}</Extension>
{subtitle}
</CardSubtitle>
</CardContent>
<CardBadge>
{formatMessage({
id: getTrad(`settings.section.${variant.toLowerCase()}.label`),
defaultMessage: variant,
})}
</CardBadge>
</CardBody>
</CardContainer>
);
};
AssetCardBase.defaultProps = {
selected: false,
onEdit: undefined,
onSelect: undefined,
onRemove: undefined,
subtitle: '',
variant: 'Image',
};
AssetCardBase.propTypes = {
children: PropTypes.node.isRequired,
extension: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
onEdit: PropTypes.func,
onSelect: PropTypes.func,
onRemove: PropTypes.func,
selected: PropTypes.bool,
subtitle: PropTypes.string,
variant: PropTypes.oneOf(['Image', 'Video', 'Audio', 'Doc']),
};

View File

@ -1,29 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import {
Card,
CardAction,
CardAsset,
CardBadge,
CardBody,
CardCheckbox,
CardContent,
CardHeader,
CardTitle,
CardSubtitle,
} from '@strapi/design-system/Card';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import { useIntl } from 'react-intl';
import { CardAsset } from '@strapi/design-system/Card';
import { Box } from '@strapi/design-system/Box';
import { AudioPreview } from './AudioPreview';
import { getTrad } from '../../utils';
const Extension = styled.span`
text-transform: uppercase;
`;
import { AudioPreview } from './AudioPreview';
import { AssetCardBase } from './AssetCardBase';
const AudioPreviewWrapper = styled(Box)`
canvas,
@ -34,64 +16,15 @@ const AudioPreviewWrapper = styled(Box)`
}
`;
export const AudioAssetCard = ({
name,
extension,
url,
selected,
onSelect,
onEdit,
onRemove,
size,
}) => {
const { formatMessage } = useIntl();
export const AudioAssetCard = ({ name, url, size, ...restProps }) => {
return (
<Card height="100%">
<CardHeader>
<CardAsset size={size}>
<AudioPreviewWrapper size={size}>
<AudioPreview url={url} alt={name} />
</AudioPreviewWrapper>
</CardAsset>
{onSelect && <CardCheckbox value={selected} onValueChange={onSelect} />}
{(onRemove || onEdit) && (
<CardAction position="end">
{onRemove && (
<IconButton
label={formatMessage({
id: getTrad('control-card.remove-selection'),
defaultMessage: 'Remove from selection',
})}
icon={<Trash />}
onClick={onRemove}
/>
)}
{onEdit && (
<IconButton
label={formatMessage({ id: getTrad('control-card.edit'), defaultMessage: 'Edit' })}
icon={<Pencil />}
onClick={onEdit}
/>
)}
</CardAction>
)}
</CardHeader>
<CardBody>
<CardContent>
<Box paddingTop={1}>
<CardTitle as="h2">{name}</CardTitle>
</Box>
<CardSubtitle>
<Extension>{extension}</Extension>
</CardSubtitle>
</CardContent>
<CardBadge>
{formatMessage({ id: getTrad('settings.section.audio.label'), defaultMessage: 'Audio' })}
</CardBadge>
</CardBody>
</Card>
<AssetCardBase name={name} {...restProps} variant="Audio">
<CardAsset size={size}>
<AudioPreviewWrapper size={size}>
<AudioPreview url={url} alt={name} />
</AudioPreviewWrapper>
</CardAsset>
</AssetCardBase>
);
};

View File

@ -1,31 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import {
Card,
CardAction,
CardBadge,
CardBody,
CardCheckbox,
CardContent,
CardHeader,
CardTitle,
CardSubtitle,
} from '@strapi/design-system/Card';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import FileIcon from '@strapi/icons/File';
import FilePdfIcon from '@strapi/icons/FilePdf';
import Trash from '@strapi/icons/Trash';
import { pxToRem } from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import { getTrad } from '../../utils';
const Extension = styled.span`
text-transform: uppercase;
`;
import { AssetCardBase } from './AssetCardBase';
const IconWrapper = styled.span`
svg {
@ -38,80 +19,28 @@ const CardAsset = styled(Flex)`
background: linear-gradient(180deg, #ffffff 0%, #f6f6f9 121.48%);
`;
export const DocAssetCard = ({ name, extension, selected, onSelect, onEdit, onRemove, size }) => {
const { formatMessage } = useIntl();
export const DocAssetCard = ({ name, extension, size, ...restProps }) => {
return (
<Card height="100%">
<CardHeader>
{onSelect && <CardCheckbox value={selected} onValueChange={onSelect} />}
{(onRemove || onEdit) && (
<CardAction position="end">
{onRemove && (
<IconButton
label={formatMessage({
id: getTrad('control-card.remove-selection'),
defaultMessage: 'Remove from selection',
})}
icon={<Trash />}
onClick={onRemove}
/>
)}
{onEdit && (
<IconButton
label={formatMessage({ id: getTrad('control-card.edit'), defaultMessage: 'Edit' })}
icon={<Pencil />}
onClick={onEdit}
/>
)}
</CardAction>
)}
<CardAsset
width="100%"
height={size === 'S' ? pxToRem(88) : pxToRem(164)}
justifyContent="center"
>
<IconWrapper>
{extension === 'pdf' ? (
<FilePdfIcon aria-label={name} />
) : (
<FileIcon aria-label={name} />
)}
</IconWrapper>
</CardAsset>
</CardHeader>
<CardBody>
<CardContent>
<Box paddingTop={1}>
<CardTitle as="h2">{name}</CardTitle>
</Box>
<CardSubtitle>
<Extension>{extension}</Extension>
</CardSubtitle>
</CardContent>
<CardBadge>
{formatMessage({ id: getTrad('settings.section.doc.label'), defaultMessage: 'Doc' })}
</CardBadge>
</CardBody>
</Card>
<AssetCardBase name={name} extension={extension} {...restProps} variant="Doc">
<CardAsset
width="100%"
height={size === 'S' ? pxToRem(88) : pxToRem(164)}
justifyContent="center"
>
<IconWrapper>
{extension === 'pdf' ? <FilePdfIcon aria-label={name} /> : <FileIcon aria-label={name} />}
</IconWrapper>
</CardAsset>
</AssetCardBase>
);
};
DocAssetCard.defaultProps = {
selected: false,
onEdit: undefined,
onSelect: undefined,
onRemove: undefined,
size: 'M',
};
DocAssetCard.propTypes = {
extension: PropTypes.string.isRequired,
...AssetCardBase.propTypes,
name: PropTypes.string.isRequired,
onEdit: PropTypes.func,
onRemove: PropTypes.func,
onSelect: PropTypes.func,
selected: PropTypes.bool,
size: PropTypes.oneOf(['S', 'M']),
};

View File

@ -1,92 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Box } from '@strapi/design-system/Box';
import {
Card,
CardAction,
CardAsset,
CardBadge,
CardBody,
CardCheckbox,
CardContent,
CardHeader,
CardTitle,
CardSubtitle,
} from '@strapi/design-system/Card';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import { useIntl } from 'react-intl';
import { getTrad } from '../../utils';
import { CardAsset } from '@strapi/design-system/Card';
const Extension = styled.span`
text-transform: uppercase;
`;
export const ImageAssetCard = ({
name,
extension,
height,
width,
thumbnail,
selected,
onSelect,
onEdit,
onRemove,
size,
alt,
}) => {
const { formatMessage } = useIntl();
import { AssetCardBase } from './AssetCardBase';
export const ImageAssetCard = ({ height, width, thumbnail, size, alt, ...props }) => {
// Prevents the browser from caching the URL for all sizes and allow react-query to make a smooth update
// instead of a full refresh
const optimizedCachingThumbnail =
width && height ? `${thumbnail}?width=${width}&height=${height}` : thumbnail;
return (
<Card height="100%">
<CardHeader>
{onSelect && <CardCheckbox value={selected} onValueChange={onSelect} />}
{(onRemove || onEdit) && (
<CardAction position="end">
{onRemove && (
<IconButton
label={formatMessage({
id: getTrad('control-card.remove-selection'),
defaultMessage: 'Remove from selection',
})}
icon={<Trash />}
onClick={onRemove}
/>
)}
{onEdit && (
<IconButton
label={formatMessage({ id: getTrad('control-card.edit'), defaultMessage: 'Edit' })}
icon={<Pencil />}
onClick={onEdit}
/>
)}
</CardAction>
)}
<CardAsset src={optimizedCachingThumbnail} size={size} alt={alt} />
</CardHeader>
<CardBody>
<CardContent>
<Box paddingTop={1}>
<CardTitle as="h2">{name}</CardTitle>
</Box>
<CardSubtitle>
<Extension>{extension}</Extension>
{height && width && ` - ${width}${height}`}
</CardSubtitle>
</CardContent>
<CardBadge>
{formatMessage({ id: getTrad('settings.section.image.label'), defaultMessage: 'Image' })}
</CardBadge>
</CardBody>
</Card>
<AssetCardBase {...props} subtitle={height && width && ` - ${width}${height}`} variant="Image">
<CardAsset src={optimizedCachingThumbnail} size={size} alt={alt} />
</AssetCardBase>
);
};

View File

@ -1,30 +1,13 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import {
Card,
CardAction,
CardAsset,
CardBadge,
CardBody,
CardCheckbox,
CardContent,
CardHeader,
CardTitle,
CardSubtitle,
CardTimer,
} from '@strapi/design-system/Card';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import { useIntl } from 'react-intl';
import { CardAsset, CardTimer } from '@strapi/design-system/Card';
import { Box } from '@strapi/design-system/Box';
import { VideoPreview } from './VideoPreview';
import { getTrad, formatDuration } from '../../utils';
const Extension = styled.span`
text-transform: uppercase;
`;
import { VideoPreview } from './VideoPreview';
import { AssetCardBase } from './AssetCardBase';
import { formatDuration } from '../../utils';
const VideoPreviewWrapper = styled(Box)`
canvas,
@ -35,69 +18,20 @@ const VideoPreviewWrapper = styled(Box)`
}
`;
export const VideoAssetCard = ({
name,
extension,
url,
mime,
selected,
onSelect,
onEdit,
onRemove,
size,
}) => {
const { formatMessage } = useIntl();
export const VideoAssetCard = ({ name, url, mime, size, ...props }) => {
const [duration, setDuration] = useState();
const formattedDuration = duration && formatDuration(duration);
return (
<Card height="100%">
<CardHeader>
{onSelect && <CardCheckbox value={selected} onValueChange={onSelect} />}
{(onRemove || onEdit) && (
<CardAction position="end">
{onRemove && (
<IconButton
label={formatMessage({
id: getTrad('control-card.remove-selection'),
defaultMessage: 'Remove from selection',
})}
icon={<Trash />}
onClick={onRemove}
/>
)}
{onEdit && (
<IconButton
label={formatMessage({ id: getTrad('control-card.edit'), defaultMessage: 'Edit' })}
icon={<Pencil />}
onClick={onEdit}
/>
)}
</CardAction>
)}
<CardAsset size={size}>
<VideoPreviewWrapper size={size}>
<VideoPreview url={url} mime={mime} onLoadDuration={setDuration} alt={name} />
</VideoPreviewWrapper>
</CardAsset>
<CardTimer>{formattedDuration || '...'}</CardTimer>
</CardHeader>
<CardBody>
<CardContent>
<Box paddingTop={1}>
<CardTitle as="h2">{name}</CardTitle>
</Box>
<CardSubtitle>
<Extension>{extension}</Extension>
</CardSubtitle>
</CardContent>
<CardBadge>
{formatMessage({ id: getTrad('settings.section.video.label'), defaultMessage: 'Video' })}
</CardBadge>
</CardBody>
</Card>
<AssetCardBase {...props} variant="Video">
<CardAsset size={size}>
<VideoPreviewWrapper size={size}>
<VideoPreview url={url} mime={mime} onLoadDuration={setDuration} alt={name} />
</VideoPreviewWrapper>
</CardAsset>
<CardTimer>{formattedDuration || '...'}</CardTimer>
</AssetCardBase>
);
};