aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/layout
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-02 17:01:57 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:14:41 +0100
commit36890cfafeba6e30782df1260d7f9e678c7da4bf (patch)
tree1abe20cf36d60e048b75828dd5516529e504ddd8 /src/components/organisms/layout
parent4f768afe543bbf9e1857c41d03804f8e37ab3512 (diff)
refactor(components): rewrite DescriptionList component
* add a `spacing` prop * replace `layout` prop with `isInline` prop * remove `items` prop (and classNames props) in favor of new components: Description, Group, Term * remove `withSeparator` prop (CSS content is announced by screen readers and Firefox/Safari have no support for alternative text so the consumer should add itself an element with `aria-hidden` if it need a separator) Be aware, Meta component and its consumers can be visually broken, they should be refactored before using them in production.
Diffstat (limited to 'src/components/organisms/layout')
-rw-r--r--src/components/organisms/layout/comment.fixture.ts (renamed from src/components/organisms/layout/comment.fixture.tsx)4
-rw-r--r--src/components/organisms/layout/comment.stories.tsx12
-rw-r--r--src/components/organisms/layout/comment.test.tsx28
-rw-r--r--src/components/organisms/layout/comment.tsx43
-rw-r--r--src/components/organisms/layout/comments-list.tsx11
-rw-r--r--src/components/organisms/layout/overview.module.scss4
-rw-r--r--src/components/organisms/layout/overview.tsx6
-rw-r--r--src/components/organisms/layout/summary.tsx11
8 files changed, 57 insertions, 62 deletions
diff --git a/src/components/organisms/layout/comment.fixture.tsx b/src/components/organisms/layout/comment.fixture.ts
index eee7981..f626be9 100644
--- a/src/components/organisms/layout/comment.fixture.tsx
+++ b/src/components/organisms/layout/comment.fixture.ts
@@ -1,5 +1,5 @@
import { getFormattedDate, getFormattedTime } from '../../../utils/helpers';
-import { CommentProps } from './comment';
+import type { UserCommentProps } from './comment';
export const author = {
avatar: {
@@ -28,7 +28,7 @@ export const saveComment = async () => {
/** Do nothing. */
};
-export const data: CommentProps = {
+export const data: UserCommentProps = {
approved: true,
content,
id,
diff --git a/src/components/organisms/layout/comment.stories.tsx b/src/components/organisms/layout/comment.stories.tsx
index a73ba23..9c33ba3 100644
--- a/src/components/organisms/layout/comment.stories.tsx
+++ b/src/components/organisms/layout/comment.stories.tsx
@@ -1,5 +1,5 @@
-import { ComponentMeta, ComponentStory } from '@storybook/react';
-import { Comment } from './comment';
+import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import { UserComment } from './comment';
import { data } from './comment.fixture';
const saveComment = async () => {
@@ -11,7 +11,7 @@ const saveComment = async () => {
*/
export default {
title: 'Organisms/Layout/Comment',
- component: Comment,
+ component: UserComment,
args: {
canReply: true,
saveComment,
@@ -104,10 +104,10 @@ export default {
},
},
},
-} as ComponentMeta<typeof Comment>;
+} as ComponentMeta<typeof UserComment>;
-const Template: ComponentStory<typeof Comment> = (args) => (
- <Comment {...args} />
+const Template: ComponentStory<typeof UserComment> = (args) => (
+ <UserComment {...args} />
);
/**
diff --git a/src/components/organisms/layout/comment.test.tsx b/src/components/organisms/layout/comment.test.tsx
index 1aa9e4a..b64f84a 100644
--- a/src/components/organisms/layout/comment.test.tsx
+++ b/src/components/organisms/layout/comment.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it } from '@jest/globals';
-import { render, screen } from '../../../../tests/utils';
-import { Comment } from './comment';
+import { render, screen as rtlScreen } from '../../../../tests/utils';
+import { UserComment } from './comment';
import {
author,
data,
@@ -9,40 +9,42 @@ import {
id,
} from './comment.fixture';
-describe('Comment', () => {
+describe('UserComment', () => {
it('renders an avatar', () => {
- render(<Comment canReply={true} {...data} />);
+ render(<UserComment canReply={true} {...data} />);
expect(
- screen.getByRole('img', { name: author.avatar.alt })
+ rtlScreen.getByRole('img', { name: author.avatar.alt })
).toBeInTheDocument();
});
it('renders the author website url', () => {
- render(<Comment canReply={true} {...data} />);
- expect(screen.getByRole('link', { name: author.name })).toHaveAttribute(
+ render(<UserComment canReply={true} {...data} />);
+ expect(rtlScreen.getByRole('link', { name: author.name })).toHaveAttribute(
'href',
author.website
);
});
it('renders a permalink to the comment', () => {
- render(<Comment canReply={true} {...data} />);
+ render(<UserComment canReply={true} {...data} />);
expect(
- screen.getByRole('link', {
+ rtlScreen.getByRole('link', {
name: `${formattedDate} at ${formattedTime}`,
})
).toHaveAttribute('href', `#comment-${id}`);
});
it('renders a reply button', () => {
- render(<Comment canReply={true} {...data} />);
- expect(screen.getByRole('button', { name: 'Reply' })).toBeInTheDocument();
+ render(<UserComment canReply={true} {...data} />);
+ expect(
+ rtlScreen.getByRole('button', { name: 'Reply' })
+ ).toBeInTheDocument();
});
it('does not render a reply button', () => {
- render(<Comment canReply={false} {...data} />);
+ render(<UserComment canReply={false} {...data} />);
expect(
- screen.queryByRole('button', { name: 'Reply' })
+ rtlScreen.queryByRole('button', { name: 'Reply' })
).not.toBeInTheDocument();
});
});
diff --git a/src/components/organisms/layout/comment.tsx b/src/components/organisms/layout/comment.tsx
index e2a42bf..ca209f5 100644
--- a/src/components/organisms/layout/comment.tsx
+++ b/src/components/organisms/layout/comment.tsx
@@ -1,16 +1,17 @@
-import Image from 'next/image';
+/* eslint-disable max-statements */
+import NextImage from 'next/image';
import Script from 'next/script';
-import { FC, useCallback, useState } from 'react';
+import { type FC, useCallback, useState } from 'react';
import { useIntl } from 'react-intl';
-import { type Comment as CommentSchema, type WithContext } from 'schema-dts';
-import { type SingleComment } from '../../../types';
+import type { Comment as CommentSchema, WithContext } from 'schema-dts';
+import type { SingleComment } from '../../../types';
import { useSettings } from '../../../utils/hooks';
import { Button, Link } from '../../atoms';
import { Meta } from '../../molecules';
import { CommentForm, type CommentFormProps } from '../forms';
import styles from './comment.module.scss';
-export type CommentProps = Pick<
+export type UserCommentProps = Pick<
SingleComment,
'approved' | 'content' | 'id' | 'meta' | 'parentId'
> &
@@ -22,11 +23,11 @@ export type CommentProps = Pick<
};
/**
- * Comment component
+ * UserComment component
*
* Render a single comment.
*/
-export const Comment: FC<CommentProps> = ({
+export const UserComment: FC<UserCommentProps> = ({
approved,
canReply = true,
content,
@@ -103,6 +104,9 @@ export const Comment: FC<CommentProps> = ({
text: content,
};
+ const commentWrapperClass = `${styles.wrapper} ${styles['wrapper--comment']}`;
+ const formWrapperClass = `${styles.wrapper} ${styles['wrapper--form']}`;
+
return (
<>
<Script
@@ -110,14 +114,11 @@ export const Comment: FC<CommentProps> = ({
id="schema-comments"
type="application/ld+json"
/>
- <article
- className={`${styles.wrapper} ${styles['wrapper--comment']}`}
- id={`comment-${id}`}
- >
+ <article className={commentWrapperClass} id={`comment-${id}`}>
<header className={styles.header}>
- {author.avatar && (
+ {author.avatar ? (
<div className={styles.avatar}>
- <Image
+ <NextImage
{...props}
alt={author.avatar.alt}
fill
@@ -125,7 +126,7 @@ export const Comment: FC<CommentProps> = ({
style={{ objectFit: 'cover' }}
/>
</div>
- )}
+ ) : null}
{author.website ? (
<Link href={author.website} className={styles.author}>
{author.name}
@@ -143,31 +144,29 @@ export const Comment: FC<CommentProps> = ({
target: `#comment-${id}`,
},
}}
- groupClassName={styles.date__item}
- itemsLayout="inline"
- layout="inline"
+ isInline
/>
<div
className={styles.body}
dangerouslySetInnerHTML={{ __html: content }}
/>
<footer className={styles.footer}>
- {canReply && (
+ {canReply ? (
<Button kind="tertiary" onClick={handleReply}>
{buttonLabel}
</Button>
- )}
+ ) : null}
</footer>
</article>
- {isReplying && (
+ {isReplying ? (
<CommentForm
- className={`${styles.wrapper} ${styles['wrapper--form']}`}
+ className={formWrapperClass}
Notice={Notice}
parentId={id}
saveComment={saveComment}
title={formTitle}
/>
- )}
+ ) : null}
</>
);
};
diff --git a/src/components/organisms/layout/comments-list.tsx b/src/components/organisms/layout/comments-list.tsx
index 103bfb4..af0152a 100644
--- a/src/components/organisms/layout/comments-list.tsx
+++ b/src/components/organisms/layout/comments-list.tsx
@@ -1,14 +1,15 @@
import type { FC } from 'react';
import type { SingleComment } from '../../../types';
import { List, ListItem } from '../../atoms';
-
-// eslint-disable-next-line @typescript-eslint/no-shadow
-import { Comment, type CommentProps } from './comment';
+import { UserComment, type UserCommentProps } from './comment';
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
export type CommentsListDepth = 0 | 1 | 2 | 3 | 4;
-export type CommentsListProps = Pick<CommentProps, 'Notice' | 'saveComment'> & {
+export type CommentsListProps = Pick<
+ UserCommentProps,
+ 'Notice' | 'saveComment'
+> & {
/**
* An array of comments.
*/
@@ -44,7 +45,7 @@ export const CommentsList: FC<CommentsListProps> = ({
return commentsList.map(({ replies, ...comment }) => (
<ListItem key={comment.id}>
- <Comment
+ <UserComment
canReply={!isLastLevel}
Notice={Notice}
saveComment={saveComment}
diff --git a/src/components/organisms/layout/overview.module.scss b/src/components/organisms/layout/overview.module.scss
index e4f6a6a..59ce167 100644
--- a/src/components/organisms/layout/overview.module.scss
+++ b/src/components/organisms/layout/overview.module.scss
@@ -29,6 +29,10 @@
dd {
padding: 0 var(--spacing-2xs);
border: fun.convert-px(1) solid var(--color-border-dark);
+
+ &::before {
+ display: none;
+ }
}
}
}
diff --git a/src/components/organisms/layout/overview.tsx b/src/components/organisms/layout/overview.tsx
index 51920f6..bb319c4 100644
--- a/src/components/organisms/layout/overview.tsx
+++ b/src/components/organisms/layout/overview.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import type { FC } from 'react';
import {
Meta,
type MetaData,
@@ -47,12 +47,10 @@ export const Overview: FC<OverviewProps> = ({
return (
<div className={`${styles.wrapper} ${className}`}>
- {cover && <ResponsiveImage className={styles.cover} {...cover} />}
+ {cover ? <ResponsiveImage className={styles.cover} {...cover} /> : null}
<Meta
className={`${styles.meta} ${metaModifier}`}
data={{ ...remainingMeta, technologies }}
- layout="inline"
- withSeparator={false}
/>
</div>
);
diff --git a/src/components/organisms/layout/summary.tsx b/src/components/organisms/layout/summary.tsx
index 99f6c85..d66af75 100644
--- a/src/components/organisms/layout/summary.tsx
+++ b/src/components/organisms/layout/summary.tsx
@@ -135,16 +135,7 @@ export const Summary: FC<SummaryProps> = ({
</ButtonLink>
</div>
<footer className={styles.footer}>
- <Meta
- className={styles.meta}
- data={getMeta()}
- groupClassName={styles.meta__item}
- // eslint-disable-next-line react/jsx-no-literals -- Layout allowed
- itemsLayout="stacked"
- // eslint-disable-next-line react/jsx-no-literals -- Layout allowed
- layout="column"
- withSeparator={false}
- />
+ <Meta className={styles.meta} data={getMeta()} spacing="xs" />
</footer>
</article>
);