Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add icon picker to components and show component's icons #16703

Merged
merged 21 commits into from Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
94cb61d
add IconPicker field to components
Feranchz May 11, 2023
3dba194
add component icons on content type builders dynamic zones
Feranchz May 11, 2023
09febe2
add component's icon back to the content manager
Feranchz May 11, 2023
1444c3e
Fix bug on searchIcon on components icons picker and add remove icon btn
Feranchz May 12, 2023
8e57bfd
update component card tests and update snapshots
Feranchz May 12, 2023
0e2454a
not use a popover on icon picker searchbar
Feranchz May 12, 2023
cf28b91
fix problems with accesibility on component icons
Feranchz May 17, 2023
d14a097
fix lint errors
Feranchz May 17, 2023
86e071b
make a map between DS icons and component icons
Feranchz May 18, 2023
b3f1896
move components' icons to a constants file and other improves
Feranchz May 19, 2023
63cef20
improves on dynamic zone component list on content type builder
Feranchz May 22, 2023
f6c4422
improves and small fixes on component icons
Feranchz May 24, 2023
8647512
icons regex
Feranchz May 24, 2023
4f87df7
remove brand icons
Feranchz May 24, 2023
b14a181
Update packages/core/admin/admin/src/content-manager/pages/EditSettin…
Feranchz May 24, 2023
633fcd2
add more space between icons searchbar and icon picker
Feranchz May 24, 2023
9ae4140
fix regex problem
Feranchz May 24, 2023
0439cfe
fix icon names on tests
Feranchz May 25, 2023
affd0c0
allow old icon names on the regex
Feranchz May 26, 2023
7eb0b9d
edit icon validation error with a more readable message
Feranchz May 31, 2023
420f300
snaps fix
Feranchz Jun 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions api-tests/core/content-type-builder/components.test.api.js
Expand Up @@ -68,6 +68,7 @@ describe('Content Type Builder - Components', () => {
component: {
category: 'default',
displayName: 'Some Component',
icon: 'calendar',
pluginOptions: {
pluginName: {
option: true,
Expand Down Expand Up @@ -107,6 +108,7 @@ describe('Content Type Builder - Components', () => {
body: {
component: {
category: 'default',
icon: 'calendar',
displayName: 'someComponent',
attributes: {},
},
Expand Down Expand Up @@ -172,6 +174,7 @@ describe('Content Type Builder - Components', () => {
category: 'default',
schema: {
displayName: 'Some Component',
icon: 'calendar',
description: '',
collectionName: 'components_default_some_components',
pluginOptions: {
Expand Down Expand Up @@ -254,6 +257,7 @@ describe('Content Type Builder - Components', () => {
body: {
component: {
category: 'default',
icon: 'calendar',
displayName: 'New Component',
attributes: {
name: {
Expand Down
@@ -1,49 +1,39 @@
import PropTypes from 'prop-types';
import React from 'react';
import styled from 'styled-components';

import { Flex } from '@strapi/design-system';
import { Flex, Icon } from '@strapi/design-system';
import { COMPONENT_ICONS } from './constants';

const WIDTH_S = 5;
const WIDTH_M = 8;

const Wrapper = styled(Flex)`
border-radius: ${({ showBackground }) => (showBackground ? `50%` : 0)};
color: ${({ theme }) => theme.colors.neutral600};
height: ${({ theme, size }) => theme.spaces[size === 'S' ? WIDTH_S : WIDTH_M]};
width: ${({ theme, size }) => theme.spaces[size === 'S' ? WIDTH_S : WIDTH_M]};

svg {
height: ${({ theme, size }) => theme.spaces[size === 'S' ? WIDTH_S - 2 : WIDTH_M - 3]};
width: ${({ theme, size }) => theme.spaces[size === 'S' ? WIDTH_S - 2 : WIDTH_M - 3]};
}
`;

export function ComponentIcon({ showBackground = true, size = 'M' }) {
export function ComponentIcon({ showBackground = true, size = 'M', icon }) {
return (
<Wrapper
<Flex
alignItems="center"
background={showBackground ? 'neutral200' : null}
justifyContent="center"
size={size}
showBackground={showBackground}
height={size === 'S' ? 5 : 8}
width={size === 'S' ? 5 : 8}
color="neutral600"
borderRadius={showBackground ? '50%' : 0}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M216.3 2c4.8-2.6 10.5-2.6 15.3 0L422.3 106c5.1 2.8 8.3 8.2 8.3 14s-3.2 11.2-8.3 14L231.7 238c-4.8 2.6-10.5 2.6-15.3 0L25.7 134c-5.1-2.8-8.3-8.2-8.3-14s3.2-11.2 8.3-14L216.3 2zM23.7 170l176 96c5.1 2.8 8.3 8.2 8.3 14V496c0 5.6-3 10.9-7.8 13.8s-10.9 3-15.8 .3L8.3 414C3.2 411.2 0 405.9 0 400V184c0-5.6 3-10.9 7.8-13.8s10.9-3 15.8-.3zm400.7 0c5-2.7 11-2.6 15.8 .3s7.8 8.1 7.8 13.8V400c0 5.9-3.2 11.2-8.3 14l-176 96c-5 2.7-11 2.6-15.8-.3s-7.8-8.1-7.8-13.8V280c0-5.9 3.2-11.2 8.3-14l176-96z"
fill="currentColor"
/>
</svg>
</Wrapper>
<Icon
as={COMPONENT_ICONS[icon] || COMPONENT_ICONS.cube}
height={size === 'S' ? 3 : 5}
width={size === 'S' ? 3 : 5}
/>
</Flex>
);
}

ComponentIcon.defaultProps = {
showBackground: true,
size: 'M',
icon: 'Cube',
};

ComponentIcon.propTypes = {
showBackground: PropTypes.bool,
size: PropTypes.string,
icon: PropTypes.string,
};
@@ -0,0 +1,133 @@
import * as Icons from '@strapi/icons';

const COMPONENT_ICONS = {
alien: Icons.Alien,
apps: Icons.Apps,
archive: Icons.Archive,
arrowDown: Icons.ArrowDown,
arrowLeft: Icons.ArrowLeft,
arrowRight: Icons.ArrowRight,
arrowUp: Icons.ArrowUp,
attachment: Icons.Attachment,
bell: Icons.Bell,
bold: Icons.Bold,
book: Icons.Book,
briefcase: Icons.Briefcase,
brush: Icons.Brush,
bulletList: Icons.BulletList,
calendar: Icons.Calendar,
car: Icons.Car,
cast: Icons.Cast,
chartBubble: Icons.ChartBubble,
chartCircle: Icons.ChartCircle,
chartPie: Icons.ChartPie,
check: Icons.Check,
clock: Icons.Clock,
cloud: Icons.Cloud,
code: Icons.Code,
cog: Icons.Cog,
collapse: Icons.Collapse,
command: Icons.Command,
connector: Icons.Connector,
crop: Icons.Crop,
crown: Icons.Crown,
cube: Icons.Cube,
cup: Icons.Cup,
cursor: Icons.Cursor,
dashboard: Icons.Dashboard,
database: Icons.Database,
discuss: Icons.Discuss,
doctor: Icons.Doctor,
earth: Icons.Earth,
emotionHappy: Icons.EmotionHappy,
emotionUnhappy: Icons.EmotionUnhappy,
envelop: Icons.Envelop,
exit: Icons.Exit,
expand: Icons.Expand,
eye: Icons.Eye,
feather: Icons.Feather,
file: Icons.File,
fileError: Icons.FileError,
filePdf: Icons.FilePdf,
filter: Icons.Filter,
folder: Icons.Folder,
gate: Icons.Gate,
gift: Icons.Gift,
globe: Icons.Globe,
grid: Icons.Grid,
handHeart: Icons.HandHeart,
hashtag: Icons.Hashtag,
headphone: Icons.Headphone,
heart: Icons.Heart,
house: Icons.House,
information: Icons.Information,
italic: Icons.Italic,
key: Icons.Key,
landscape: Icons.Landscape,
layer: Icons.Layer,
layout: Icons.Layout,
lightbulb: Icons.Lightbulb,
link: Icons.Link,
lock: Icons.Lock,
magic: Icons.Magic,
manyToMany: Icons.ManyToMany,
manyToOne: Icons.ManyToOne,
manyWays: Icons.ManyWays,
medium: Icons.Medium,
message: Icons.Message,
microphone: Icons.Microphone,
monitor: Icons.Monitor,
moon: Icons.Moon,
music: Icons.Music,
oneToMany: Icons.OneToMany,
oneToOne: Icons.OneToOne,
oneWay: Icons.OneWay,
paint: Icons.Paint,
paintBrush: Icons.PaintBrush,
paperPlane: Icons.PaperPlane,
pencil: Icons.Pencil,
phone: Icons.Phone,
picture: Icons.Picture,
pin: Icons.Pin,
pinMap: Icons.PinMap,
plane: Icons.Plane,
play: Icons.Play,
plus: Icons.Plus,
priceTag: Icons.PriceTag,
puzzle: Icons.Puzzle,
question: Icons.Question,
quote: Icons.Quote,
refresh: Icons.Refresh,
repeat: Icons.Repeat,
restaurant: Icons.Restaurant,
rocket: Icons.Rocket,
rotate: Icons.Rotate,
scissors: Icons.Scissors,
search: Icons.Search,
seed: Icons.Seed,
server: Icons.Server,
shield: Icons.Shield,
shirt: Icons.Shirt,
shoppingCart: Icons.ShoppingCart,
slideshow: Icons.Slideshow,
stack: Icons.Stack,
star: Icons.Star,
store: Icons.Store,
strikeThrough: Icons.StrikeThrough,
sun: Icons.Sun,
television: Icons.Television,
thumbDown: Icons.ThumbDown,
thumbUp: Icons.ThumbUp,
train: Icons.Train,
twitter: Icons.Twitter,
typhoon: Icons.Typhoon,
underline: Icons.Underline,
user: Icons.User,
volumeMute: Icons.VolumeMute,
volumeUp: Icons.VolumeUp,
walk: Icons.Walk,
wheelchair: Icons.Wheelchair,
write: Icons.Write,
};

export { COMPONENT_ICONS };
@@ -0,0 +1,72 @@
/**
*
* ComponentCard
*
*/

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { Box, Typography, Flex } from '@strapi/design-system';
import { pxToRem } from '@strapi/helper-plugin';

import { ComponentIcon } from '../../ComponentIcon';

const ComponentBox = styled(Box)`
flex-shrink: 0;
height: ${pxToRem(84)};
border: 1px solid ${({ theme }) => theme.colors.neutral200};
background: ${({ theme }) => theme.colors.neutral100};
border-radius: ${({ theme }) => theme.borderRadius};
display: flex;
justify-content: center;
align-items: center;

&:focus,
&:hover {
border: 1px solid ${({ theme }) => theme.colors.primary200};
background: ${({ theme }) => theme.colors.primary100};

${Typography} {
color: ${({ theme }) => theme.colors.primary600};
}

/* > Flex > ComponentIcon */
> div > div:first-child {
background: ${({ theme }) => theme.colors.primary200};
color: ${({ theme }) => theme.colors.primary600};

svg {
path {
fill: ${({ theme }) => theme.colors.primary600};
}
}
}
}
`;

export default function ComponentCard({ children, onClick, icon }) {
return (
<ComponentBox as="button" type="button" onClick={onClick} hasRadius>
<Flex direction="column" gap={1} alignItems="center" justifyContent="center">
<ComponentIcon icon={icon} />

<Typography variant="pi" fontWeight="bold" textColor="neutral600">
{children}
</Typography>
</Flex>
</ComponentBox>
);
}

ComponentCard.defaultProps = {
onClick() {},
icon: 'Cube',
};

ComponentCard.propTypes = {
children: PropTypes.node.isRequired,
onClick: PropTypes.func,
icon: PropTypes.string,
};
Expand Up @@ -38,7 +38,7 @@ export const ComponentCategory = ({
<AccordionContent>
<Box paddingTop={4} paddingBottom={4} paddingLeft={3} paddingRight={3}>
<Grid>
{components.map(({ componentUid, info: { displayName } }) => (
{components.map(({ componentUid, info: { displayName, icon } }) => (
<ComponentBox
key={componentUid}
as="button"
Expand All @@ -52,7 +52,7 @@ export const ComponentCategory = ({
borderColor="neutral200"
>
<Flex direction="column" gap={1} alignItems="center" justifyContent="center">
<ComponentIcon />
<ComponentIcon icon={icon} />

<Typography variant="pi" fontWeight="bold" textColor="neutral600">
{formatMessage({ id: displayName, defaultMessage: displayName })}
Expand Down
Expand Up @@ -22,6 +22,7 @@ import { useContentTypeLayout, useDragAndDrop } from '../../../hooks';
import { composeRefs, getTrad, ItemTypes } from '../../../utils';

import FieldComponent from '../../FieldComponent';
import { ComponentIcon } from '../../ComponentIcon';

export const DynamicComponent = ({
componentUid,
Expand Down Expand Up @@ -206,6 +207,7 @@ export const DynamicComponent = ({
) : (
<Accordion expanded={isOpen} onToggle={handleToggle} size="S" error={errorMessage}>
<AccordionToggle
startIcon={<ComponentIcon icon={icon} showBackground={false} size="S" />}
action={accordionActions}
title={`${friendlyName}${mainValue}`}
togglePosition="left"
Expand Down
@@ -0,0 +1,25 @@
import React from 'react';
import { fireEvent, render } from '@testing-library/react';

import { ThemeProvider, lightTheme } from '@strapi/design-system';

import GlobalStyle from '../../../../../components/GlobalStyle';

import ComponentCard from '../ComponentCard';

describe('ComponentCard', () => {
const setup = (props) =>
render(
<ThemeProvider theme={lightTheme}>
<ComponentCard {...props}>test</ComponentCard>
<GlobalStyle />
</ThemeProvider>
);

it('should call the onClick handler when passed', () => {
const onClick = jest.fn();
const { getByText } = setup({ onClick });
fireEvent.click(getByText('test'));
expect(onClick).toHaveBeenCalled();
});
});
Expand Up @@ -25,13 +25,20 @@ const CustomLink = styled(Flex)`
> div:first-child {
background: ${({ theme }) => theme.colors.primary200};
color: ${({ theme }) => theme.colors.primary600};

svg {
path {
fill: ${({ theme }) => theme.colors.primary600};
}
}
}
}
`;

const DynamicZoneList = ({ components }) => {
const { componentLayouts } = useLayoutDnd();


return (
<Flex gap={2} overflow="scroll hidden" padding={3}>
{components.map((componentUid) => (
Expand All @@ -49,7 +56,7 @@ const DynamicZoneList = ({ components }) => {
as={Link}
to={`/content-manager/components/${componentUid}/configurations/edit`}
>
<ComponentIcon />
<ComponentIcon icon={componentLayouts?.[componentUid]?.info?.icon} />

<Box paddingTop={1}>
<Typography fontSize={1} textColor="neutral600" fontWeight="bold">
Expand Down