diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-05-24 19:35:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-24 19:35:12 +0200 |
| commit | c85ab5ad43ccf52881ee224672c41ec30021cf48 (patch) | |
| tree | 8058808d9bfca19383f120c46b34d99ff2f89f63 /src/pages/index.tsx | |
| parent | 52404177c07a2aab7fc894362fb3060dff2431a0 (diff) | |
| parent | 11b9de44a4b2f305a6a484187805e429b2767118 (diff) | |
refactor: use storybook and atomic design (#16)
BREAKING CHANGE: rewrite most of the Typescript types, so the content format (the meta in particular) needs to be updated.
Diffstat (limited to 'src/pages/index.tsx')
| -rw-r--r-- | src/pages/index.tsx | 327 |
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; |
