summaryrefslogtreecommitdiffstats
path: root/src/pages/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/index.tsx')
-rw-r--r--src/pages/index.tsx327
1 files changed, 221 insertions, 106 deletions
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index ca0a809..6e9c4c6 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,39 +1,59 @@
import FeedIcon from '@assets/images/icon-feed.svg';
-import { ButtonLink } from '@components/Buttons';
-import { ContactIcon } from '@components/Icons';
-import Layout from '@components/Layouts/Layout';
-import { ResponsiveImage } from '@components/MDX';
-import { RecentPosts } from '@components/Widgets';
+import ButtonLink from '@components/atoms/buttons/button-link';
+import Envelop from '@components/atoms/icons/envelop';
+import Column, { type ColumnProps } from '@components/atoms/layout/column';
+import Section, { type SectionProps } from '@components/atoms/layout/section';
+import List, { type ListItem } from '@components/atoms/lists/list';
+import ResponsiveImage, {
+ type ResponsiveImageProps,
+} from '@components/molecules/images/responsive-image';
+import Columns, {
+ type ColumnsProps,
+} from '@components/molecules/layout/columns';
+import CardsList, {
+ type CardsListItem,
+} from '@components/organisms/layout/cards-list';
+import { getLayout } from '@components/templates/layout/layout';
import HomePageContent from '@content/pages/homepage.mdx';
-import { getPublishedPosts } from '@services/graphql/queries';
-import styles from '@styles/pages/Home.module.scss';
-import { NextPageWithLayout, ResponsiveImageProps } from '@ts/types/app';
-import { PostsList } from '@ts/types/blog';
-import { settings } from '@utils/config';
-import { loadTranslation } from '@utils/helpers/i18n';
+import { getArticlesCard } from '@services/graphql/articles';
+import styles from '@styles/pages/home.module.scss';
+import { type ArticleCard, type NextPageWithLayout } from '@ts/types/app';
+import { loadTranslation, type Messages } from '@utils/helpers/i18n';
+import { getSchemaJson, getWebPageSchema } from '@utils/helpers/schema-org';
+import useBreadcrumb from '@utils/hooks/use-breadcrumb';
+import useSettings from '@utils/hooks/use-settings';
import { NestedMDXComponents } from 'mdx/types';
-import { GetStaticProps, GetStaticPropsContext } from 'next';
+import { GetStaticProps } from 'next';
import Head from 'next/head';
import Script from 'next/script';
-import type { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { useIntl } from 'react-intl';
-import { Graph, WebPage } from 'schema-dts';
-type HomePageProps = {
- recentPosts: PostsList;
+type HomeProps = {
+ recentPosts: ArticleCard[];
+ translation?: Messages;
};
-const Home: NextPageWithLayout<HomePageProps> = ({
- recentPosts,
-}: {
- recentPosts: PostsList;
-}) => {
+/**
+ * Home page.
+ */
+const HomePage: NextPageWithLayout<HomeProps> = ({ recentPosts }) => {
const intl = useIntl();
+ const { schema: breadcrumbSchema } = useBreadcrumb({
+ title: '',
+ url: `/`,
+ });
- const CodingLinks = () => {
- return (
- <ul className={styles['links-list']}>
- <li>
+ /**
+ * Retrieve a list of coding links.
+ *
+ * @returns {JSX.Element} - A list of links.
+ */
+ const CodingLinks = (): JSX.Element => {
+ const links: ListItem[] = [
+ {
+ id: 'web-development',
+ value: (
<ButtonLink target="/thematique/developpement-web">
{intl.formatMessage({
defaultMessage: 'Web development',
@@ -41,8 +61,11 @@ const Home: NextPageWithLayout<HomePageProps> = ({
id: 'vkF/RP',
})}
</ButtonLink>
- </li>
- <li>
+ ),
+ },
+ {
+ id: 'projects',
+ value: (
<ButtonLink target="/projets">
{intl.formatMessage({
defaultMessage: 'Projects',
@@ -50,38 +73,65 @@ const Home: NextPageWithLayout<HomePageProps> = ({
id: 'N44SOc',
})}
</ButtonLink>
- </li>
- </ul>
- );
+ ),
+ },
+ ];
+
+ return <List kind="flex" items={links} className={styles.list} />;
};
- const ColdarkRepos = () => {
- return (
- <ul className={styles['links-list']}>
- <li>
+ /**
+ * Retrieve a list of Coldark repositories.
+ *
+ * @returns {JSX.Element} - A list of links.
+ */
+ const ColdarkRepos = (): JSX.Element => {
+ const links: ListItem[] = [
+ {
+ id: 'coldark-github',
+ value: (
<ButtonLink
target="https://github.com/ArmandPhilippot/coldark"
- isExternal={true}
+ external={true}
>
- Github
+ {intl.formatMessage({
+ defaultMessage: 'Github',
+ description: 'HomePage: Github link',
+ id: '3f3PzH',
+ })}
</ButtonLink>
- </li>
- <li>
+ ),
+ },
+ {
+ id: 'coldark-gitlab',
+ value: (
<ButtonLink
target="https://gitlab.com/ArmandPhilippot/coldark"
- isExternal={true}
+ external={true}
>
- Gitlab
+ {intl.formatMessage({
+ defaultMessage: 'Gitlab',
+ description: 'HomePage: Gitlab link',
+ id: '7AnwZ7',
+ })}
</ButtonLink>
- </li>
- </ul>
- );
+ ),
+ },
+ ];
+
+ return <List kind="flex" items={links} className={styles.list} />;
};
- const LibreLinks = () => {
- return (
- <ul className={styles['links-list']}>
- <li>
+ /**
+ * Retrieve a list of links related to Free thematic.
+ *
+ * @returns {JSX.Element} - A list of links.
+ */
+ const LibreLinks = (): JSX.Element => {
+ const links: ListItem[] = [
+ {
+ id: 'free',
+ value: (
<ButtonLink target="/thematique/libre">
{intl.formatMessage({
defaultMessage: 'Free',
@@ -89,8 +139,11 @@ const Home: NextPageWithLayout<HomePageProps> = ({
id: 'w8GrOf',
})}
</ButtonLink>
- </li>
- <li>
+ ),
+ },
+ {
+ id: 'linux',
+ value: (
<ButtonLink target="/thematique/linux">
{intl.formatMessage({
defaultMessage: 'Linux',
@@ -98,15 +151,23 @@ const Home: NextPageWithLayout<HomePageProps> = ({
id: 'jASD7k',
})}
</ButtonLink>
- </li>
- </ul>
- );
+ ),
+ },
+ ];
+
+ return <List kind="flex" items={links} className={styles.list} />;
};
- const ShaarliLink = () => {
- return (
- <ul className={styles['links-list']}>
- <li>
+ /**
+ * Retrieve the Shaarli link.
+ *
+ * @returns {JSX.Element} - A list of links
+ */
+ const ShaarliLink = (): JSX.Element => {
+ const links: ListItem[] = [
+ {
+ id: 'shaarli',
+ value: (
<ButtonLink target="https://shaarli.armandphilippot.com/">
{intl.formatMessage({
defaultMessage: 'Shaarli',
@@ -114,59 +175,127 @@ const Home: NextPageWithLayout<HomePageProps> = ({
id: 'i5L19t',
})}
</ButtonLink>
- </li>
- </ul>
- );
+ ),
+ },
+ ];
+
+ return <List kind="flex" items={links} className={styles.list} />;
};
- const MoreLinks = () => {
- return (
- <ul className={styles['links-list']}>
- <li>
+ /**
+ * Retrieve the additional links.
+ *
+ * @returns {JSX.Element} - A list of links.
+ */
+ const MoreLinks = (): JSX.Element => {
+ const links: ListItem[] = [
+ {
+ id: 'contact-me',
+ value: (
<ButtonLink target="/contact">
- <ContactIcon />
+ <Envelop className={styles.icon} />
{intl.formatMessage({
defaultMessage: 'Contact me',
description: 'HomePage: contact button text',
id: 'sO/Iwj',
})}
</ButtonLink>
- </li>
- <li>
+ ),
+ },
+ {
+ id: 'rss-feed',
+ value: (
<ButtonLink target="/feed">
- <FeedIcon className={styles['icon--feed']} />
+ <FeedIcon className={`${styles.icon} ${styles['icon--feed']}`} />
{intl.formatMessage({
defaultMessage: 'Subscribe',
description: 'HomePage: RSS feed subscription text',
id: 'T4YA64',
})}
</ButtonLink>
- </li>
- </ul>
+ ),
+ },
+ ];
+
+ return <List kind="flex" items={links} className={styles.list} />;
+ };
+
+ /**
+ * Get a cards list of recent posts.
+ *
+ * @returns {JSX.Element} - The cards list.
+ */
+ const getRecentPosts = (): JSX.Element => {
+ const posts: CardsListItem[] = recentPosts.map((post) => {
+ return {
+ cover: post.cover,
+ id: post.slug,
+ meta: { publication: { date: post.dates.publication } },
+ title: post.title,
+ url: `/article/${post.slug}`,
+ };
+ });
+
+ return (
+ <CardsList
+ items={posts}
+ titleLevel={3}
+ className={`${styles.list} ${styles['list--cards']}`}
+ />
);
};
- const getRecentPosts = () => {
- return <RecentPosts posts={recentPosts} />;
+ /**
+ * Create the page sections.
+ *
+ * @param {object} obj - An object containing the section body.
+ * @param {ReactElement[]} obj.children - The section body.
+ * @returns {JSX.Element} A section element.
+ */
+ const getSection = ({
+ children,
+ variant,
+ }: {
+ children: ReactElement[];
+ variant: SectionProps['variant'];
+ }): JSX.Element => {
+ const [headingEl, ...content] = children;
+ const title = headingEl.props.children;
+
+ return (
+ <Section
+ title={title}
+ content={content}
+ variant={variant}
+ className={styles.section}
+ />
+ );
};
const components: NestedMDXComponents = {
CodingLinks: CodingLinks,
ColdarkRepos: ColdarkRepos,
- Image: (props: ResponsiveImageProps) => ResponsiveImage({ ...props }),
+ Column: (props: ColumnProps) => <Column {...props} />,
+ Columns: (props: ColumnsProps) => (
+ <Columns className={styles.columns} {...props} />
+ ),
+ Image: (props: ResponsiveImageProps) => <ResponsiveImage {...props} />,
LibreLinks: LibreLinks,
MoreLinks: MoreLinks,
RecentPosts: getRecentPosts,
+ Section: getSection,
ShaarliLink: ShaarliLink,
};
+ const { website } = useSettings();
+
const pageTitle = intl.formatMessage(
{
defaultMessage: '{websiteName} | Front-end developer: WordPress/React',
description: 'HomePage: SEO - Page title',
id: 'PXp2hv',
},
- { websiteName: settings.name }
+ { websiteName: website.name }
);
const pageDescription = intl.formatMessage(
{
@@ -175,35 +304,22 @@ const Home: NextPageWithLayout<HomePageProps> = ({
description: 'HomePage: SEO - Meta description',
id: 'tMuNTy',
},
- { websiteName: settings.name }
+ { websiteName: website.name }
);
-
- const webpageSchema: WebPage = {
- '@id': `${settings.url}/#home`,
- '@type': 'WebPage',
- name: pageTitle,
+ const webpageSchema = getWebPageSchema({
description: pageDescription,
- author: { '@id': `${settings.url}/#branding` },
- creator: { '@id': `${settings.url}/#branding` },
- editor: { '@id': `${settings.url}/#branding` },
- inLanguage: settings.locales.defaultLocale,
- license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr',
- reviewedBy: { '@id': `${settings.url}/#branding` },
- url: `${settings.url}`,
- };
-
- const schemaJsonLd: Graph = {
- '@context': 'https://schema.org',
- '@graph': [webpageSchema],
- };
+ locale: website.locales.default,
+ slug: '',
+ title: pageTitle,
+ });
+ const schemaJsonLd = getSchemaJson([webpageSchema]);
return (
<>
<Head>
<title>{pageTitle}</title>
<meta name="description" content={pageDescription} />
- <meta property="og:type" content="website" />
- <meta property="og:url" content={`${settings.url}`} />
+ <meta property="og:url" content={website.url} />
<meta property="og:title" content={pageTitle} />
<meta property="og:description" content={pageDescription} />
</Head>
@@ -212,23 +328,22 @@ const Home: NextPageWithLayout<HomePageProps> = ({
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }}
/>
- <div id="home">
- <HomePageContent components={components} />
- </div>
+ <Script
+ id="schema-breadcrumb"
+ type="application/ld+json"
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
+ />
+ <HomePageContent components={components} />
</>
);
};
-Home.getLayout = function getLayout(page: ReactElement) {
- return <Layout isHome={true}>{page}</Layout>;
-};
+HomePage.getLayout = (page) =>
+ getLayout(page, { isHome: true, withExtraPadding: false });
-export const getStaticProps: GetStaticProps = async (
- context: GetStaticPropsContext
-) => {
- const { locale } = context;
+export const getStaticProps: GetStaticProps<HomeProps> = async ({ locale }) => {
const translation = await loadTranslation(locale);
- const recentPosts = await getPublishedPosts({ first: 3 });
+ const recentPosts = await getArticlesCard({ first: 3 });
return {
props: {
@@ -238,4 +353,4 @@ export const getStaticProps: GetStaticProps = async (
};
};
-export default Home;
+export default HomePage;