From 62f06c40a4eac6d11f1a93f3b49dfe6c48ce16f8 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 11 Apr 2022 19:24:04 +0200 Subject: chore: add a Meta component --- src/components/molecules/layout/meta.stories.tsx | 57 +++++++++++++++++++ src/components/molecules/layout/meta.test.tsx | 8 +++ src/components/molecules/layout/meta.tsx | 70 ++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/components/molecules/layout/meta.stories.tsx create mode 100644 src/components/molecules/layout/meta.test.tsx create mode 100644 src/components/molecules/layout/meta.tsx (limited to 'src') diff --git a/src/components/molecules/layout/meta.stories.tsx b/src/components/molecules/layout/meta.stories.tsx new file mode 100644 index 0000000..e7a932d --- /dev/null +++ b/src/components/molecules/layout/meta.stories.tsx @@ -0,0 +1,57 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import MetaComponent from './meta'; + +export default { + title: 'Molecules/Layout', + component: MetaComponent, + argTypes: { + className: { + control: { + type: 'text', + }, + description: 'Set additional classnames to the meta wrapper.', + table: { + category: 'Styles', + }, + type: { + name: 'string', + required: false, + }, + }, + meta: { + control: { + type: null, + }, + description: 'The page metadata.', + type: { + name: 'object', + required: true, + value: {}, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const data = { + publication: { name: 'Published on:', value: 'April 9th 2022' }, + categories: { + name: 'Categories:', + value: [ + + Category 1 + , + + Category 2 + , + ], + }, +}; + +export const Meta = Template.bind({}); +Meta.args = { + data, +}; diff --git a/src/components/molecules/layout/meta.test.tsx b/src/components/molecules/layout/meta.test.tsx new file mode 100644 index 0000000..a738bdb --- /dev/null +++ b/src/components/molecules/layout/meta.test.tsx @@ -0,0 +1,8 @@ +import { render } from '@test-utils'; +import Meta from './meta'; + +describe('Meta', () => { + it('renders a Meta component', () => { + render(); + }); +}); diff --git a/src/components/molecules/layout/meta.tsx b/src/components/molecules/layout/meta.tsx new file mode 100644 index 0000000..ace6f89 --- /dev/null +++ b/src/components/molecules/layout/meta.tsx @@ -0,0 +1,70 @@ +import DescriptionList, { + type DescriptionListProps, + type DescriptionListItem, +} from '@components/atoms/lists/description-list'; +import { ReactNode, VFC } from 'react'; + +export type MetaItem = { + /** + * The meta name. + */ + name: string; + /** + * The meta value. + */ + value: ReactNode | ReactNode[]; +}; + +export type MetaMap = { + [key: string]: MetaItem | undefined; +}; + +export type MetaProps = { + /** + * Set additional classnames to the meta wrapper. + */ + className?: string; + /** + * The meta data. + */ + data: MetaMap; + /** + * The meta layout. + */ + layout?: DescriptionListProps['layout']; +}; + +/** + * Meta component + * + * Renders the page metadata. + */ +const Meta: VFC = ({ data, ...props }) => { + /** + * Transform the metadata to description list item format. + * + * @param {MetaMap} items - The meta. + * @returns {DescriptionListItem[]} The formatted description list items. + */ + const getItems = (items: MetaMap): DescriptionListItem[] => { + const listItems: DescriptionListItem[] = Object.entries(items) + .map(([key, item]) => { + if (!item) return; + + const { name, value } = item; + + return { + id: key, + term: name, + value: Array.isArray(value) ? value : [value], + } as DescriptionListItem; + }) + .filter((item): item is DescriptionListItem => !!item); + + return listItems; + }; + + return ; +}; + +export default Meta; -- cgit v1.2.3