diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-04-21 17:03:45 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-04-21 17:03:45 +0200 |
| commit | 34502bd004c2522a8f2a217da3adf51586d1dec3 (patch) | |
| tree | 548ae3e34d6f8e3d2897a126bb8971a7fe2d278b /src/components/molecules | |
| parent | 2b51960da1bd907f5855869d3eee53565ca7cbfc (diff) | |
chore: add a PageHeader component
Diffstat (limited to 'src/components/molecules')
4 files changed, 233 insertions, 0 deletions
diff --git a/src/components/molecules/layout/page-header.module.scss b/src/components/molecules/layout/page-header.module.scss new file mode 100644 index 0000000..93f7595 --- /dev/null +++ b/src/components/molecules/layout/page-header.module.scss @@ -0,0 +1,63 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/mixins" as mix; +@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 { + @include mix.media("screen") { + @include mix.dimensions("xs") { + font-size: var(--font-size-sm); + } + } +} diff --git a/src/components/molecules/layout/page-header.stories.tsx b/src/components/molecules/layout/page-header.stories.tsx new file mode 100644 index 0000000..6054845 --- /dev/null +++ b/src/components/molecules/layout/page-header.stories.tsx @@ -0,0 +1,103 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import PageHeader from './page-header'; + +/** + * Page Header - Storybook Meta + */ +export default { + title: 'Molecules/Layout/PageHeader', + component: PageHeader, + argTypes: { + 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<typeof PageHeader>; + +const Template: ComponentStory<typeof PageHeader> = (args) => ( + <PageHeader {...args} /> +); + +const meta = { + publication: { name: 'Published on:', value: 'April 9th 2022' }, + categories: { + name: 'Categories:', + value: [ + <a key="category1" href="#"> + Category 1 + </a>, + <a key="category2" href="#"> + Category 2 + </a>, + ], + }, +}; + +/** + * 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, + 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, + title: 'Excepturi nesciunt illum', +}; diff --git a/src/components/molecules/layout/page-header.test.tsx b/src/components/molecules/layout/page-header.test.tsx new file mode 100644 index 0000000..329b54c --- /dev/null +++ b/src/components/molecules/layout/page-header.test.tsx @@ -0,0 +1,18 @@ +import { render, screen } from '@test-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(<PageHeader title={title} intro={intro} />); + expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(title); + }); + + it('renders an introduction', () => { + render(<PageHeader title={title} intro={intro} />); + expect(screen.getByText(intro)).toBeInTheDocument(); + }); +}); diff --git a/src/components/molecules/layout/page-header.tsx b/src/components/molecules/layout/page-header.tsx new file mode 100644 index 0000000..174e246 --- /dev/null +++ b/src/components/molecules/layout/page-header.tsx @@ -0,0 +1,49 @@ +import Heading from '@components/atoms/headings/heading'; +import styles from './page-header.module.scss'; +import Meta, { type MetaMap } from './meta'; +import { FC } from 'react'; + +export type PageHeaderProps = { + /** + * Set additional classnames to the header element. + */ + className?: string; + /** + * The page introduction. + */ + intro?: string; + /** + * The page metadata. + */ + meta?: MetaMap; + /** + * The page title. + */ + title: string; +}; + +/** + * PageHeader component + * + * Render a header element with page title, meta and intro. + */ +const PageHeader: FC<PageHeaderProps> = ({ + className = '', + intro, + meta, + title, +}) => { + return ( + <header className={`${styles.wrapper} ${className}`}> + <div className={styles.body}> + <Heading level={1} className={styles.title} withMargin={false}> + {title} + </Heading> + {meta && <Meta data={meta} className={styles.meta} layout="inline" />} + {intro && <div>{intro}</div>} + </div> + </header> + ); +}; + +export default PageHeader; |
