aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/atoms/layout
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-04-11 18:50:20 +0200
committerArmand Philippot <git@armandphilippot.com>2022-04-11 18:50:20 +0200
commita7adae1a2376082841053c91508b1c23dc951b74 (patch)
tree07ef9ae47b00f2ce2cf9432f3300974171071bb3 /src/components/atoms/layout
parent6a898c510f5c9b5469f639472970d1fefe9766ca (diff)
chore: add a Copyright component
Diffstat (limited to 'src/components/atoms/layout')
-rw-r--r--src/components/atoms/layout/copyright.module.scss32
-rw-r--r--src/components/atoms/layout/copyright.stories.tsx55
-rw-r--r--src/components/atoms/layout/copyright.test.tsx32
-rw-r--r--src/components/atoms/layout/copyright.tsx59
4 files changed, 178 insertions, 0 deletions
diff --git a/src/components/atoms/layout/copyright.module.scss b/src/components/atoms/layout/copyright.module.scss
new file mode 100644
index 0000000..a0e5347
--- /dev/null
+++ b/src/components/atoms/layout/copyright.module.scss
@@ -0,0 +1,32 @@
+@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
new file mode 100644
index 0000000..3b315fa
--- /dev/null
+++ b/src/components/atoms/layout/copyright.stories.tsx
@@ -0,0 +1,55 @@
+import CCBySA from '@components/atoms/icons/cc-by-sa';
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import { IntlProvider } from 'react-intl';
+import CopyrightComponent from './copyright';
+
+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<typeof CopyrightComponent>;
+
+const Template: ComponentStory<typeof CopyrightComponent> = (args) => (
+ <IntlProvider locale="en">
+ <CopyrightComponent {...args} />
+ </IntlProvider>
+);
+
+export const Copyright = Template.bind({});
+Copyright.args = {
+ dates: {
+ start: '2012',
+ end: '2022',
+ },
+ icon: <CCBySA />,
+ owner: 'Your name',
+};
diff --git a/src/components/atoms/layout/copyright.test.tsx b/src/components/atoms/layout/copyright.test.tsx
new file mode 100644
index 0000000..6bfe612
--- /dev/null
+++ b/src/components/atoms/layout/copyright.test.tsx
@@ -0,0 +1,32 @@
+import CCBySA from '@components/atoms/icons/cc-by-sa';
+import { render, screen } from '@test-utils';
+import Copyright from './copyright';
+
+const dates = {
+ start: '2012',
+ end: '2022',
+};
+const icon = <CCBySA />;
+const owner = 'Your name';
+
+describe('Copyright', () => {
+ it('renders the copyright owner', () => {
+ render(<Copyright dates={dates} icon={icon} owner={owner} />);
+ expect(screen.getByText(owner)).toBeInTheDocument();
+ });
+
+ it('renders the copyright start date', () => {
+ render(<Copyright dates={dates} icon={icon} owner={owner} />);
+ expect(screen.getByText(dates.start)).toBeInTheDocument();
+ });
+
+ it('renders the copyright end date', () => {
+ render(<Copyright dates={dates} icon={icon} owner={owner} />);
+ expect(screen.getByText(dates.end)).toBeInTheDocument();
+ });
+
+ it('renders the copyright icon', () => {
+ render(<Copyright dates={dates} icon={icon} owner={owner} />);
+ expect(screen.getByTitle('CC BY SA')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/atoms/layout/copyright.tsx b/src/components/atoms/layout/copyright.tsx
new file mode 100644
index 0000000..76252ee
--- /dev/null
+++ b/src/components/atoms/layout/copyright.tsx
@@ -0,0 +1,59 @@
+import { ReactNode, VFC } from 'react';
+import styles from './copyright.module.scss';
+
+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).
+ */
+const Copyright: VFC<CopyrightProps> = ({ owner, dates, icon }) => {
+ const getFormattedDate = (date: string) => {
+ const datetime = new Date(date).toISOString();
+
+ return <time dateTime={datetime}>{date}</time>;
+ };
+
+ return (
+ <div className={styles.wrapper}>
+ <span className={styles.owner}>{owner}</span>
+ {icon}
+ {getFormattedDate(dates.start)}
+ {dates.end ? (
+ <>
+ <span>-</span>
+ {getFormattedDate(dates.end)}
+ </>
+ ) : (
+ ''
+ )}
+ </div>
+ );
+};
+
+export default Copyright;