From 837e0e904c40f7b87561c34ca3f49edd5d8d1c52 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 28 Sep 2023 18:03:43 +0200 Subject: feat(components): replace icons with a generic Icon component Sizes are also predefined and can be set using the `size` prop, so the consumers should no longer adjust the size in CSS. --- .../hamburger-icon/hamburger-icon.module.scss | 45 +++++ .../images/icons/hamburger-icon/hamburger-icon.tsx | 25 +++ .../atoms/images/icons/hamburger-icon/index.ts | 1 + src/components/atoms/images/icons/icon.module.scss | 53 ++++++ src/components/atoms/images/icons/icon.stories.tsx | 201 +++++++++++++++++++++ src/components/atoms/images/icons/icon.test.tsx | 182 +++++++++++++++++++ src/components/atoms/images/icons/icon.tsx | 126 +++++++++++++ src/components/atoms/images/icons/index.ts | 1 + .../atoms/images/icons/plus-minus-icon/index.ts | 1 + .../plus-minus-icon/plus-minus-icon.module.scss | 38 ++++ .../icons/plus-minus-icon/plus-minus-icon.tsx | 30 +++ .../svg-paths/icons-paths/arrow-icon-paths.tsx | 51 ++++++ .../icons-paths/career-icon-paths.module.scss | 43 +++++ .../svg-paths/icons-paths/career-icon-paths.tsx | 57 ++++++ .../svg-paths/icons-paths/cc-by-sa-icon-paths.tsx | 20 ++ .../icons/svg-paths/icons-paths/cog-icon-paths.tsx | 14 ++ .../icons-paths/computer-icon-paths.module.scss | 37 ++++ .../svg-paths/icons-paths/computer-icon-paths.tsx | 65 +++++++ .../icons-paths/cross-icon-paths.module.scss | 5 + .../svg-paths/icons-paths/cross-icon-paths.tsx | 21 +++ .../icons-paths/envelop-icon-paths.module.scss | 22 +++ .../svg-paths/icons-paths/envelop-icon-paths.tsx | 53 ++++++ .../svg-paths/icons-paths/feed-icon-paths.tsx | 59 ++++++ .../icons-paths/home-icon-paths.module.scss | 25 +++ .../svg-paths/icons-paths/home-icon-paths.tsx | 41 +++++ .../images/icons/svg-paths/icons-paths/index.ts | 13 ++ .../magnifying-glass-icon-paths.module.scss | 20 ++ .../icons-paths/magnifying-glass-icon-paths.tsx | 29 +++ .../svg-paths/icons-paths/moon-icon-paths.tsx | 11 ++ .../icons-paths/posts-stack-icon-paths.module.scss | 21 +++ .../icons-paths/posts-stack-icon-paths.tsx | 49 +++++ .../icons/svg-paths/icons-paths/sun-icon-paths.tsx | 11 ++ .../atoms/images/icons/svg-paths/index.ts | 1 + .../atoms/images/icons/svg-paths/svg-paths.tsx | 82 +++++++++ src/components/atoms/images/index.ts | 1 + 35 files changed, 1454 insertions(+) create mode 100644 src/components/atoms/images/icons/hamburger-icon/hamburger-icon.module.scss create mode 100644 src/components/atoms/images/icons/hamburger-icon/hamburger-icon.tsx create mode 100644 src/components/atoms/images/icons/hamburger-icon/index.ts create mode 100644 src/components/atoms/images/icons/icon.module.scss create mode 100644 src/components/atoms/images/icons/icon.stories.tsx create mode 100644 src/components/atoms/images/icons/icon.test.tsx create mode 100644 src/components/atoms/images/icons/icon.tsx create mode 100644 src/components/atoms/images/icons/index.ts create mode 100644 src/components/atoms/images/icons/plus-minus-icon/index.ts create mode 100644 src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.module.scss create mode 100644 src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/arrow-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/cc-by-sa-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/cog-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/feed-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/index.ts create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/moon-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.module.scss create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/icons-paths/sun-icon-paths.tsx create mode 100644 src/components/atoms/images/icons/svg-paths/index.ts create mode 100644 src/components/atoms/images/icons/svg-paths/svg-paths.tsx (limited to 'src/components/atoms/images') diff --git a/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.module.scss b/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.module.scss new file mode 100644 index 0000000..8b8ad7e --- /dev/null +++ b/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.module.scss @@ -0,0 +1,45 @@ +@use "../../../../../styles/abstracts/functions" as fun; + +.wrapper { + display: flex; + align-items: center; + aspect-ratio: 1/1; + position: relative; +} + +.icon { + width: 100%; + + &, + &::before, + &::after { + display: block; + height: 20%; + background: var(--color-primary-lighter); + background-image: linear-gradient( + to right, + var(--color-primary-light) 0%, + var(--color-primary-lighter) 100% + ); + border: fun.convert-px(1) solid var(--color-primary-darker); + border-radius: fun.convert-px(4); + transition: + all 0.25s ease-in-out 0s, + transform 0.4s ease-in 0s; + } + + &::before, + &::after { + content: ""; + position: absolute; + inset-inline: 0; + } + + &::before { + top: 3%; + } + + &::after { + bottom: 3%; + } +} diff --git a/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.tsx b/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.tsx new file mode 100644 index 0000000..edd25ba --- /dev/null +++ b/src/components/atoms/images/icons/hamburger-icon/hamburger-icon.tsx @@ -0,0 +1,25 @@ +import type { FC, HTMLAttributes } from 'react'; +import styles from './hamburger-icon.module.scss'; + +export type HamburgerIconProps = Omit< + HTMLAttributes, + 'children' +>; + +/** + * HamburgerIcon component + * + * Render a Hamburger icon. + */ +export const HamburgerIcon: FC = ({ + className = '', + ...props +}) => { + const wrapperClass = `${styles.wrapper} ${className}`; + + return ( + + + + ); +}; diff --git a/src/components/atoms/images/icons/hamburger-icon/index.ts b/src/components/atoms/images/icons/hamburger-icon/index.ts new file mode 100644 index 0000000..a601d0c --- /dev/null +++ b/src/components/atoms/images/icons/hamburger-icon/index.ts @@ -0,0 +1 @@ +export * from './hamburger-icon'; diff --git a/src/components/atoms/images/icons/icon.module.scss b/src/components/atoms/images/icons/icon.module.scss new file mode 100644 index 0000000..72eb611 --- /dev/null +++ b/src/components/atoms/images/icons/icon.module.scss @@ -0,0 +1,53 @@ +@use "../../../../styles/abstracts/functions" as fun; + +.icon { + width: var(--icon-size); + transition: all 0.25s ease-in-out 0s; + + &--arrow { + fill: var(--color-primary); + } + + &--cc-by-sa { + width: calc(var(--icon-size) * 2); + fill: var(--color-fg); + } + + &--cog, + &--home, + &--moon, + &--sun { + stroke-width: 4; + } + + &--cog, + &--moon, + &--sun { + fill: var(--color-primary-lighter); + stroke: var(--color-primary-darker); + } + + &--stroke { + stroke: var(--color-primary); + } + + &--xs { + --icon-size: var(--icon-size-xs); + } + + &--sm { + --icon-size: var(--icon-size-sm); + } + + &--md { + --icon-size: var(--icon-size-md); + } + + &--lg { + --icon-size: var(--icon-size-lg); + } + + &--xl { + --icon-size: var(--icon-size-xl); + } +} diff --git a/src/components/atoms/images/icons/icon.stories.tsx b/src/components/atoms/images/icons/icon.stories.tsx new file mode 100644 index 0000000..fa8d2b5 --- /dev/null +++ b/src/components/atoms/images/icons/icon.stories.tsx @@ -0,0 +1,201 @@ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Icon, type IconProps, type IconShape } from './icon'; + +/** + * Home icon - Storybook Meta + */ +export default { + title: 'Atoms/Images/Icons', + component: Icon, + argTypes: { + shape: { + control: { + type: 'select', + }, + options: [ + 'arrow', + 'career', + 'cc-by-sa', + 'cog', + 'computer', + 'cross', + 'envelop', + 'feed', + 'hamburger', + 'home', + 'magnifying-glass', + 'minus', + 'moon', + 'posts-stack', + 'plus', + 'sun', + ], + description: 'Define the icon shape.', + type: { + name: 'string', + required: false, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = ({ + shape, + ...args +}: IconProps) => ; + +/** + * Icon Stories - ArrowRight + */ +export const ArrowRight = Template.bind({}); +ArrowRight.args = { + orientation: 'right', + shape: 'arrow', +}; + +/** + * Icon Stories - ArrowLeft + */ +export const ArrowLeft = Template.bind({}); +ArrowLeft.args = { + orientation: 'left', + shape: 'arrow', +}; + +/** + * Icon Stories - ArrowBottom + */ +export const ArrowBottom = Template.bind({}); +ArrowBottom.args = { + orientation: 'bottom', + shape: 'arrow', +}; + +/** + * Icon Stories - ArrowTop + */ +export const ArrowTop = Template.bind({}); +ArrowTop.args = { + orientation: 'top', + shape: 'arrow', +}; + +/** + * Icon Stories - Career + */ +export const Career = Template.bind({}); +Career.args = { + shape: 'career', +}; + +/** + * Icon Stories - CCBySA + */ +export const CCBySA = Template.bind({}); +CCBySA.args = { + shape: 'cc-by-sa', +}; + +/** + * Icon Stories - Cog + */ +export const Cog = Template.bind({}); +Cog.args = { + shape: 'cog', +}; + +/** + * Icon Stories - Computer + */ +export const Computer = Template.bind({}); +Computer.args = { + shape: 'computer', +}; + +/** + * Icon Stories - Cross + */ +export const Cross = Template.bind({}); +Cross.args = { + shape: 'cross', +}; + +/** + * Icon Stories - Envelop + */ +export const Envelop = Template.bind({}); +Envelop.args = { + shape: 'envelop', +}; + +/** + * Icon Stories - Feed + */ +export const Feed = Template.bind({}); +Feed.args = { + shape: 'feed', +}; + +/** + * Icon Stories - Hamburger + */ +export const Hamburger = Template.bind({}); +Hamburger.args = { + shape: 'hamburger', +}; + +/** + * Icon Stories - Home + */ +export const Home = Template.bind({}); +Home.args = { + shape: 'home', +}; + +/** + * Icon Stories - MagnifyingGlass + */ +export const MagnifyingGlass = Template.bind({}); +MagnifyingGlass.args = { + shape: 'magnifying-glass', +}; + +/** + * Icon Stories - Minus + */ +export const Minus = Template.bind({}); +Minus.args = { + shape: 'minus', +}; + +/** + * Icon Stories - Moon + */ +export const Moon = Template.bind({}); +Moon.args = { + shape: 'moon', +}; + +/** + * Icon Stories - Plus + */ +export const Plus = Template.bind({}); +Plus.args = { + shape: 'plus', +}; + +/** + * Icon Stories - PostsStack + */ +export const PostsStack = Template.bind({}); +PostsStack.args = { + shape: 'posts-stack', +}; + +/** + * Icon Stories - Sun + */ +export const Sun = Template.bind({}); +Sun.args = { + shape: 'sun', +}; diff --git a/src/components/atoms/images/icons/icon.test.tsx b/src/components/atoms/images/icons/icon.test.tsx new file mode 100644 index 0000000..d80edd7 --- /dev/null +++ b/src/components/atoms/images/icons/icon.test.tsx @@ -0,0 +1,182 @@ +/* eslint-disable max-statements */ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { Icon } from './icon'; + +/* eslint-disable jsx-a11y/prefer-tag-over-role -- Valid on SVG */ +describe('Icon', () => { + it('can render an icon with a heading', () => { + const heading = 'architecto'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('can render an icon with a description', () => { + const description = 'fuga voluptates eligendi'; + + render(); + + expect(rtlScreen.getByRole('img')).toHaveTextContent(description); + }); + + it('render an icon with bottom arrow shape', () => { + const heading = 'quae'; + + render( + + ); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with left arrow shape', () => { + const heading = 'nemo'; + + render( + + ); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with right arrow shape', () => { + const heading = 'odit'; + + render( + + ); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with top arrow shape', () => { + const heading = 'ut'; + + render( + + ); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with career shape', () => { + const heading = 'autem'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with cc-by-sa shape', () => { + const heading = 'blanditiis'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with cog shape', () => { + const heading = 'consequatur'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with computer shape', () => { + const heading = 'amet'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with cross shape', () => { + const heading = 'molestias'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with envelop shape', () => { + const heading = 'laudantium'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + it('render an icon with feed shape', () => { + const heading = 'beatae'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with home shape', () => { + const heading = 'aut'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with magnifying glass shape', () => { + const heading = 'rerum'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with moon shape', () => { + const heading = 'saepe'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with posts stack shape', () => { + const heading = 'sunt'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with sun shape', () => { + const heading = 'aut'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with hamburger shape', () => { + const heading = 'sed'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with minus shape', () => { + const heading = 'sunt'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); + + it('render an icon with plus shape', () => { + const heading = 'maxime'; + + render(); + + expect(rtlScreen.getByRole('img', { name: heading })).toBeInTheDocument(); + }); +}); diff --git a/src/components/atoms/images/icons/icon.tsx b/src/components/atoms/images/icons/icon.tsx new file mode 100644 index 0000000..23170d9 --- /dev/null +++ b/src/components/atoms/images/icons/icon.tsx @@ -0,0 +1,126 @@ +import type { SVGAttributes } from 'react'; +import { HamburgerIcon, type HamburgerIconProps } from './hamburger-icon'; +import styles from './icon.module.scss'; +import { + PlusMinusIcon, + type PlusMinusIconProps, + type PlusMinusIconShape, +} from './plus-minus-icon'; +import { type SVGIconShape, SVGPaths, type SVGPathsProps } from './svg-paths'; + +export type IconShape = SVGIconShape | PlusMinusIconShape | 'hamburger'; + +export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; + +type SVGIconProps = Omit< + SVGAttributes, + 'children' | 'viewBox' | 'xmlns' +> & { + /** + * Describe the icon. + */ + description?: string; + /** + * Define an accessible title for the icon. + */ + heading?: string; +}; + +type IconBaseProps = T extends 'hamburger' + ? HamburgerIconProps + : T extends 'minus' | 'plus' + ? PlusMinusIconProps + : SVGIconProps; + +type AdditionalProps = Pick< + SVGPathsProps, + 'orientation' +> & { + /** + * The icon shape. + */ + shape: T; + /** + * The icon size. + * + * @default 'md' + */ + size?: IconSize; +}; + +export type IconProps = IconBaseProps & + Pick & + AdditionalProps; + +type BuildClassNameConfig = Pick< + IconProps, + 'className' +> & + Pick, 'shape' | 'size'>; + +const buildClassName = ({ + className, + shape, + size, +}: BuildClassNameConfig) => { + const classNames = ['icon', `icon--${shape}`, `icon--${size}`].map( + (key) => styles[key] + ); + + if (className) classNames.push(className); + + return classNames.join(' '); +}; + +type ExtractedProps = 'className' | 'orientation' | 'shape' | 'size'; + +export const Icon = ({ + className = '', + orientation, + shape, + size = 'md', + ...props +}: IconProps) => { + const iconClass = buildClassName({ className, shape, size }); + + if (shape === 'hamburger') + return ( + , ExtractedProps>)} + className={iconClass} + /> + ); + + if (shape === 'minus' || shape === 'plus') + return ( + , ExtractedProps>)} + className={iconClass} + shape={shape} + /> + ); + + const viewBox = shape === 'cc-by-sa' ? '0 0 100 40' : '0 0 100 100'; + + // Without casting Typescript complains because of props generic type + const { heading, description, ...remainingProps } = props as Omit< + IconProps, + ExtractedProps + >; + + return ( + + {heading ? {heading} : null} + {description ? {description} : null} + + + ); +}; diff --git a/src/components/atoms/images/icons/index.ts b/src/components/atoms/images/icons/index.ts new file mode 100644 index 0000000..af77d84 --- /dev/null +++ b/src/components/atoms/images/icons/index.ts @@ -0,0 +1 @@ +export * from './icon'; diff --git a/src/components/atoms/images/icons/plus-minus-icon/index.ts b/src/components/atoms/images/icons/plus-minus-icon/index.ts new file mode 100644 index 0000000..acca727 --- /dev/null +++ b/src/components/atoms/images/icons/plus-minus-icon/index.ts @@ -0,0 +1 @@ +export * from './plus-minus-icon'; diff --git a/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.module.scss b/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.module.scss new file mode 100644 index 0000000..07550c9 --- /dev/null +++ b/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.module.scss @@ -0,0 +1,38 @@ +@use "../../../../../styles/abstracts/functions" as fun; + +.icon { + display: flex; + place-content: center; + place-items: center; + aspect-ratio: 1/1; + position: relative; + background: var(--color-bg); + border: fun.convert-px(1) solid var(--color-primary); + border-radius: fun.convert-px(3); + color: var(--color-primary); + + &::before, + &::after { + content: ""; + position: absolute; + background: var(--color-primary); + transition: transform 0.4s ease-out 0s; + } + + &::after { + height: fun.convert-px(3); + width: 60%; + } + + &::before { + height: 55%; + width: fun.convert-px(3); + transform: scaleY(1); + } + + &--minus { + &::before { + transform: scaleY(0); + } + } +} diff --git a/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.tsx b/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.tsx new file mode 100644 index 0000000..ed6bcf2 --- /dev/null +++ b/src/components/atoms/images/icons/plus-minus-icon/plus-minus-icon.tsx @@ -0,0 +1,30 @@ +import type { FC, HTMLAttributes } from 'react'; +import styles from './plus-minus-icon.module.scss'; + +export type PlusMinusIconShape = 'minus' | 'plus'; + +export type PlusMinusIconProps = Omit< + HTMLAttributes, + 'children' +> & { + /** + * Which shape should be displayed. + */ + shape: PlusMinusIconShape; +}; + +/** + * PlusMinusIcon component + * + * Render a plus or a minus icon. + */ +export const PlusMinusIcon: FC = ({ + className = '', + shape, + ...props +}) => { + const shapeClass = styles[`icon--${shape}`]; + const iconClass = `${styles.icon} ${shapeClass} ${className}`; + + return
; +}; diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/arrow-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/arrow-icon-paths.tsx new file mode 100644 index 0000000..ee29d5d --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/arrow-icon-paths.tsx @@ -0,0 +1,51 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +export type ArrowOrientation = 'top' | 'right' | 'bottom' | 'left'; + +const getArrowBarPathFrom = (orientation: ArrowOrientation) => { + switch (orientation) { + case 'bottom': + return 'm 55.749998,2e-6 v 61.764896 h -11.5 V 2e-6 Z'; + case 'left': + return 'M 99.999996,44.25 H 38.2351 v 11.5 h 61.764896 z'; + case 'right': + return 'm 0,44.25 h 61.764896 v 11.5 H 0 Z'; + case 'top': + default: + return 'M 55.749998,99.999998 V 38.235102 h -11.5 v 61.764896 z'; + } +}; + +const getArrowHeadPathFrom = (orientation: ArrowOrientation) => { + switch (orientation) { + case 'bottom': + return 'm 69.999998,61.764898 -20,38.2351 -20,-38.2351 z'; + case 'left': + return 'M 38.2351,30 0,50 38.2351,70 Z'; + case 'right': + return 'm 61.764896,30 38.2351,20 -38.2351,20 z'; + case 'top': + default: + return 'm 69.999998,38.235102 -20,-38.2351 -20,38.2351 z'; + } +}; + +export type ArrowProps = { + /** + * The arrow orientation. + */ + orientation: ArrowOrientation; +}; + +/** + * ArrowIconPaths + * + * Render the svg paths to make an arrow icon. + */ +export const ArrowIconPaths: FC = ({ orientation }) => ( + <> + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.module.scss new file mode 100644 index 0000000..f93e73a --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.module.scss @@ -0,0 +1,43 @@ +.bottom, +.diploma, +.lines, +.top { + stroke-width: 4; +} + +.bottom, +.diploma, +.handle, +.lock, +.seal, +.top { + stroke: var(--color-primary-darker); +} + +.bottom { + fill: var(--color-primary); +} + +.diploma, +.lock { + fill: var(--color-bg); +} + +.handle, +.seal, +.top { + fill: var(--color-primary-lighter); +} + +.handle, +.lock { + stroke-width: 3; +} + +.lines { + fill: var(--color-fg); +} + +.seal { + stroke-width: 2; +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.tsx new file mode 100644 index 0000000..8fbaa12 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/career-icon-paths.tsx @@ -0,0 +1,57 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './career-icon-paths.module.scss'; + +/** + * CareerIconPaths + * + * Render the svg paths to make a career icon. + */ +export const CareerIconPaths: FC = () => ( + <> + + + + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/cc-by-sa-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/cc-by-sa-icon-paths.tsx new file mode 100644 index 0000000..5961d92 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/cc-by-sa-icon-paths.tsx @@ -0,0 +1,20 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +/** + * CCBySAIconPaths + * + * Render the svg paths to make a CC-BY-SA icon. + */ +export const CCBySAIconPaths: FC = () => ( + <> + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/cog-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/cog-icon-paths.tsx new file mode 100644 index 0000000..1ff9e3c --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/cog-icon-paths.tsx @@ -0,0 +1,14 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +/** + * CogIconPaths component + * + * Render the svg paths to make a cog icon. + */ +export const CogIconPaths: FC = () => ( + <> + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.module.scss new file mode 100644 index 0000000..479b8b7 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.module.scss @@ -0,0 +1,37 @@ +.cursor, +.lines, +.root, +.separator, +.text { + fill: var(--color-fg); +} + +.contour, +.stand, +.screen { + stroke: var(--color-primary-dark); +} + +.contour, +.screen { + stroke-width: 3; +} + +.contour, +.stand { + fill: var(--color-primary-lighter); +} + +.screen { + fill: var(--color-bg); +} + +.stand { + &--top { + stroke-width: 3; + } + + &--bottom { + stroke-width: 2; + } +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.tsx new file mode 100644 index 0000000..f581332 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/computer-icon-paths.tsx @@ -0,0 +1,65 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './computer-icon-paths.module.scss'; + +/** + * ComputerIconPaths + * + * Render the svg paths to make a computer icon. + */ +export const ComputerIconPaths: FC = () => ( + <> + + + + + + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.module.scss new file mode 100644 index 0000000..b30fea9 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.module.scss @@ -0,0 +1,5 @@ +.lines { + fill: var(--color-primary-lighter); + stroke: var(--color-primary-darker); + stroke-width: 3; +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.tsx new file mode 100644 index 0000000..12740af --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/cross-icon-paths.tsx @@ -0,0 +1,21 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './cross-icon-paths.module.scss'; + +/** + * CrossIconPaths + * + * Render the svg paths to make a cross icon. + */ +export const CrossIconPaths: FC = () => ( + <> + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.module.scss new file mode 100644 index 0000000..0819bba --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.module.scss @@ -0,0 +1,22 @@ +.bg, +.envelop, +.paper { + stroke: var(--color-primary-darker); + stroke-width: 4; +} + +.bg { + fill: var(--color-shadow-dark); +} + +.envelop { + fill: var(--color-primary-lighter); +} + +.lines { + fill: var(--color-fg); +} + +.paper { + fill: var(--color-bg); +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.tsx new file mode 100644 index 0000000..9e23991 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/envelop-icon-paths.tsx @@ -0,0 +1,53 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './envelop-icon-paths.module.scss'; + +/** + * EnvelopIconPaths + * + * Render the svg paths to make an envelop icon. + */ +export const EnvelopIconPaths: FC = () => ( + <> + + + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/feed-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/feed-icon-paths.tsx new file mode 100644 index 0000000..922bf8a --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/feed-icon-paths.tsx @@ -0,0 +1,59 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +/** + * FeedIconPaths + * + * Render the svg paths to make a feed icon. + */ +export const FeedIconPaths: FC = () => ( + <> + + + + + + + + + + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.module.scss new file mode 100644 index 0000000..a8d775c --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.module.scss @@ -0,0 +1,25 @@ +.chimney, +.door, +.indoor, +.roof, +.wall { + stroke: var(--color-primary-darker); +} + +.door, +.roof { + fill: var(--color-primary-lighter); +} + +.indoor { + fill: var(--color-shadow-dark); +} + +.chimney, +.wall { + fill: var(--color-bg); +} + +.lines { + fill: var(--color-primary-darker); +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.tsx new file mode 100644 index 0000000..d472445 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/home-icon-paths.tsx @@ -0,0 +1,41 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './home-icon-paths.module.scss'; + +/** + * HomeIconPaths + * + * Render the svg paths to make a home icon. + */ +export const HomeIconPaths: FC = () => ( + <> + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/index.ts b/src/components/atoms/images/icons/svg-paths/icons-paths/index.ts new file mode 100644 index 0000000..43927ae --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/index.ts @@ -0,0 +1,13 @@ +export * from './arrow-icon-paths'; +export * from './career-icon-paths'; +export * from './cc-by-sa-icon-paths'; +export * from './cog-icon-paths'; +export * from './computer-icon-paths'; +export * from './cross-icon-paths'; +export * from './envelop-icon-paths'; +export * from './feed-icon-paths'; +export * from './home-icon-paths'; +export * from './magnifying-glass-icon-paths'; +export * from './moon-icon-paths'; +export * from './posts-stack-icon-paths'; +export * from './sun-icon-paths'; diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.module.scss new file mode 100644 index 0000000..4b7db05 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.module.scss @@ -0,0 +1,20 @@ +.big-handle, +.upright { + fill: var(--color-primary-lighter); + stroke: var(--color-primary-darker); + stroke-width: 3; +} + +.glass, +.small-handle { + stroke: var(--color-primary-darker); + stroke-width: 2; +} + +.glass { + fill: var(--color-bg-opacity); +} + +.small-handle { + fill: var(--color-primary); +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.tsx new file mode 100644 index 0000000..b800305 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/magnifying-glass-icon-paths.tsx @@ -0,0 +1,29 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './magnifying-glass-icon-paths.module.scss'; + +/** + * MagnifyingGlassIconPaths + * + * Render the svg paths to make a magnifying glass icon. + */ +export const MagnifyingGlassIconPaths: FC = () => ( + <> + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/moon-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/moon-icon-paths.tsx new file mode 100644 index 0000000..35025ef --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/moon-icon-paths.tsx @@ -0,0 +1,11 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +/** + * MoonIconPaths + * + * Render the svg paths to make a moon icon. + */ +export const MoonIconPaths: FC = () => ( + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.module.scss b/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.module.scss new file mode 100644 index 0000000..f368493 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.module.scss @@ -0,0 +1,21 @@ +.bg, +.lines { + stroke-width: 4; +} + +.bg, +.picture { + stroke: var(--color-primary-darker); +} + +.bg { + fill: var(--color-bg); +} + +.lines { + fill: var(--color-fg); +} + +.picture { + fill: var(--color-primary-lighter); +} diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.tsx new file mode 100644 index 0000000..daf14d4 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/posts-stack-icon-paths.tsx @@ -0,0 +1,49 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; +import styles from './posts-stack-icon-paths.module.scss'; + +/** + * PostsStackIconPaths + * + * Render the svg paths to make a posts stack icon. + */ +export const PostsStackIconPaths: FC = () => ( + <> + + + + + + + + + + + + + +); diff --git a/src/components/atoms/images/icons/svg-paths/icons-paths/sun-icon-paths.tsx b/src/components/atoms/images/icons/svg-paths/icons-paths/sun-icon-paths.tsx new file mode 100644 index 0000000..0cdffb3 --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/icons-paths/sun-icon-paths.tsx @@ -0,0 +1,11 @@ +/* eslint-disable react/jsx-no-literals */ +import type { FC } from 'react'; + +/** + * SunIconPaths + * + * Render the svg paths to make a sun icon. + */ +export const SunIconPaths: FC = () => ( + +); diff --git a/src/components/atoms/images/icons/svg-paths/index.ts b/src/components/atoms/images/icons/svg-paths/index.ts new file mode 100644 index 0000000..01623ef --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/index.ts @@ -0,0 +1 @@ +export * from './svg-paths'; diff --git a/src/components/atoms/images/icons/svg-paths/svg-paths.tsx b/src/components/atoms/images/icons/svg-paths/svg-paths.tsx new file mode 100644 index 0000000..0f5be6e --- /dev/null +++ b/src/components/atoms/images/icons/svg-paths/svg-paths.tsx @@ -0,0 +1,82 @@ +import type { FC } from 'react'; +import { + ArrowIconPaths, + type ArrowOrientation, + CCBySAIconPaths, + CareerIconPaths, + CogIconPaths, + ComputerIconPaths, + EnvelopIconPaths, + FeedIconPaths, + HomeIconPaths, + MagnifyingGlassIconPaths, + MoonIconPaths, + PostsStackIconPaths, + SunIconPaths, + CrossIconPaths, +} from './icons-paths'; + +export type SVGIconOrientation = ArrowOrientation; + +export type SVGIconShape = + | 'arrow' + | 'career' + | 'cc-by-sa' + | 'cog' + | 'computer' + | 'cross' + | 'envelop' + | 'feed' + | 'home' + | 'magnifying-glass' + | 'moon' + | 'posts-stack' + | 'sun'; + +export type SVGPathsProps = { + /** + * The icon orientation. Only used with arrow icon. + * + * @default 'right' + */ + orientation?: SVGIconOrientation; + /** + * The icon shape. + */ + shape: SVGIconShape; +}; + +export const SVGPaths: FC = ({ + orientation = 'right', + shape, +}) => { + switch (shape) { + case 'arrow': + return ; + case 'career': + return ; + case 'cc-by-sa': + return ; + case 'cog': + return ; + case 'computer': + return ; + case 'cross': + return ; + case 'envelop': + return ; + case 'feed': + return ; + case 'home': + return ; + case 'magnifying-glass': + return ; + case 'moon': + return ; + case 'posts-stack': + return ; + case 'sun': + default: + return ; + } +}; diff --git a/src/components/atoms/images/index.ts b/src/components/atoms/images/index.ts index cb6151d..197d909 100644 --- a/src/components/atoms/images/index.ts +++ b/src/components/atoms/images/index.ts @@ -1 +1,2 @@ +export * from './icons'; export * from './logo'; -- cgit v1.2.3