diff options
Diffstat (limited to 'src/pages')
| -rw-r--r-- | src/pages/article/[slug].tsx | 127 | ||||
| -rw-r--r-- | src/pages/blog/index.tsx | 25 | ||||
| -rw-r--r-- | src/pages/blog/page/[number].tsx | 25 | ||||
| -rw-r--r-- | src/pages/cv.tsx | 44 | ||||
| -rw-r--r-- | src/pages/index.tsx | 26 | ||||
| -rw-r--r-- | src/pages/mentions-legales.tsx | 47 | ||||
| -rw-r--r-- | src/pages/projets/[slug].tsx | 168 | ||||
| -rw-r--r-- | src/pages/projets/index.tsx | 20 | ||||
| -rw-r--r-- | src/pages/recherche/index.tsx | 25 | ||||
| -rw-r--r-- | src/pages/sujet/[slug].tsx | 76 | ||||
| -rw-r--r-- | src/pages/thematique/[slug].tsx | 64 |
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 ? [ |
