From 70b4f633a6fbedb58c8b9134ac64ede854d489de Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 20 Nov 2023 12:27:46 +0100 Subject: refactor(components): replace PageLayout template with Page * split pages in smaller components (it is both easier to maintain and more readable, we avoid the use of fragments in pages directory) * extract breadcrumbs from article tag (the navigation is not related to the page contents) * remove useReadingTime hook * remove layout options except `isHome` --- .../molecules/collapsible/collapsible.module.scss | 4 +- src/components/molecules/index.ts | 1 - src/components/molecules/layout/index.ts | 2 - .../molecules/layout/page-footer.stories.tsx | 57 --- .../molecules/layout/page-footer.test.tsx | 10 - src/components/molecules/layout/page-footer.tsx | 18 - .../molecules/layout/page-header.module.scss | 64 --- .../molecules/layout/page-header.stories.tsx | 154 ------ .../molecules/layout/page-header.test.tsx | 21 - src/components/molecules/layout/page-header.tsx | 62 --- src/components/templates/layout/layout.module.scss | 13 - src/components/templates/layout/layout.test.tsx | 14 +- src/components/templates/layout/layout.tsx | 25 +- src/components/templates/page/index.ts | 7 +- src/components/templates/page/page-body.test.tsx | 14 + src/components/templates/page/page-body.tsx | 23 + .../templates/page/page-comments.stories.tsx | 170 +++++++ .../templates/page/page-comments.test.tsx | 103 ++++ src/components/templates/page/page-comments.tsx | 178 +++++++ .../templates/page/page-footer.stories.tsx | 41 ++ src/components/templates/page/page-footer.test.tsx | 53 +++ src/components/templates/page/page-footer.tsx | 54 +++ .../templates/page/page-header.stories.tsx | 76 +++ src/components/templates/page/page-header.test.tsx | 149 ++++++ src/components/templates/page/page-header.tsx | 172 +++++++ .../templates/page/page-layout.module.scss | 95 ---- .../templates/page/page-layout.stories.tsx | 521 --------------------- src/components/templates/page/page-layout.test.tsx | 113 ----- src/components/templates/page/page-layout.tsx | 287 ------------ .../templates/page/page-sidebar.test.tsx | 14 + src/components/templates/page/page-sidebar.tsx | 20 + src/components/templates/page/page.module.scss | 212 +++++++++ src/components/templates/page/page.stories.tsx | 456 ++++++++++++++++++ src/components/templates/page/page.test.tsx | 49 ++ src/components/templates/page/page.tsx | 56 +++ 35 files changed, 1858 insertions(+), 1450 deletions(-) delete mode 100644 src/components/molecules/layout/index.ts delete mode 100644 src/components/molecules/layout/page-footer.stories.tsx delete mode 100644 src/components/molecules/layout/page-footer.test.tsx delete mode 100644 src/components/molecules/layout/page-footer.tsx delete mode 100644 src/components/molecules/layout/page-header.module.scss delete mode 100644 src/components/molecules/layout/page-header.stories.tsx delete mode 100644 src/components/molecules/layout/page-header.test.tsx delete mode 100644 src/components/molecules/layout/page-header.tsx create mode 100644 src/components/templates/page/page-body.test.tsx create mode 100644 src/components/templates/page/page-body.tsx create mode 100644 src/components/templates/page/page-comments.stories.tsx create mode 100644 src/components/templates/page/page-comments.test.tsx create mode 100644 src/components/templates/page/page-comments.tsx create mode 100644 src/components/templates/page/page-footer.stories.tsx create mode 100644 src/components/templates/page/page-footer.test.tsx create mode 100644 src/components/templates/page/page-footer.tsx create mode 100644 src/components/templates/page/page-header.stories.tsx create mode 100644 src/components/templates/page/page-header.test.tsx create mode 100644 src/components/templates/page/page-header.tsx delete mode 100644 src/components/templates/page/page-layout.module.scss delete mode 100644 src/components/templates/page/page-layout.stories.tsx delete mode 100644 src/components/templates/page/page-layout.test.tsx delete mode 100644 src/components/templates/page/page-layout.tsx create mode 100644 src/components/templates/page/page-sidebar.test.tsx create mode 100644 src/components/templates/page/page-sidebar.tsx create mode 100644 src/components/templates/page/page.module.scss create mode 100644 src/components/templates/page/page.stories.tsx create mode 100644 src/components/templates/page/page.test.tsx create mode 100644 src/components/templates/page/page.tsx (limited to 'src/components') diff --git a/src/components/molecules/collapsible/collapsible.module.scss b/src/components/molecules/collapsible/collapsible.module.scss index 3c5a97c..2ee9aea 100644 --- a/src/components/molecules/collapsible/collapsible.module.scss +++ b/src/components/molecules/collapsible/collapsible.module.scss @@ -88,12 +88,12 @@ max-height 1.2s ease-in-out; &--has-padding { - margin: var(--spacing-2xs) 0; + margin-top: var(--spacing-2xs); padding-block: var(--spacing-2xs); } &--no-padding { - margin: var(--spacing-xs) 0; + margin-top: var(--spacing-xs); } } } diff --git a/src/components/molecules/index.ts b/src/components/molecules/index.ts index 04c669f..0619de8 100644 --- a/src/components/molecules/index.ts +++ b/src/components/molecules/index.ts @@ -8,7 +8,6 @@ export * from './copyright'; export * from './forms'; export * from './grid'; export * from './images'; -export * from './layout'; export * from './meta-list'; export * from './modals'; export * from './nav'; diff --git a/src/components/molecules/layout/index.ts b/src/components/molecules/layout/index.ts deleted file mode 100644 index f204f56..0000000 --- a/src/components/molecules/layout/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './page-footer'; -export * from './page-header'; diff --git a/src/components/molecules/layout/page-footer.stories.tsx b/src/components/molecules/layout/page-footer.stories.tsx deleted file mode 100644 index 994e888..0000000 --- a/src/components/molecules/layout/page-footer.stories.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import type { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Link } from '../../atoms'; -import { MetaItem, MetaList } from '../meta-list'; -import { PageFooter as PageFooterComponent } from './page-footer'; - -/** - * Page Footer - Storybook Meta - */ -export default { - title: 'Molecules/Layout', - component: PageFooterComponent, - argTypes: { - className: { - control: { - type: 'text', - }, - description: 'Set additional classnames to the footer element.', - table: { - category: 'Styles', - }, - type: { - name: 'string', - required: false, - }, - }, - meta: { - description: 'The page meta.', - table: { - category: 'Options', - }, - type: { - name: 'object', - required: false, - value: {}, - }, - }, - }, -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - -); - -/** - * Page Footer Stories - With meta - */ -export const PageFooter = Template.bind({}); -PageFooter.args = { - children: ( - - Topic name} - /> - - ), -}; diff --git a/src/components/molecules/layout/page-footer.test.tsx b/src/components/molecules/layout/page-footer.test.tsx deleted file mode 100644 index dbd20f5..0000000 --- a/src/components/molecules/layout/page-footer.test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen as rtlScreen } from '../../../../tests/utils'; -import { PageFooter } from './page-footer'; - -describe('PageFooter', () => { - it('renders a footer element', () => { - render(); - expect(rtlScreen.getByRole('contentinfo')).toBeInTheDocument(); - }); -}); diff --git a/src/components/molecules/layout/page-footer.tsx b/src/components/molecules/layout/page-footer.tsx deleted file mode 100644 index e0ce2ef..0000000 --- a/src/components/molecules/layout/page-footer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import type { FC, ReactNode } from 'react'; -import { Footer, type FooterProps } from '../../atoms'; - -export type PageFooterProps = Omit & { - /** - * The footer contents. - */ - children?: ReactNode; -}; - -/** - * PageFooter component - * - * Render a footer to display page meta. - */ -export const PageFooter: FC = ({ children, ...props }) => ( -
{children}
-); diff --git a/src/components/molecules/layout/page-header.module.scss b/src/components/molecules/layout/page-header.module.scss deleted file mode 100644 index 1a90fe5..0000000 --- a/src/components/molecules/layout/page-header.module.scss +++ /dev/null @@ -1,64 +0,0 @@ -@use "../../../styles/abstracts/functions" as fun; -@use "../../../styles/abstracts/placeholders"; - -.wrapper { - @extend %grid; - - &::before, - &::after { - content: ""; - width: 100%; - height: 100%; - background: var(--color-bg-secondary); - border-top: fun.convert-px(3) solid var(--color-border-light); - border-bottom: fun.convert-px(3) solid var(--color-border-light); - } - - &::before { - grid-column: 1; - justify-self: start; - border-right: fun.convert-px(3) solid var(--color-border-light); - } - - &::after { - grid-column: 3; - justify-self: end; - border-left: fun.convert-px(3) solid var(--color-border-light); - } -} - -.body { - grid-column: 2; - display: flex; - flex-flow: column wrap; - row-gap: var(--spacing-sm); -} - -.title { - display: flex; - flex-flow: row wrap; - align-items: center; - position: relative; - - &::before, - &::after { - content: ""; - width: 100%; - height: fun.convert-px(4); - background: radial-gradient( - ellipse at center, - var(--color-primary-light), - var(--color-primary-dark) - ); - } -} - -.meta { - font-size: var(--font-size-sm); -} - -.intro { - > *:last-child { - margin-bottom: 0; - } -} diff --git a/src/components/molecules/layout/page-header.stories.tsx b/src/components/molecules/layout/page-header.stories.tsx deleted file mode 100644 index 97eae5a..0000000 --- a/src/components/molecules/layout/page-header.stories.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import type { ComponentMeta, ComponentStory } from '@storybook/react'; -import { MetaItem, MetaList } from '../meta-list'; -import { PageHeader } from './page-header'; - -/** - * Page Header - Storybook Meta - */ -export default { - title: 'Molecules/Layout/PageHeader', - component: PageHeader, - argTypes: { - className: { - control: { - type: 'text', - }, - description: 'Set additional classnames to the header element.', - table: { - category: 'Styles', - }, - type: { - name: 'string', - required: false, - }, - }, - intro: { - control: { - type: 'text', - }, - description: 'The page introduction.', - table: { - category: 'Options', - }, - type: { - name: 'string', - required: false, - }, - }, - meta: { - description: 'The page metadata.', - table: { - category: 'Options', - }, - type: { - name: 'object', - required: false, - value: {}, - }, - }, - title: { - control: { - type: 'text', - }, - description: 'The page title.', - type: { - name: 'string', - required: true, - }, - }, - }, -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - -); - -/** - * Page Header Stories - Default - */ -export const Default = Template.bind({}); -Default.args = { - title: 'Excepturi nesciunt illum', -}; - -/** - * Page Header Stories - With introduction - */ -export const WithIntro = Template.bind({}); -WithIntro.args = { - intro: - 'Minima dolor nihil. Velit atque odit totam enim. Quisquam reprehenderit ut et inventore et nihil libero exercitationem. Cumque similique magni placeat et. Et sed est cumque labore. Et quia similique.', - title: 'Excepturi nesciunt illum', -}; - -/** - * Page Header Stories - With meta - */ -export const WithMeta = Template.bind({}); -WithMeta.args = { - meta: ( - - - - Category 1 - - ), - }, - { - id: 'cat-2', - value: ( - - Category 2 - - ), - }, - ]} - /> - - ), - title: 'Excepturi nesciunt illum', -}; - -/** - * Page Header Stories - With introduction and meta - */ -export const WithIntroAndMeta = Template.bind({}); -WithIntroAndMeta.args = { - intro: - 'Minima dolor nihil. Velit atque odit totam enim. Quisquam reprehenderit ut et inventore et nihil libero exercitationem. Cumque similique magni placeat et. Et sed est cumque labore. Et quia similique.', - meta: ( - - - - Category 1 - - ), - }, - { - id: 'cat-2', - value: ( - - Category 2 - - ), - }, - ]} - /> - - ), - title: 'Excepturi nesciunt illum', -}; diff --git a/src/components/molecules/layout/page-header.test.tsx b/src/components/molecules/layout/page-header.test.tsx deleted file mode 100644 index 82aa7e1..0000000 --- a/src/components/molecules/layout/page-header.test.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen as rtlScreen } from '../../../../tests/utils'; -import { PageHeader } from './page-header'; - -const title = 'Non nemo amet'; -const intro = - 'Suscipit omnis minima doloribus commodi. Laudantium similique ut enim voluptatem soluta maxime autem et.'; - -describe('PageHeader', () => { - it('renders a title', () => { - render(); - expect(rtlScreen.getByRole('heading', { level: 1 })).toHaveTextContent( - title - ); - }); - - it('renders an introduction', () => { - render(); - expect(rtlScreen.getByText(intro)).toBeInTheDocument(); - }); -}); diff --git a/src/components/molecules/layout/page-header.tsx b/src/components/molecules/layout/page-header.tsx deleted file mode 100644 index e70d66c..0000000 --- a/src/components/molecules/layout/page-header.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type { FC, ReactNode } from 'react'; -import { Header, Heading } from '../../atoms'; -import styles from './page-header.module.scss'; - -export type PageHeaderProps = { - /** - * Set additional classnames to the header element. - */ - className?: string; - /** - * The page introduction. - */ - intro?: string | ReactNode; - /** - * The page metadata. - */ - meta?: ReactNode; - /** - * The page title. - */ - title: ReactNode; -}; - -/** - * PageHeader component - * - * Render a header element with page title, meta and intro. - */ -export const PageHeader: FC = ({ - className = '', - intro, - meta, - title, -}) => { - const headerClass = `${styles.wrapper} ${className}`; - - const getIntro = () => { - if (typeof intro === 'string') - return ( -
- ); - - return
{intro}
; - }; - - return ( -
-
- - {title} - - {meta} - {intro ? getIntro() : null} -
-
- ); -}; diff --git a/src/components/templates/layout/layout.module.scss b/src/components/templates/layout/layout.module.scss index 03276bf..69c4ef0 100644 --- a/src/components/templates/layout/layout.module.scss +++ b/src/components/templates/layout/layout.module.scss @@ -90,19 +90,6 @@ flex: 1; } -.article { - &--grid { - @extend %grid; - - grid-auto-flow: column dense; - align-items: baseline; - } - - &--padding { - padding-bottom: var(--spacing-lg); - } -} - .footer { display: flex; flex-flow: column wrap; diff --git a/src/components/templates/layout/layout.test.tsx b/src/components/templates/layout/layout.test.tsx index 6a257f0..d3abe1d 100644 --- a/src/components/templates/layout/layout.test.tsx +++ b/src/components/templates/layout/layout.test.tsx @@ -1,5 +1,5 @@ import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; +import { render, screen as rtlScreen } from '../../../../tests/utils'; import { Layout } from './layout'; const body = @@ -8,28 +8,28 @@ const body = describe('Layout', () => { it('renders the website header', () => { render({body}); - expect(screen.getByRole('banner')).toBeInTheDocument(); + expect(rtlScreen.getByRole('banner')).toBeInTheDocument(); }); it('renders the website main content', () => { render({body}); - expect(screen.getByRole('main')).toBeInTheDocument(); + expect(rtlScreen.getByRole('main')).toBeInTheDocument(); }); it('renders the website footer', () => { render({body}); - expect(screen.getByRole('contentinfo')).toBeInTheDocument(); + expect(rtlScreen.getByRole('contentinfo')).toBeInTheDocument(); }); it('renders a skip to content link', () => { render({body}); expect( - screen.getByRole('link', { name: 'Skip to content' }) + rtlScreen.getByRole('link', { name: 'Skip to content' }) ).toBeInTheDocument(); }); - it('renders an article', () => { + it('renders its body', () => { render({body}); - expect(screen.getByRole('article')).toHaveTextContent(body); + expect(rtlScreen.getByText(body)).toBeInTheDocument(); }); }); diff --git a/src/components/templates/layout/layout.tsx b/src/components/templates/layout/layout.tsx index 055b1a1..953b0db 100644 --- a/src/components/templates/layout/layout.tsx +++ b/src/components/templates/layout/layout.tsx @@ -65,14 +65,6 @@ export type LayoutProps = { * @default false */ isHome?: boolean; - /** - * Determine if article has a comments section. - */ - withExtraPadding?: boolean; - /** - * Determine if article should use grid. Default: false. - */ - useGrid?: boolean; }; /** @@ -80,17 +72,10 @@ export type LayoutProps = { * * Render the base layout used by all pages. */ -export const Layout: FC = ({ - children, - withExtraPadding = false, - isHome, - useGrid = false, -}) => { +export const Layout: FC = ({ children, isHome }) => { const router = useRouter(); const intl = useIntl(); const { baseline, copyright, locales, name, url } = CONFIG; - const articleGridClass = useGrid ? 'article--grid' : ''; - const articleCommentsClass = withExtraPadding ? 'article--padding' : ''; const skipToContent = intl.formatMessage({ defaultMessage: 'Skip to content', @@ -455,11 +440,7 @@ export const Layout: FC = ({
-
- {children} -
+ {children}