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. --- .../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 +-- 16 files changed, 175 insertions(+), 201 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/components') 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 (