aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/Form
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-01-03 15:32:01 +0100
committerArmand Philippot <git@armandphilippot.com>2022-01-03 15:32:01 +0100
commitd76e7c054e51471c908707634f5dbdcd3422b8d9 (patch)
tree6d74a0cdc8c21df22fbbaf087c56ed4e07a905ce /src/components/Form
parentf9276790f55bd9d528512e6fe647774b67860dd0 (diff)
chore: add line numbers to all prism blocks and translate copy button
Diffstat (limited to 'src/components/Form')
0 files changed, 0 insertions, 0 deletions
id='n89' href='#n89'>89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
import ButtonLink from '@components/atoms/buttons/button-link';
import Heading, { type HeadingLevel } from '@components/atoms/headings/heading';
import Arrow from '@components/atoms/icons/arrow';
import Link from '@components/atoms/links/link';
import ResponsiveImage, {
  type ResponsiveImageProps,
} from '@components/molecules/images/responsive-image';
import Meta, { type MetaData } from '@components/molecules/layout/meta';
import { type Dates } from '@ts/types/app';
import useReadingTime from '@utils/hooks/use-reading-time';
import { FC, ReactNode } from 'react';
import { useIntl } from 'react-intl';
import styles from './summary.module.scss';

export type Cover = Pick<
  ResponsiveImageProps,
  'alt' | 'src' | 'width' | 'height'
>;

export type SummaryMetaLink = {
  id: number | string;
  name: string;
  url: string;
};

export type SummaryMetaReadingTime = {
  wordsCount: number;
  onlyMinutes?: boolean;
};

export type SummaryMeta = {
  author?: string;
  commentsCount?: number;
  dates: Dates;
  readingTime: SummaryMetaReadingTime;
  thematics?: SummaryMetaLink[];
  topics?: SummaryMetaLink[];
};

export type SummaryProps = {
  /**
   * The post cover.
   */
  cover?: Cover;
  /**
   * The post excerpt.
   */
  excerpt: string;
  /**
   * The post meta.
   */
  meta: SummaryMeta;
  /**
   * The post title.
   */
  title: string;
  /**
   * The heading level (hn).
   */
  titleLevel?: HeadingLevel;
  /**
   * The post url.
   */
  url: string;
};

/**
 * Summary component
 *
 * Render a page summary.
 */
const Summary: FC<SummaryProps> = ({
  cover,
  excerpt,
  meta,
  title,
  titleLevel = 2,
  url,
}) => {
  const intl = useIntl();
  const readMore = intl.formatMessage(
    {
      defaultMessage: 'Read more<a11y> about {title}</a11y>',
      description: 'Summary: read more link',
      id: 'Zpgv+f',
    },
    {
      title,
      a11y: (chunks: ReactNode) => (
        <span className="screen-reader-text">{chunks}</span>
      ),
    }
  );
  const { wordsCount, onlyMinutes } = meta.readingTime;
  const readingTime = useReadingTime(wordsCount, onlyMinutes);

  const getMeta = (data: SummaryMeta): MetaData => {
    const { author, commentsCount, dates, thematics, topics } = data;

    return {
      author,
      publication: { date: dates.publication },
      update:
        dates.update && dates.publication !== dates.update
          ? { date: dates.update }
          : undefined,
      readingTime,
      thematics: thematics?.map((thematic) => (
        <Link key={thematic.id} href={thematic.url}>
          {thematic.name}
        </Link>
      )),
      topics: topics?.map((topic) => (
        <Link key={topic.id} href={topic.url}>
          {topic.name}
        </Link>
      )),
      comments: {
        about: title,
        count: commentsCount || 0,
        target: `${url}#comments`,
      },
    };
  };

  return (
    <article className={styles.wrapper}>
      {cover && <ResponsiveImage className={styles.cover} {...cover} />}
      <header className={styles.header}>
        <Link href={url} className={styles.link}>
          <Heading level={titleLevel} className={styles.title}>
            {title}
          </Heading>
        </Link>
      </header>
      <div className={styles.body}>
        {typeof excerpt === 'string' ? (
          <div dangerouslySetInnerHTML={{ __html: excerpt }} />
        ) : (
          excerpt
        )}
        <ButtonLink target={url} className={styles['read-more']}>
          <>
            {readMore}
            <Arrow direction="right" className={styles.icon} />
          </>
        </ButtonLink>
      </div>
      <footer className={styles.footer}>
        <Meta
          data={getMeta(meta)}
          layout="column"
          itemsLayout="stacked"
          withSeparator={false}
          className={styles.meta}
          groupClassName={styles.meta__item}
        />
      </footer>
    </article>
  );
};

export default Summary;