aboutsummaryrefslogtreecommitdiffstats
path: root/src/pages
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-10 19:37:51 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:14:41 +0100
commitc87c615b5866b8a8f361eeb0764bfdea85740e90 (patch)
treec27bda05fd96bbe3154472e170ba1abd5f9ea499 /src/pages
parent15522ec9146f6f1956620355c44dea2a6a75b67c (diff)
refactor(components): replace Meta component with MetaList
It removes items complexity by allowing consumers to use any label/value association. Translations should also be defined by the consumer. Each item can now be configured separately (borders, layout...).
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/article/[slug].tsx127
-rw-r--r--src/pages/blog/index.tsx25
-rw-r--r--src/pages/blog/page/[number].tsx25
-rw-r--r--src/pages/cv.tsx44
-rw-r--r--src/pages/index.tsx26
-rw-r--r--src/pages/mentions-legales.tsx47
-rw-r--r--src/pages/projets/[slug].tsx168
-rw-r--r--src/pages/projets/index.tsx20
-rw-r--r--src/pages/recherche/index.tsx25
-rw-r--r--src/pages/sujet/[slug].tsx76
-rw-r--r--src/pages/thematique/[slug].tsx64
11 files changed, 552 insertions, 95 deletions
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index acb80b2..bce493b 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -12,9 +12,9 @@ import {
getLayout,
Link,
PageLayout,
- type PageLayoutProps,
Sharing,
Spinner,
+ type MetaItemData,
} from '../../components';
import {
getAllArticlesSlugs,
@@ -26,6 +26,7 @@ import type { Article, NextPageWithLayout, SingleComment } from '../../types';
import { ROUTES } from '../../utils/constants';
import {
getBlogSchema,
+ getFormattedDate,
getSchemaJson,
getSinglePageSchema,
getWebPageSchema,
@@ -82,37 +83,113 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({
const { content, id, intro, meta, title } = article;
const { author, commentsCount, cover, dates, seo, thematics, topics } = meta;
- const headerMeta: PageLayoutProps['headerMeta'] = {
- author: author?.name,
- 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>
- )),
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
};
+ const headerMeta: (MetaItemData | undefined)[] = [
+ author
+ ? {
+ id: 'author',
+ label: intl.formatMessage({
+ defaultMessage: 'Written by:',
+ description: 'ArticlePage: author label',
+ id: 'MJbZfX',
+ }),
+ value: author.name,
+ }
+ : undefined,
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'ArticlePage: publication date label',
+ id: 'RecdwX',
+ }),
+ value: getDate(dates.publication),
+ },
+ dates.update && dates.publication !== dates.update
+ ? {
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'ArticlePage: update date label',
+ id: 'ZAqGZ6',
+ }),
+ value: getDate(dates.update),
+ }
+ : undefined,
+ {
+ id: 'reading-time',
+ label: intl.formatMessage({
+ defaultMessage: 'Reading time:',
+ description: 'ArticlePage: reading time label',
+ id: 'Gw7X3x',
+ }),
+ value: readingTime,
+ },
+ thematics
+ ? {
+ id: 'thematics',
+ label: intl.formatMessage({
+ defaultMessage: 'Thematics:',
+ description: 'ArticlePage: thematics meta label',
+ id: 'CvOqoh',
+ }),
+ value: thematics.map((thematic) => {
+ return {
+ id: `thematic-${thematic.id}`,
+ value: (
+ <Link key={thematic.id} href={thematic.url}>
+ {thematic.name}
+ </Link>
+ ),
+ };
+ }),
+ }
+ : undefined,
+ ];
+ const filteredHeaderMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
+
const footerMetaLabel = intl.formatMessage({
defaultMessage: 'Read more articles about:',
description: 'ArticlePage: footer topics list label',
id: '50xc4o',
});
- const footerMeta: PageLayoutProps['footerMeta'] = {
- custom: topics && {
- label: footerMetaLabel,
- value: topics.map((topic) => (
- <ButtonLink className={styles.btn} key={topic.id} to={topic.url}>
- {topic.logo ? <NextImage {...topic.logo} /> : null} {topic.name}
- </ButtonLink>
- )),
- },
- };
+ const footerMeta: MetaItemData[] = topics
+ ? [
+ {
+ id: 'more-about',
+ label: footerMetaLabel,
+ value: topics.map((topic) => {
+ return {
+ id: `topic--${topic.id}`,
+ value: (
+ <ButtonLink
+ className={styles.btn}
+ key={topic.id}
+ to={topic.url}
+ >
+ {topic.logo ? <NextImage {...topic.logo} /> : null}{' '}
+ {topic.name}
+ </ButtonLink>
+ ),
+ };
+ }),
+ },
+ ]
+ : [];
const webpageSchema = getWebPageSchema({
description: intro,
@@ -208,7 +285,7 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({
breadcrumbSchema={breadcrumbSchema}
comments={commentsData}
footerMeta={footerMeta}
- headerMeta={headerMeta}
+ headerMeta={filteredHeaderMeta}
id={id as number}
intro={intro}
title={title}
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index 0241a5d..5c64e6d 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -9,6 +9,7 @@ import {
getLayout,
Heading,
LinksListWidget,
+ type MetaItemData,
Notice,
PageLayout,
PostsList,
@@ -134,6 +135,28 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
});
const postsListBaseUrl = `${ROUTES.BLOG}/page/`;
+ const headerMeta: MetaItemData[] = totalArticles
+ ? [
+ {
+ id: 'posts-count',
+ label: intl.formatMessage({
+ defaultMessage: 'Total:',
+ description: 'Page: total label',
+ id: 'kNBXyK',
+ }),
+ value: intl.formatMessage(
+ {
+ defaultMessage:
+ '{postsCount, plural, =0 {No articles} one {# article} other {# articles}}',
+ description: 'Page: posts count meta',
+ id: 'RvGb2c',
+ },
+ { postsCount: totalArticles }
+ ),
+ },
+ ]
+ : [];
+
return (
<>
<Head>
@@ -157,7 +180,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
title={title}
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={{ total: totalArticles }}
+ headerMeta={headerMeta}
widgets={[
<LinksListWidget
heading={
diff --git a/src/pages/blog/page/[number].tsx b/src/pages/blog/page/[number].tsx
index 15d7245..58cf7b9 100644
--- a/src/pages/blog/page/[number].tsx
+++ b/src/pages/blog/page/[number].tsx
@@ -9,6 +9,7 @@ import {
getLayout,
Heading,
LinksListWidget,
+ type MetaItemData,
PageLayout,
PostsList,
} from '../../../components';
@@ -132,6 +133,28 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
});
const postsListBaseUrl = `${ROUTES.BLOG}/page/`;
+ const headerMeta: MetaItemData[] = totalArticles
+ ? [
+ {
+ id: 'posts-count',
+ label: intl.formatMessage({
+ defaultMessage: 'Total:',
+ description: 'Page: total label',
+ id: 'kNBXyK',
+ }),
+ value: intl.formatMessage(
+ {
+ defaultMessage:
+ '{postsCount, plural, =0 {No articles} one {# article} other {# articles}}',
+ description: 'Page: posts count meta',
+ id: 'RvGb2c',
+ },
+ { postsCount: totalArticles }
+ ),
+ },
+ ]
+ : [];
+
return (
<>
<Head>
@@ -155,7 +178,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
title={pageTitleWithPageNumber}
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={{ total: totalArticles }}
+ headerMeta={headerMeta}
widgets={[
<LinksListWidget
heading={
diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx
index 206c7f5..652b913 100644
--- a/src/pages/cv.tsx
+++ b/src/pages/cv.tsx
@@ -18,14 +18,15 @@ import {
List,
PageLayout,
SocialMedia,
- type MetaData,
ListItem,
+ type MetaItemData,
} from '../components';
import CVContent, { data, meta } from '../content/pages/cv.mdx';
import styles from '../styles/pages/cv.module.scss';
import type { NextPageWithLayout } from '../types';
import { PERSONAL_LINKS, ROUTES } from '../utils/constants';
import {
+ getFormattedDate,
getSchemaJson,
getSinglePageSchema,
getWebPageSchema,
@@ -152,16 +153,43 @@ const CVPage: NextPageWithLayout = () => {
id: '+Dre5J',
});
- const headerMeta: MetaData = {
- publication: {
- date: dates.publication,
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
+ };
+
+ const headerMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'Page: publication date label',
+ id: '4QbTDq',
+ }),
+ value: getDate(dates.publication),
},
- update: dates.update
+ dates.update
? {
- date: dates.update,
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'Page: update date label',
+ id: 'Ez8Qim',
+ }),
+ value: getDate(dates.update),
}
: undefined,
- };
+ ];
+ const filteredMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
const { website } = useSettings();
const cvCaption = intl.formatMessage(
@@ -267,7 +295,7 @@ const CVPage: NextPageWithLayout = () => {
<PageLayout
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={headerMeta}
+ headerMeta={filteredMeta}
intro={intro}
title={title}
widgets={widgets}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index d94160f..cdc51c5 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable max-statements */
import type { MDXComponents } from 'mdx/types';
import type { GetStaticProps } from 'next';
import Head from 'next/head';
@@ -26,7 +27,11 @@ import { getArticlesCard } from '../services/graphql';
import styles from '../styles/pages/home.module.scss';
import type { ArticleCard, NextPageWithLayout } from '../types';
import { PERSONAL_LINKS, ROUTES } from '../utils/constants';
-import { getSchemaJson, getWebPageSchema } from '../utils/helpers';
+import {
+ getFormattedDate,
+ getSchemaJson,
+ getWebPageSchema,
+} from '../utils/helpers';
import { loadTranslation, type Messages } from '../utils/helpers/server';
import { useBreadcrumb, useSettings } from '../utils/hooks';
@@ -279,6 +284,11 @@ type HomeProps = {
*/
const HomePage: NextPageWithLayout<HomeProps> = ({ recentPosts }) => {
const intl = useIntl();
+ const publicationDate = intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'HomePage: publication date label',
+ id: 'pT5nHk',
+ });
const { schema: breadcrumbSchema } = useBreadcrumb({
title: '',
url: `/`,
@@ -291,10 +301,22 @@ const HomePage: NextPageWithLayout<HomeProps> = ({ recentPosts }) => {
*/
const getRecentPosts = (): JSX.Element => {
const posts: CardsListItem[] = recentPosts.map((post) => {
+ const isoDate = new Date(`${post.dates.publication}`).toISOString();
+
return {
cover: post.cover,
id: post.slug,
- meta: { publication: { date: post.dates.publication } },
+ meta: [
+ {
+ id: 'publication-date',
+ label: publicationDate,
+ value: (
+ <time dateTime={isoDate}>
+ {getFormattedDate(post.dates.publication)}
+ </time>
+ ),
+ },
+ ],
title: post.title,
url: `${ROUTES.ARTICLE}/${post.slug}`,
};
diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx
index 810d9ec..25c2dd9 100644
--- a/src/pages/mentions-legales.tsx
+++ b/src/pages/mentions-legales.tsx
@@ -1,20 +1,23 @@
+/* eslint-disable max-statements */
import type { MDXComponents } from 'mdx/types';
import type { GetStaticProps } from 'next';
import Head from 'next/head';
import NextImage, { type ImageProps as NextImageProps } from 'next/image';
import { useRouter } from 'next/router';
import Script from 'next/script';
+import { useIntl } from 'react-intl';
import {
getLayout,
Link,
PageLayout,
- type MetaData,
Figure,
+ type MetaItemData,
} from '../components';
import LegalNoticeContent, { meta } from '../content/pages/legal-notice.mdx';
import type { NextPageWithLayout } from '../types';
import { ROUTES } from '../utils/constants';
import {
+ getFormattedDate,
getSchemaJson,
getSinglePageSchema,
getWebPageSchema,
@@ -37,22 +40,50 @@ const components: MDXComponents = {
* Legal Notice page.
*/
const LegalNoticePage: NextPageWithLayout = () => {
+ const intl = useIntl();
const { dates, intro, seo, title } = meta;
const { items: breadcrumbItems, schema: breadcrumbSchema } = useBreadcrumb({
title,
url: ROUTES.LEGAL_NOTICE,
});
- const headerMeta: MetaData = {
- publication: {
- date: dates.publication,
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
+ };
+
+ const headerMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'Page: publication date label',
+ id: '4QbTDq',
+ }),
+ value: getDate(dates.publication),
},
- update: dates.update
+ dates.update
? {
- date: dates.update,
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'Page: update date label',
+ id: 'Ez8Qim',
+ }),
+ value: getDate(dates.update),
}
: undefined,
- };
+ ];
+ const filteredMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
const { website } = useSettings();
const { asPath } = useRouter();
@@ -82,7 +113,7 @@ const LegalNoticePage: NextPageWithLayout = () => {
<PageLayout
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={headerMeta}
+ headerMeta={filteredMeta}
intro={intro}
title={title}
withToC={true}
diff --git a/src/pages/projets/[slug].tsx b/src/pages/projets/[slug].tsx
index 0b94a4e..6ef3df5 100644
--- a/src/pages/projets/[slug].tsx
+++ b/src/pages/projets/[slug].tsx
@@ -14,21 +14,22 @@ import {
getLayout,
Link,
Overview,
- type OverviewMeta,
PageLayout,
Sharing,
SocialLink,
Spinner,
- type MetaData,
Heading,
List,
ListItem,
Figure,
+ type MetaItemData,
+ type MetaValues,
} from '../../components';
import styles from '../../styles/pages/project.module.scss';
import type { NextPageWithLayout, ProjectPreview, Repos } from '../../types';
import { ROUTES } from '../../utils/constants';
import {
+ getFormattedDate,
getSchemaJson,
getSinglePageSchema,
getWebPageSchema,
@@ -166,22 +167,52 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => {
url: `${website.url}${asPath}`,
};
- const headerMeta: MetaData = {
- publication: { date: dates.publication },
- update:
- dates.update && dates.update !== dates.publication
- ? { date: dates.update }
- : undefined,
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
};
+ const headerMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'ProjectsPage: publication date label',
+ id: 'HxZvY4',
+ }),
+ value: getDate(dates.publication),
+ },
+ dates.update && dates.update !== dates.publication
+ ? {
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'ProjectsPage: update date label',
+ id: 'wQrvgw',
+ }),
+ value: getDate(dates.update),
+ }
+ : undefined,
+ ];
+ const filteredHeaderMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
+
/**
* Retrieve the repositories links.
*
* @param {Repos} repositories - A repositories object.
- * @returns {JSX.Element[]} - An array of SocialLink.
+ * @returns {MetaValues[]} - An array of meta values.
*/
- const getReposLinks = (repositories: Repos): JSX.Element[] => {
- const links = [];
+ const getReposLinks = (repositories: Repos): MetaValues[] => {
+ const links: MetaValues[] = [];
const githubLabel = intl.formatMessage({
defaultMessage: 'Github profile',
description: 'ProjectsPage: Github profile link',
@@ -194,22 +225,28 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => {
});
if (repositories.github)
- links.push(
- <SocialLink
- icon="Github"
- label={githubLabel}
- url={repositories.github}
- />
- );
+ links.push({
+ id: 'github',
+ value: (
+ <SocialLink
+ icon="Github"
+ label={githubLabel}
+ url={repositories.github}
+ />
+ ),
+ });
if (repositories.gitlab)
- links.push(
- <SocialLink
- icon="Gitlab"
- label={gitlabLabel}
- url={repositories.gitlab}
- />
- );
+ links.push({
+ id: 'gitlab',
+ value: (
+ <SocialLink
+ icon="Gitlab"
+ label={gitlabLabel}
+ url={repositories.gitlab}
+ />
+ ),
+ });
return links;
};
@@ -254,14 +291,75 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => {
);
};
- const overviewData: OverviewMeta = {
- creation: { date: data.created_at },
- update: { date: data.updated_at },
- license,
- popularity: repos?.github && getRepoPopularity(repos.github),
- repositories: repos ? getReposLinks(repos) : undefined,
- technologies,
- };
+ const overviewMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'creation-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Created on:',
+ description: 'ProjectsPage: creation date label',
+ id: 'wVFA4m',
+ }),
+ value: getDate(data.created_at),
+ },
+ {
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'ProjectsPage: update date label',
+ id: 'wQrvgw',
+ }),
+ value: getDate(data.updated_at),
+ },
+ license
+ ? {
+ id: 'license',
+ label: intl.formatMessage({
+ defaultMessage: 'License:',
+ description: 'ProjectsPage: license label',
+ id: 'VtYzuv',
+ }),
+ value: license,
+ }
+ : undefined,
+ repos?.github
+ ? {
+ id: 'popularity',
+ label: intl.formatMessage({
+ defaultMessage: 'Popularity:',
+ description: 'ProjectsPage: popularity label',
+ id: 'KrNvQi',
+ }),
+ value: getRepoPopularity(repos.github),
+ }
+ : undefined,
+ repos
+ ? {
+ id: 'repositories',
+ label: intl.formatMessage({
+ defaultMessage: 'Repositories:',
+ description: 'ProjectsPage: repositories label',
+ id: 'iDIKb7',
+ }),
+ value: getReposLinks(repos),
+ }
+ : undefined,
+ technologies
+ ? {
+ id: 'technologies',
+ label: intl.formatMessage({
+ defaultMessage: 'Technologies:',
+ description: 'ProjectsPage: technologies label',
+ id: 'RwNZ6p',
+ }),
+ value: technologies.map((techno) => {
+ return { id: techno, value: techno };
+ }),
+ }
+ : undefined,
+ ];
+ const filteredOverviewMeta = overviewMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
const webpageSchema = getWebPageSchema({
description: seo.description,
@@ -306,7 +404,7 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => {
intro={intro}
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={headerMeta}
+ headerMeta={filteredHeaderMeta}
withToC={true}
widgets={[
<Sharing
@@ -325,7 +423,7 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => {
/>,
]}
>
- <Overview cover={cover} meta={overviewData} />
+ <Overview cover={cover} meta={filteredOverviewMeta} />
<ProjectContent components={components} />
</PageLayout>
</>
diff --git a/src/pages/projets/index.tsx b/src/pages/projets/index.tsx
index 97963dd..44354ce 100644
--- a/src/pages/projets/index.tsx
+++ b/src/pages/projets/index.tsx
@@ -1,8 +1,10 @@
+/* eslint-disable max-statements */
import type { MDXComponents } from 'mdx/types';
import type { GetStaticProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
import Script from 'next/script';
+import { useIntl } from 'react-intl';
import {
CardsList,
type CardsListItem,
@@ -44,6 +46,12 @@ const ProjectsPage: NextPageWithLayout<ProjectsPageProps> = ({ projects }) => {
title,
url: ROUTES.PROJECTS,
});
+ const intl = useIntl();
+ const metaLabel = intl.formatMessage({
+ defaultMessage: 'Technologies:',
+ description: 'Meta: technologies label',
+ id: 'ADQmDF',
+ });
const items: CardsListItem[] = projects.map(
({ id, meta: projectMeta, slug, title: projectTitle }) => {
@@ -52,7 +60,17 @@ const ProjectsPage: NextPageWithLayout<ProjectsPageProps> = ({ projects }) => {
return {
cover,
id: id as string,
- meta: { technologies },
+ meta: technologies?.length
+ ? [
+ {
+ id: 'technologies',
+ label: metaLabel,
+ value: technologies.map((techno) => {
+ return { id: techno, value: techno };
+ }),
+ },
+ ]
+ : [],
tagline,
title: projectTitle,
url: `${ROUTES.PROJECTS}/${slug}`,
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index f47e40c..32312ec 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -9,6 +9,7 @@ import {
getLayout,
Heading,
LinksListWidget,
+ type MetaItemData,
Notice,
PageLayout,
PostsList,
@@ -133,6 +134,28 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
getTotalArticles(query.s as string)
);
+ const headerMeta: MetaItemData[] = totalArticles
+ ? [
+ {
+ id: 'posts-count',
+ label: intl.formatMessage({
+ defaultMessage: 'Total:',
+ description: 'Page: total label',
+ id: 'kNBXyK',
+ }),
+ value: intl.formatMessage(
+ {
+ defaultMessage:
+ '{postsCount, plural, =0 {No articles} one {# article} other {# articles}}',
+ description: 'Page: posts count meta',
+ id: 'RvGb2c',
+ },
+ { postsCount: totalArticles }
+ ),
+ },
+ ]
+ : [];
+
/**
* Load more posts handler.
*/
@@ -181,7 +204,7 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
title={title}
breadcrumb={breadcrumbItems}
breadcrumbSchema={breadcrumbSchema}
- headerMeta={{ total: totalArticles }}
+ headerMeta={headerMeta}
widgets={[
<LinksListWidget
heading={
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index 899f9e1..cacc972 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -10,9 +10,9 @@ import {
getLayout,
Heading,
LinksListWidget,
+ type MetaItemData,
PageLayout,
PostsList,
- type MetaData,
} from '../../components';
import {
getAllTopicsSlugs,
@@ -24,6 +24,7 @@ import styles from '../../styles/pages/topic.module.scss';
import type { NextPageWithLayout, PageLink, Topic } from '../../types';
import { ROUTES } from '../../utils/constants';
import {
+ getFormattedDate,
getLinksListItems,
getPageLinkFromRawData,
getPostsWithUrl,
@@ -59,13 +60,74 @@ const TopicPage: NextPageWithLayout<TopicPageProps> = ({
url: `${ROUTES.TOPICS}/${slug}`,
});
- const headerMeta: MetaData = {
- publication: { date: dates.publication },
- update: dates.update ? { date: dates.update } : undefined,
- website: officialWebsite,
- total: articles ? articles.length : undefined,
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
};
+ const headerMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'TopicPage: publication date label',
+ id: 'KV+NMZ',
+ }),
+ value: getDate(dates.publication),
+ },
+ dates.update
+ ? {
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'TopicPage: update date label',
+ id: '9DfuHk',
+ }),
+ value: getDate(dates.update),
+ }
+ : undefined,
+ officialWebsite
+ ? {
+ id: 'website',
+ label: intl.formatMessage({
+ defaultMessage: 'Official website:',
+ description: 'TopicPage: official website label',
+ id: 'zoifQd',
+ }),
+ value: officialWebsite,
+ }
+ : undefined,
+ articles?.length
+ ? {
+ id: 'total',
+ label: intl.formatMessage({
+ defaultMessage: 'Total:',
+ description: 'TopicPage: total label',
+ id: 'tBX4mb',
+ }),
+ value: intl.formatMessage(
+ {
+ defaultMessage:
+ '{postsCount, plural, =0 {No articles} one {# article} other {# articles}}',
+ description: 'TopicPage: posts count meta',
+ id: 'uAL4iW',
+ },
+ { postsCount: articles.length }
+ ),
+ }
+ : undefined,
+ ];
+ const filteredMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
+
const { website } = useSettings();
const { asPath } = useRouter();
const webpageSchema = getWebPageSchema({
@@ -132,7 +194,7 @@ const TopicPage: NextPageWithLayout<TopicPageProps> = ({
breadcrumbSchema={breadcrumbSchema}
title={getPageHeading()}
intro={intro}
- headerMeta={headerMeta}
+ headerMeta={filteredMeta}
widgets={
thematics
? [
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index 95b4780..a5badf3 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -9,9 +9,9 @@ import {
getLayout,
Heading,
LinksListWidget,
+ type MetaItemData,
PageLayout,
PostsList,
- type MetaData,
} from '../../components';
import {
getAllThematicsSlugs,
@@ -22,6 +22,7 @@ import {
import type { NextPageWithLayout, PageLink, Thematic } from '../../types';
import { ROUTES } from '../../utils/constants';
import {
+ getFormattedDate,
getLinksListItems,
getPageLinkFromRawData,
getPostsWithUrl,
@@ -50,12 +51,63 @@ const ThematicPage: NextPageWithLayout<ThematicPageProps> = ({
url: `${ROUTES.THEMATICS.INDEX}/${slug}`,
});
- const headerMeta: MetaData = {
- publication: { date: dates.publication },
- update: dates.update ? { date: dates.update } : undefined,
- total: articles ? articles.length : undefined,
+ /**
+ * Retrieve a formatted date (and time).
+ *
+ * @param {string} date - A date string.
+ * @returns {JSX.Element} The formatted date wrapped in a time element.
+ */
+ const getDate = (date: string): JSX.Element => {
+ const isoDate = new Date(`${date}`).toISOString();
+
+ return <time dateTime={isoDate}>{getFormattedDate(date)}</time>;
};
+ const headerMeta: (MetaItemData | undefined)[] = [
+ {
+ id: 'publication-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Published on:',
+ description: 'ThematicPage: publication date label',
+ id: 'UTGhUU',
+ }),
+ value: getDate(dates.publication),
+ },
+ dates.update
+ ? {
+ id: 'update-date',
+ label: intl.formatMessage({
+ defaultMessage: 'Updated on:',
+ description: 'ThematicPage: update date label',
+ id: '24FIsG',
+ }),
+ value: getDate(dates.update),
+ }
+ : undefined,
+ articles
+ ? {
+ id: 'total',
+ label: intl.formatMessage({
+ defaultMessage: 'Total:',
+ description: 'ThematicPage: total label',
+ id: 'lHkta9',
+ }),
+ value: intl.formatMessage(
+ {
+ defaultMessage:
+ '{postsCount, plural, =0 {No articles} one {# article} other {# articles}}',
+ description: 'ThematicPage: posts count meta',
+ id: 'iv3Ex1',
+ },
+ { postsCount: articles.length }
+ ),
+ }
+ : undefined,
+ ];
+ const filteredMeta = headerMeta.filter(
+ (item): item is MetaItemData => !!item
+ );
+
const { website } = useSettings();
const { asPath } = useRouter();
const webpageSchema = getWebPageSchema({
@@ -114,7 +166,7 @@ const ThematicPage: NextPageWithLayout<ThematicPageProps> = ({
breadcrumbSchema={breadcrumbSchema}
title={title}
intro={intro}
- headerMeta={headerMeta}
+ headerMeta={filteredMeta}
widgets={
topics
? [