aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/molecules')
-rw-r--r--src/components/molecules/layout/meta.stories.tsx57
-rw-r--r--src/components/molecules/layout/meta.test.tsx8
-rw-r--r--src/components/molecules/layout/meta.tsx70
3 files changed, 135 insertions, 0 deletions
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<typeof MetaComponent>;
+
+const Template: ComponentStory<typeof MetaComponent> = (args) => (
+ <MetaComponent {...args} />
+);
+
+const data = {
+ 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>,
+ ],
+ },
+};
+
+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(<Meta data={{}} />);
+ });
+});
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<MetaProps> = ({ 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 <DescriptionList items={getItems(data)} {...props} />;
+};
+
+export default Meta;