Skip to content

Commit

Permalink
add: 공용 아이콘 컴포넌트 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-yn committed Nov 28, 2023
1 parent 8fbcd66 commit fcfab6c
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 32 deletions.
68 changes: 57 additions & 11 deletions src/components/storybook/IconBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import React from 'react';
import Grid from '@/composable/Grid/Grid';
import CommonIcon from '@/composable/Icon/CommonIcon';
import SocialIcon from '@/composable/Icon/SocialIcon';
import Text from '@/composable/Text/Text';
import { backgroundColorVariants } from '@/styles/color.css';
import { globalThemeVars } from '@/styles/theme.css';

const IconBoard = () => {
const gridStyle = {
width: 'fit-content',
justifyItems: 'center',
alignItems: 'center',
rowGap: '1rem',
columnGap: '2rem',
margin: '1rem 0',
padding: '1.5rem',
borderRadius: '1rem',
};

return (
<>
<Text
Expand All @@ -16,9 +28,18 @@ const IconBoard = () => {
color: globalThemeVars.color['gray-scale-04'],
}}
>
Skill Icons
Common Icons
</Text>

<Grid
className={backgroundColorVariants['gray-scale-01']}
autoFlow="column"
templateColumns="repeat(7, 2rem)"
style={gridStyle}
>
<IconBoard.Common />
</Grid>

<Text
as="h1"
typoToken="display-m-bold"
Expand All @@ -34,16 +55,7 @@ const IconBoard = () => {
autoFlow="column"
templateColumns="repeat(16, 2rem)"
templateRows="repeat(19, 2rem)"
style={{
width: 'fit-content',
justifyItems: 'center',
alignItems: 'center',
rowGap: '1rem',
columnGap: '2rem',
margin: '1rem 0',
padding: '1.5rem',
borderRadius: '1rem',
}}
style={gridStyle}
>
<IconBoard.Social company="GOOGLE" />
<IconBoard.Social company="FACEBOOK" />
Expand Down Expand Up @@ -217,6 +229,40 @@ const Social = ({ company, format }: SocialProps) => {
);
};

interface CommonProps {
format?: 'png' | 'svg';
}

const Common = ({ format }: CommonProps) => {
return (
<>
<CommonIcon variant="DOWN_ARROW" width={32} height={32} format={format} />
<CommonIcon variant="HAMBURGER" width={32} height={32} format={format} />
<CommonIcon
variant="LARGE_CLOSE"
width={32}
height={32}
format={format}
/>
<CommonIcon variant="LEFT_ARROW" width={32} height={32} format={format} />
<CommonIcon
variant="NORMAL_CLOSE"
width={32}
height={32}
format={format}
/>
<CommonIcon
variant="ROUND_CLOSE"
width={32}
height={32}
format={format}
/>
<CommonIcon variant="UP_ARROW" width={32} height={32} format={format} />
</>
);
};

IconBoard.Social = Social;
IconBoard.Common = Common;

export default IconBoard;
11 changes: 11 additions & 0 deletions src/composable/Icon/CommonIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Image from 'next/image';
import React from 'react';
import iconAssetEndpoint from '@/utils/string/iconAssetEndpoint';

const CommonIcon = ({ variant, format, ...props }: CommonIconProps) => {
const path = iconAssetEndpoint(variant);

return <Image {...props} src={`${path}.${format || 'png'}`} alt={variant} />;
};

export default CommonIcon;
31 changes: 30 additions & 1 deletion src/composable/Icon/Icon.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,43 @@ import { render } from '@testing-library/react';
import {
iconBackgroundTokens,
iconColorTokens,
iconCommonTokens,
iconCompanyTokens,
iconStateTokens,
} from '@/mock/iconTokens.mock';
import { randomIndex, randomBetweenNumber } from '@/utils/number/random';
import capitalizeFirstLetter from '@/utils/string/capitalizeFirstLetter';
import CommonIcon from './CommonIcon';
import SocialIcon from './SocialIcon';

describe('Icon 컴포넌트', () => {
describe('Icon 컴포넌트들', () => {
describe('1. CommonIcon 컴포넌트들', () => {
test('1. Image 컴포넌트가 정확한 props로 렌더링 되는가?', () => {
const testProps = {
variant: iconCommonTokens[randomIndex(iconCommonTokens)],
size: randomBetweenNumber(0, 200),
};

const { getByRole } = render(
<CommonIcon
variant={testProps.variant}
width={testProps.size}
height={testProps.size}
/>,
);
const image = getByRole('img');

expect(image).toHaveAttribute('width', testProps.size.toString());
expect(image).toHaveAttribute('height', testProps.size.toString());
expect(image).toHaveAttribute('alt', testProps.variant);

expect(image).toHaveAttribute(
'src',
expect.stringContaining(`${testProps.variant.toLowerCase()}`),
);
});
});

test('1. Image 컴포넌트가 정확한 props로 렌더링 되는가?', () => {
const testProps = {
company: iconCompanyTokens[randomIndex(iconCompanyTokens)],
Expand Down
18 changes: 6 additions & 12 deletions src/composable/Icon/SocialIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import Image, { ImageProps } from 'next/image';
import { ASSET_ENDPOINT } from '@/const/endpoint';
import iconResourceSrcFormat from '@/utils/string/iconResourceSrcFormat';

type ModifiedImageProps = Omit<ImageProps, 'src' | 'alt'>;
type SocialProps = ODSIconTokenInterface &
ModifiedImageProps & {
format?: 'png' | 'svg';
};
import Image from 'next/image';
import iconAssetEndpoint from '@/utils/string/iconAssetEndpoint';
import socialIconResourceSrcFormat from '@/utils/string/socialIconResourceSrcFormat';

const SocialIcon = ({
company,
Expand All @@ -15,15 +9,15 @@ const SocialIcon = ({
state,
format,
...props
}: SocialProps) => {
const resource = iconResourceSrcFormat({
}: SocialIconProps) => {
const resource = socialIconResourceSrcFormat({
company,
color,
background,
state,
});

const path = `${ASSET_ENDPOINT}/icons/${company.toLowerCase()}`;
const path = iconAssetEndpoint(company);

return (
<Image
Expand Down
9 changes: 9 additions & 0 deletions src/mock/iconTokens.mock.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
export const iconCommonTokens: CommonIconToken[] = [
'DOWN_ARROW',
'HAMBURGER',
'LARGE_CLOSE',
'NORMAL_CLOSE',
'ROUND_CLOSE',
'UP_ARROW',
];

export const iconCompanyTokens: CompanyIconToken[] = [
'GOOGLE',
'FACEBOOK',
Expand Down
10 changes: 9 additions & 1 deletion src/types/designToken.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ type ODSTextToken =
| ParagraphSTextToken
| CaptionTextToken;

type CommonIconToken =
| 'HAMBURGER'
| 'DOWN_ARROW'
| 'UP_ARROW'
| 'LEFT_ARROW'
| 'ROUND_CLOSE'
| 'NORMAL_CLOSE'
| 'LARGE_CLOSE';

type CompanyIconToken =
| 'GOOGLE'
| 'FACEBOOK'
Expand All @@ -142,7 +151,6 @@ type BackgroundIconToken = 'NONE' | 'CIRCULAR' | 'RECTANGLAR';
type StateIconToken = 'DEFAULT' | 'HOVER';

interface ODSIconTokenInterface {
company: CompanyIconToken;
color: ColorIconToken;
background: BackgroundIconToken;
state: StateIconToken;
Expand Down
15 changes: 15 additions & 0 deletions src/types/props/Icon.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ImageProps } from 'next/image';

declare global {
type ModifiedImageProps = Omit<ImageProps, 'src' | 'alt'>;
type IconProps = ModifiedImageProps & {
format?: 'png' | 'svg';
};
type CommonIconProps = IconProps & {
variant: CommonIconToken;
};
type SocialIconProps = ODSIconTokenInterface &
IconProps & {
company: CompanyIconToken;
};
}
7 changes: 7 additions & 0 deletions src/utils/string/iconAssetEndpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ASSET_ENDPOINT } from '@/const/endpoint';

const iconAssetEndpoint = (iconName: string) => {
return `${ASSET_ENDPOINT}/icons/${iconName.toLowerCase()}`;
};

export default iconAssetEndpoint;
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import capitalizeFirstLetter from './capitalizeFirstLetter';

const iconResourceSrcFormat = ({
const socialIconResourceSrcFormat = ({
company,
color,
background,
state,
}: ODSIconTokenInterface) => {
}: SocialIconProps) => {
return encodeURIComponent(
`Company=${capitalizeFirstLetter(company)}, Color=${capitalizeFirstLetter(
color,
Expand All @@ -15,4 +15,4 @@ const iconResourceSrcFormat = ({
);
};

export default iconResourceSrcFormat;
export default socialIconResourceSrcFormat;
8 changes: 4 additions & 4 deletions src/utils/string/string.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import capitalizeFirstLetter from './capitalizeFirstLetter';
import iconResourceSrcFormat from './iconResourceSrcFormat';
import replaceAll from './replaceAll';
import socialIconResourceSrcFormat from './socialIconResourceSrcFormat';

describe('string', () => {
describe('capitalizeFirstLetter', () => {
Expand Down Expand Up @@ -103,9 +103,9 @@ describe('string', () => {
});
});

describe('iconResourceSrcFormat', () => {
describe('socialIconResourceSrcFormat', () => {
it('should format the icon resource source correctly', () => {
const mockIconToken: ODSIconTokenInterface = {
const mockIconToken: SocialIconProps = {
company: 'GOOGLE',
color: 'BRAND',
background: 'CIRCULAR',
Expand All @@ -116,7 +116,7 @@ describe('string', () => {
'Company=Google, Color=Brand, Background=Circular, State=Hover',
);

const result = iconResourceSrcFormat(mockIconToken);
const result = socialIconResourceSrcFormat(mockIconToken);
expect(result).toBe(expectedOutput);
});

Expand Down

0 comments on commit fcfab6c

Please sign in to comment.