From 9492414d4ae94045eff4e06f636529bc0e71cb06 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 20 Oct 2023 17:01:37 +0200 Subject: refactor(components): rewrite Copyright component * remove `icon` prop (it is confusing because a copyright should have the copyright symbol, the license is not part of the copyright) * reorganize copyright informations I also updated the CC BY SA icon because the elements was in the wrong order. --- src/assets/images/cc-by-sa.svg | 38 ++++++------- .../svg-paths/icons-paths/cc-by-sa-icon-paths.tsx | 19 ++++--- src/components/atoms/layout/copyright.module.scss | 32 ----------- src/components/atoms/layout/copyright.stories.tsx | 58 ------------------- src/components/atoms/layout/copyright.test.tsx | 34 ----------- src/components/atoms/layout/copyright.tsx | 50 ----------------- src/components/atoms/layout/index.ts | 1 - .../molecules/copyright/copyright.module.scss | 4 ++ .../molecules/copyright/copyright.stories.tsx | 65 ++++++++++++++++++++++ .../molecules/copyright/copyright.test.tsx | 23 ++++++++ src/components/molecules/copyright/copyright.tsx | 48 ++++++++++++++++ src/components/molecules/copyright/index.ts | 1 + src/components/molecules/index.ts | 1 + .../organisms/layout/site-footer.stories.tsx | 5 +- .../organisms/layout/site-footer.test.tsx | 9 +-- src/components/organisms/layout/site-footer.tsx | 18 +++--- src/components/templates/layout/layout.tsx | 8 +-- 17 files changed, 194 insertions(+), 220 deletions(-) delete mode 100644 src/components/atoms/layout/copyright.module.scss delete mode 100644 src/components/atoms/layout/copyright.stories.tsx delete mode 100644 src/components/atoms/layout/copyright.test.tsx delete mode 100644 src/components/atoms/layout/copyright.tsx create mode 100644 src/components/molecules/copyright/copyright.module.scss create mode 100644 src/components/molecules/copyright/copyright.stories.tsx create mode 100644 src/components/molecules/copyright/copyright.test.tsx create mode 100644 src/components/molecules/copyright/copyright.tsx create mode 100644 src/components/molecules/copyright/index.ts (limited to 'src') diff --git a/src/assets/images/cc-by-sa.svg b/src/assets/images/cc-by-sa.svg index 949002c..3af4fc0 100644 --- a/src/assets/images/cc-by-sa.svg +++ b/src/assets/images/cc-by-sa.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.4082226" - inkscape:cx="36.956717" - inkscape:cy="27.198482" + inkscape:zoom="4.0486371" + inkscape:cx="24.452673" + inkscape:cy="45.817888" inkscape:document-units="px" inkscape:current-layer="svg8" inkscape:document-rotation="0" @@ -55,35 +55,35 @@ + style="stroke-width:0.446638" /> + style="stroke-width:0.446638" /> + d="m 49.974702,5.7075681 c -3.947838,0 -7.29882,1.3777958 -10.055473,4.1348959 C 37.112107,12.700951 35.707566,16.087 35.707566,20 c 0,3.913447 1.40454,7.273201 4.211663,10.080771 2.841068,2.80757 6.192495,4.211661 10.055473,4.211661 3.929971,0 7.340998,-1.421169 10.233429,-4.263129 C 62.930839,27.358405 64.29243,24.015727 64.29243,20 c 0,-3.998308 -1.387464,-7.383911 -4.160195,-10.157536 C 57.375582,7.0858108 53.989089,5.7075681 49.974702,5.7075681 Z m 0.05059,2.5777675 c 3.232768,0 5.989274,1.1399334 8.268917,3.4195754 2.279196,2.280536 3.419576,5.044475 3.419576,8.294217 0,3.301105 -1.122836,6.032188 -3.36898,8.193025 -2.36495,2.331899 -5.138982,3.496342 -8.320385,3.496342 -3.198825,0 -5.954888,-1.156563 -8.268923,-3.471044 -2.313587,-2.312695 -3.470171,-5.051698 -3.470171,-8.216579 0,-3.147461 1.164892,-5.912719 3.496345,-8.295088 2.246145,-2.279643 4.993878,-3.4204484 8.243621,-3.4204484 z" + style="stroke-width:0.446638" /> + style="stroke-width:0.446638" /> + d="m 83.025529,5.7075681 c -3.930417,0 -7.282295,1.3869937 -10.05547,4.1610649 -2.807123,2.858487 -4.211662,6.236212 -4.211662,10.132239 0,3.913894 1.404539,7.272776 4.211662,10.079899 2.841067,2.80757 6.192495,4.211661 10.05547,4.211661 3.946498,0 7.358419,-1.412417 10.233431,-4.236958 2.722708,-2.70529 4.084299,-6.056272 4.084299,-10.055474 0,-3.998308 -1.387465,-7.375586 -4.160196,-10.1322391 C 90.408991,7.0941366 87.023391,5.7075681 83.025529,5.7075681 Z m 0.0506,2.5777675 c 3.249294,0 6.0058,1.1477914 8.268917,3.4457454 2.279197,2.245698 3.419577,5.002652 3.419577,8.268919 0,3.284133 -1.122837,6.015216 -3.368981,8.193026 -2.364952,2.331006 -5.138982,3.496341 -8.320385,3.496341 -3.198823,0 -5.954885,-1.156563 -8.268921,-3.471044 C 72.492744,25.921261 71.336161,23.182299 71.336161,20 c 0,-3.147014 1.164891,-5.903521 3.496344,-8.268919 2.246146,-2.297062 4.993878,-3.4457454 8.243618,-3.4457454 z" + style="stroke-width:0.446638" /> + d="m 16.923439,5.707569 c -3.964485,0 -7.3081372,1.387505 -10.0304815,4.16032 -1.3779222,1.378369 -2.4287352,2.939566 -3.1518644,4.683742 -0.7231292,1.744177 -1.0843526,3.559914 -1.0843526,5.448806 0,1.905865 0.3574962,3.717877 1.0721392,5.436596 0.7146444,1.718714 1.7566842,3.262836 3.126566,4.63227 1.3698819,1.369435 2.9185982,2.416096 4.6453563,3.13878 1.727204,0.724023 3.535064,1.084348 5.423508,1.084348 1.888446,0 3.718002,-0.364947 5.487191,-1.096564 1.770087,-0.731616 3.352531,-1.787899 4.747423,-3.165819 1.343533,-1.31003 2.360614,-2.820419 3.0498,-4.530204 0.688287,-1.70934 1.032883,-3.542622 1.032883,-5.499407 0,-1.939809 -0.349616,-3.773073 -1.046841,-5.500277 C 29.497095,12.773404 28.476284,11.237164 27.132755,9.893188 24.325548,7.1029519 20.921421,5.707569 16.923439,5.707569 Z m 0.05147,2.5778471 c 3.232867,0 5.997743,1.1487199 8.296212,3.4458509 1.105019,1.106804 1.947112,2.365909 2.524633,3.778224 0.578414,1.412312 0.868006,2.909332 0.868006,4.491817 0,3.284683 -1.114117,6.015399 -3.342911,8.19328 -1.157722,1.12288 -2.453859,1.981561 -3.891633,2.577845 -1.43956,0.595834 -2.923186,0.892428 -4.454307,0.892428 -1.548543,0 -3.029356,-0.293316 -4.441223,-0.880217 C 11.120479,30.19685 9.8539198,29.346942 8.7310371,28.232096 7.6077069,27.117702 6.7444257,25.850267 6.1401055,24.428577 5.5353382,23.008668 5.233716,21.532881 5.233716,20.001308 c 0,-1.548541 0.3016222,-3.033506 0.9063895,-4.454303 C 6.7439799,14.126202 7.6077069,12.846272 8.7310371,11.705969 10.960277,9.426255 13.708096,8.2854161 16.97491,8.2854161 Z" + style="stroke-width:0.446638" /> + style="stroke-width:0.446638" /> + style="stroke-width:0.446638" /> 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 index 5961d92..a21b94d 100644 --- 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 @@ -8,13 +8,16 @@ import type { FC } from 'react'; */ export const CCBySAIconPaths: FC = () => ( <> - - - - - - - - + + + + + + + + ); diff --git a/src/components/atoms/layout/copyright.module.scss b/src/components/atoms/layout/copyright.module.scss deleted file mode 100644 index 5d5435c..0000000 --- a/src/components/atoms/layout/copyright.module.scss +++ /dev/null @@ -1,32 +0,0 @@ -@use "../../../styles/abstracts/functions" as fun; -@use "../../../styles/abstracts/mixins" as mix; - -.wrapper { - --icon-size: #{fun.convert-px(70)}; - - display: flex; - flex-flow: row wrap; - align-items: center; - place-content: center; - gap: var(--spacing-2xs); - margin: 0; - font-family: var(--font-family-secondary); - font-size: var(--font-size-md); - text-align: center; - - @include mix.media("screen") { - @include mix.dimensions("sm") { - text-align: left; - } - } -} - -.owner { - flex: 1 0 100%; - - @include mix.media("screen") { - @include mix.dimensions("sm") { - flex: initial; - } - } -} diff --git a/src/components/atoms/layout/copyright.stories.tsx b/src/components/atoms/layout/copyright.stories.tsx deleted file mode 100644 index 58d1b1e..0000000 --- a/src/components/atoms/layout/copyright.stories.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import type { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Icon } from '../images/icons'; -import { Copyright as CopyrightComponent } from './copyright'; - -/** - * Copyright - Storybook Meta - */ -export default { - title: 'Atoms/Layout', - component: CopyrightComponent, - argTypes: { - dates: { - description: 'The copyright dates.', - type: { - name: 'object', - required: true, - value: {}, - }, - }, - icon: { - control: { - type: null, - }, - description: 'The copyright icon.', - type: { - name: 'string', - required: true, - }, - }, - owner: { - control: { - type: 'text', - }, - description: 'The copyright owner', - type: { - name: 'string', - required: true, - }, - }, - }, -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - -); - -/** - * Layout Stories - Copyright - */ -export const Copyright = Template.bind({}); -Copyright.args = { - dates: { - start: '2012', - end: '2022', - }, - icon: , - owner: 'Your name', -}; diff --git a/src/components/atoms/layout/copyright.test.tsx b/src/components/atoms/layout/copyright.test.tsx deleted file mode 100644 index cdff292..0000000 --- a/src/components/atoms/layout/copyright.test.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen as rtlScreen } from '../../../../tests/utils'; -import { Icon } from '../images/icons'; -import { Copyright } from './copyright'; - -const dates = { - start: '2012', - end: '2022', -}; -const iconHeading = 'CC BY SA'; -const icon = ; -const owner = 'Your name'; - -describe('Copyright', () => { - it('renders the copyright owner', () => { - render(); - expect(rtlScreen.getByText(owner)).toBeInTheDocument(); - }); - - it('renders the copyright start date', () => { - render(); - expect(rtlScreen.getByText(dates.start)).toBeInTheDocument(); - }); - - it('renders the copyright end date', () => { - render(); - expect(rtlScreen.getByText(dates.end)).toBeInTheDocument(); - }); - - it('renders the copyright icon', () => { - render(); - expect(rtlScreen.getByTitle('CC BY SA')).toBeInTheDocument(); - }); -}); diff --git a/src/components/atoms/layout/copyright.tsx b/src/components/atoms/layout/copyright.tsx deleted file mode 100644 index 3d56059..0000000 --- a/src/components/atoms/layout/copyright.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import type { FC, ReactNode } from 'react'; -import styles from './copyright.module.scss'; -import { Time } from './time'; - -export type CopyrightDates = { - /** - * The copyright start year. - */ - start: string; - /** - * The copyright end year. - */ - end?: string; -}; - -export type CopyrightProps = { - /** - * The copyright owner. - */ - owner: string; - /** - * The copyright dates. - */ - dates: CopyrightDates; - /** - * The copyright icon. - */ - icon: ReactNode; -}; - -/** - * Copyright component - * - * Renders a copyright information (owner, dates, license icon). - */ -export const Copyright: FC = ({ owner, dates, icon }) => ( -
- {owner} - {icon} -
-); diff --git a/src/components/atoms/layout/index.ts b/src/components/atoms/layout/index.ts index c37ff02..b8a7e6f 100644 --- a/src/components/atoms/layout/index.ts +++ b/src/components/atoms/layout/index.ts @@ -1,6 +1,5 @@ export * from './article'; export * from './aside'; -export * from './copyright'; export * from './footer'; export * from './header'; export * from './main'; diff --git a/src/components/molecules/copyright/copyright.module.scss b/src/components/molecules/copyright/copyright.module.scss new file mode 100644 index 0000000..cf57e7e --- /dev/null +++ b/src/components/molecules/copyright/copyright.module.scss @@ -0,0 +1,4 @@ +.wrapper { + font-family: var(--font-family-secondary); + font-size: var(--font-size-md); +} diff --git a/src/components/molecules/copyright/copyright.stories.tsx b/src/components/molecules/copyright/copyright.stories.tsx new file mode 100644 index 0000000..58a82e9 --- /dev/null +++ b/src/components/molecules/copyright/copyright.stories.tsx @@ -0,0 +1,65 @@ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Copyright } from './copyright'; + +/** + * Copyright - Storybook Meta + */ +export default { + title: 'Molecules/Copyright', + component: Copyright, + argTypes: { + from: { + control: { + type: 'text', + }, + description: 'The copyright start date.', + type: { + name: 'string', + required: true, + }, + }, + owner: { + control: { + type: 'text', + }, + description: 'The copyright owner.', + type: { + name: 'string', + required: true, + }, + }, + to: { + control: { + type: 'text', + }, + description: 'The copyright end date.', + type: { + name: 'string', + required: false, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +/** + * Copyright Stories - Default + */ +export const Default = Template.bind({}); +Default.args = { + from: '2012', + owner: 'Your brand', +}; + +/** + * Copyright Stories - WithEndYear + */ +export const WithEndYear = Template.bind({}); +WithEndYear.args = { + from: '2012', + owner: 'Your brand', + to: '2023', +}; diff --git a/src/components/molecules/copyright/copyright.test.tsx b/src/components/molecules/copyright/copyright.test.tsx new file mode 100644 index 0000000..0530478 --- /dev/null +++ b/src/components/molecules/copyright/copyright.test.tsx @@ -0,0 +1,23 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '../../../../tests/utils'; +import { Copyright } from './copyright'; + +const from = '2012'; +const to = '2023'; +const owner = 'Your name'; + +describe('Copyright', () => { + it('renders the copyright symbol, the owner and the start year', () => { + render(); + + expect(rtlScreen.getByText(new RegExp(owner))).toBeInTheDocument(); + expect(rtlScreen.getByText(from)).toBeInTheDocument(); + }); + + it('can render a copyright with end year', () => { + render(); + + expect(rtlScreen.getByText(from)).toBeInTheDocument(); + expect(rtlScreen.getByText(to)).toBeInTheDocument(); + }); +}); diff --git a/src/components/molecules/copyright/copyright.tsx b/src/components/molecules/copyright/copyright.tsx new file mode 100644 index 0000000..cef8ecb --- /dev/null +++ b/src/components/molecules/copyright/copyright.tsx @@ -0,0 +1,48 @@ +import type { FC, HTMLAttributes } from 'react'; +import { Time } from '../../atoms'; +import styles from './copyright.module.scss'; + +export type CopyrightProps = Omit< + HTMLAttributes, + 'children' +> & { + /** + * The start year of the copyright. + */ + from: string; + /** + * The end year of the copyright. + */ + to?: string; + /** + * The copyright owner. + */ + owner: string; +}; + +export const Copyright: FC = ({ + className = '', + from, + owner, + to, + ...props +}) => { + const wrapperClass = `${styles.wrapper} ${className}`; + + /* eslint-disable react/jsx-no-literals -- Symbols allowed */ + return ( + + © + + ); + /* eslint-enable react/jsx-no-literals */ +}; diff --git a/src/components/molecules/copyright/index.ts b/src/components/molecules/copyright/index.ts new file mode 100644 index 0000000..4b4368c --- /dev/null +++ b/src/components/molecules/copyright/index.ts @@ -0,0 +1 @@ +export * from './copyright'; diff --git a/src/components/molecules/index.ts b/src/components/molecules/index.ts index 7f48e45..d53d999 100644 --- a/src/components/molecules/index.ts +++ b/src/components/molecules/index.ts @@ -3,6 +3,7 @@ export * from './buttons'; export * from './card'; export * from './code'; export * from './collapsible'; +export * from './copyright'; export * from './forms'; export * from './grid'; export * from './images'; diff --git a/src/components/organisms/layout/site-footer.stories.tsx b/src/components/organisms/layout/site-footer.stories.tsx index 77cc183..3f244b0 100644 --- a/src/components/organisms/layout/site-footer.stories.tsx +++ b/src/components/organisms/layout/site-footer.stories.tsx @@ -73,9 +73,9 @@ const Template: ComponentStory = (args) => ( ); const copyright = { - dates: { start: '2017', end: '2022' }, + from: '2017', owner: 'Lorem ipsum', - icon: , + to: '2022', }; const navItems = [{ id: 'legal-notice', href: '#', label: 'Legal notice' }]; @@ -86,6 +86,7 @@ const navItems = [{ id: 'legal-notice', href: '#', label: 'Legal notice' }]; export const SiteFooter = Template.bind({}); SiteFooter.args = { copyright, + license: , navItems, topId: 'top', }; diff --git a/src/components/organisms/layout/site-footer.test.tsx b/src/components/organisms/layout/site-footer.test.tsx index 0d2cec2..11ddd7f 100644 --- a/src/components/organisms/layout/site-footer.test.tsx +++ b/src/components/organisms/layout/site-footer.test.tsx @@ -3,9 +3,8 @@ import { render, screen as rtlScreen } from '../../../../tests/utils'; import { SiteFooter, type SiteFooterProps } from './site-footer'; const copyright: SiteFooterProps['copyright'] = { - dates: { start: '2017', end: '2022' }, + from: '2017', owner: 'Lorem ipsum', - icon: 'CC', }; const navItems: SiteFooterProps['navItems'] = [ @@ -15,8 +14,10 @@ const navItems: SiteFooterProps['navItems'] = [ describe('SiteFooter', () => { it('renders the website copyright', () => { render(); - expect(rtlScreen.getByText(copyright.owner)).toBeInTheDocument(); - expect(rtlScreen.getByText(copyright.dates.start)).toBeInTheDocument(); + expect( + rtlScreen.getByText(new RegExp(copyright.owner)) + ).toBeInTheDocument(); + expect(rtlScreen.getByText(new RegExp(copyright.from))).toBeInTheDocument(); }); it('renders a back to top link', () => { diff --git a/src/components/organisms/layout/site-footer.tsx b/src/components/organisms/layout/site-footer.tsx index b4930d6..9ed5ce6 100644 --- a/src/components/organisms/layout/site-footer.tsx +++ b/src/components/organisms/layout/site-footer.tsx @@ -1,12 +1,14 @@ -import type { FC } from 'react'; +import type { FC, ReactNode } from 'react'; import { useIntl } from 'react-intl'; -import { Copyright, type CopyrightProps, Footer } from '../../atoms'; +import { Footer } from '../../atoms'; import { BackToTop, type BackToTopProps, NavList, NavItem, NavLink, + type CopyrightProps, + Copyright, } from '../../molecules'; import styles from './site-footer.module.scss'; @@ -29,6 +31,10 @@ export type SiteFooterProps = { * Set the copyright information. */ copyright: CopyrightProps; + /** + * The website license. + */ + license?: ReactNode; /** * The footer nav items. */ @@ -48,6 +54,7 @@ export const SiteFooter: FC = ({ backToTopClassName, className = '', copyright, + license, navItems, topId, }) => { @@ -68,11 +75,8 @@ export const SiteFooter: FC = ({ return (