diff options
Diffstat (limited to 'src/pages')
| -rw-r--r-- | src/pages/404.tsx | 85 | ||||
| -rw-r--r-- | src/pages/_app.tsx | 9 | ||||
| -rw-r--r-- | src/pages/article/[slug].tsx | 291 | ||||
| -rw-r--r-- | src/pages/blog/index.tsx | 269 | ||||
| -rw-r--r-- | src/pages/blog/page/[id].tsx | 205 | ||||
| -rw-r--r-- | src/pages/contact.tsx | 151 | ||||
| -rw-r--r-- | src/pages/cv.tsx | 181 | ||||
| -rw-r--r-- | src/pages/index.tsx | 241 | ||||
| -rw-r--r-- | src/pages/mentions-legales.tsx | 150 | ||||
| -rw-r--r-- | src/pages/projet/[slug].tsx | 186 | ||||
| -rw-r--r-- | src/pages/projets.tsx | 128 | ||||
| -rw-r--r-- | src/pages/recherche/index.tsx | 213 | ||||
| -rw-r--r-- | src/pages/sujet/[slug].tsx | 224 | ||||
| -rw-r--r-- | src/pages/thematique/[slug].tsx | 214 | 
14 files changed, 4 insertions, 2543 deletions
| diff --git a/src/pages/404.tsx b/src/pages/404.tsx deleted file mode 100644 index 24c6951..0000000 --- a/src/pages/404.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import Link from 'next/link'; -import { FormattedMessage, useIntl } from 'react-intl'; - -const Error404: NextPageWithLayout = () => { -  const intl = useIntl(); - -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Error 404: Page not found - {websiteName}', -      description: '404Page: SEO - Page title', -      id: '310o3F', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage({ -    defaultMessage: 'Page not found.', -    description: '404Page: SEO - Meta description', -    id: '48Ww//', -  }); - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -      </Head> -      <div className={`${styles.article} ${styles['article--no-comments']}`}> -        <PostHeader -          title={intl.formatMessage({ -            defaultMessage: 'Page not found', -            description: '404Page: page title', -            id: 'OccTWi', -          })} -        /> -        <div className={styles.body}> -          <FormattedMessage -            defaultMessage="Sorry, it seems that the page your are looking for does not exist. If you think this path should work, feel free to <link>contact me</link> with the necessary information so that I can fix the problem." -            description="404Page: page body" -            id="ZWh78Y" -            values={{ -              link: (chunks: string) => ( -                <Link href="/contact/"> -                  <a>{chunks}</a> -                </Link> -              ), -            }} -          /> -        </div> -      </div> -    </> -  ); -}; - -Error404.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const intl = await getIntlInstance(); -  const breadcrumbTitle = intl.formatMessage({ -    defaultMessage: 'Error 404', -    description: '404Page: breadcrumb item', -    id: 'ywkCsK', -  }); -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      translation, -    }, -  }; -}; - -export default Error404; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 84c2469..939b337 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,17 +1,16 @@ -import { AppPropsWithLayout } from '@ts/types/app';  import { settings } from '@utils/config';  import { AckeeProvider } from '@utils/providers/ackee';  import { PrismThemeProvider } from '@utils/providers/prism-theme';  import { ThemeProvider } from 'next-themes'; +import { AppProps } from 'next/app';  import { useRouter } from 'next/router';  import { IntlProvider } from 'react-intl';  import '../styles/globals.scss'; -const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => { +const App = ({ Component, pageProps }: AppProps) => {    const { locale, defaultLocale } = useRouter();    const appLocale: string = locale || settings.locales.defaultLocale; -  const getLayout = Component.getLayout ?? ((page) => page);    return (      <AckeeProvider domain={settings.ackee.url} siteId={settings.ackee.siteId}>        <IntlProvider @@ -25,7 +24,7 @@ const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => {            enableSystem={true}          >            <PrismThemeProvider> -            {getLayout(<Component {...pageProps} />)} +            <Component {...pageProps} />            </PrismThemeProvider>          </ThemeProvider>        </IntlProvider> @@ -33,4 +32,4 @@ const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => {    );  }; -export default MyApp; +export default App; diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx deleted file mode 100644 index 27a6f7b..0000000 --- a/src/pages/article/[slug].tsx +++ /dev/null @@ -1,291 +0,0 @@ -import CommentForm from '@components/CommentForm/CommentForm'; -import CommentsList from '@components/CommentsList/CommentsList'; -import { getLayout } from '@components/Layouts/Layout'; -import PostFooter from '@components/PostFooter/PostFooter'; -import PostHeader from '@components/PostHeader/PostHeader'; -import Sidebar from '@components/Sidebar/Sidebar'; -import Spinner from '@components/Spinner/Spinner'; -import { Sharing, ToC } from '@components/Widgets'; -import { -  getAllPostsSlug, -  getCommentsByPostId, -  getPostBySlug, -} from '@services/graphql/queries'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { ArticleMeta, ArticleProps } from '@ts/types/articles'; -import { PrismDefaultPlugins, PrismPlugins } from '@ts/types/prism'; -import { settings } from '@utils/config'; -import { getFormattedPaths } from '@utils/helpers/format'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { addPrismClasses } from '@utils/helpers/prism'; -import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import Prism from 'prismjs'; -import { ParsedUrlQuery } from 'querystring'; -import { useCallback, useEffect, useMemo } from 'react'; -import { useIntl } from 'react-intl'; -import { Blog, BlogPosting, Graph, WebPage } from 'schema-dts'; - -const SingleArticle: NextPageWithLayout<ArticleProps> = ({ -  comments, -  post, -}) => { -  const intl = useIntl(); -  const router = useRouter(); - -  const loadPrismPlugins = useCallback( -    async (prismPlugins: (PrismDefaultPlugins | PrismPlugins)[]) => { -      for (const plugin of prismPlugins) { -        try { -          if (plugin === 'color-scheme') { -            await import(`@utils/plugins/prism-${plugin}`); -          } else { -            await import(`prismjs/plugins/${plugin}/prism-${plugin}.min.js`); - -            if (plugin === 'autoloader') -              Prism.plugins.autoloader.languages_path = '/prism/'; -          } -        } catch (error) { -          console.error('Article: an error occurred with Prism.'); -          console.error(error); -        } -      } -    }, -    [] -  ); - -  const plugins: (PrismDefaultPlugins | PrismPlugins)[] = useMemo( -    () => [ -      'autoloader', -      'toolbar', -      'show-language', -      'copy-to-clipboard', -      'color-scheme', -      'command-line', -      'line-numbers', -      'match-braces', -      'normalize-whitespace', -    ], -    [] -  ); - -  useEffect(() => { -    loadPrismPlugins(plugins).then(() => { -      addPrismClasses(); -      Prism.highlightAll(); -    }); -  }, [plugins, loadPrismPlugins]); - -  if (router.isFallback) return <Spinner />; - -  const { -    author, -    commentCount, -    content, -    databaseId, -    dates, -    featuredImage, -    info, -    intro, -    seo, -    topics, -    thematics, -    title, -  } = post; - -  const meta: ArticleMeta = { -    author, -    commentCount: commentCount || undefined, -    dates, -    readingTime: info.readingTime, -    thematics, -    wordsCount: info.wordsCount, -  }; - -  const articleUrl = `${settings.url}${router.asPath}`; - -  const webpageSchema: WebPage = { -    '@id': `${articleUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    lastReviewed: dates.update, -    name: seo.title, -    description: seo.metaDesc, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${articleUrl}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const blogSchema: Blog = { -    '@id': `${settings.url}/#blog`, -    '@type': 'Blog', -    blogPost: { '@id': `${settings.url}/#article` }, -    isPartOf: { -      '@id': `${articleUrl}`, -    }, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -  }; - -  const publicationDate = new Date(dates.publication); -  const updateDate = new Date(dates.update); - -  const blogPostSchema: BlogPosting = { -    '@id': `${settings.url}/#article`, -    '@type': 'BlogPosting', -    name: title, -    description: intro, -    articleBody: content, -    author: { '@id': `${settings.url}/#branding` }, -    commentCount: commentCount || undefined, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    discussionUrl: `${articleUrl}/#comments`, -    editor: { '@id': `${settings.url}/#branding` }, -    headline: title, -    image: featuredImage?.sourceUrl, -    inLanguage: settings.locales.defaultLocale, -    isPartOf: { -      '@id': `${settings.url}/blog`, -    }, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${articleUrl}` }, -    thumbnailUrl: featuredImage?.sourceUrl, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, blogSchema, blogPostSchema], -  }; - -  const copyText = intl.formatMessage({ -    defaultMessage: 'Copy', -    description: 'Prism: copy button text (no clicked)', -    id: '/ly3AC', -  }); -  const copiedText = intl.formatMessage({ -    defaultMessage: 'Copied!', -    description: 'Prism: copy button text (clicked)', -    id: 'OV9r1K', -  }); -  const errorText = intl.formatMessage({ -    defaultMessage: 'Use Ctrl+c to copy', -    description: 'Prism: error text', -    id: 'z9qkcQ', -  }); -  const darkTheme = intl.formatMessage({ -    defaultMessage: 'Dark Theme 🌙', -    description: 'Prism: toggle dark theme button text', -    id: 'nFMdWI', -  }); -  const lightTheme = intl.formatMessage({ -    defaultMessage: 'Light Theme 🌞', -    description: 'Prism: toggle light theme button text', -    id: 'Ua2g2p', -  }); - -  return ( -    <> -      <Head> -        <title>{seo.title}</title> -        <meta name="description" content={seo.metaDesc} /> -        <meta property="og:url" content={`${articleUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={intro} /> -        <meta property="og:image" content={featuredImage?.sourceUrl} /> -        <meta property="og:image:alt" content={featuredImage?.altText} /> -      </Head> -      <Script -        id="schema-article" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="article" -        className={styles.article} -        data-prismjs-copy={copyText} -        data-prismjs-copy-success={copiedText} -        data-prismjs-copy-error={errorText} -        data-prismjs-color-scheme-dark={darkTheme} -        data-prismjs-color-scheme-light={lightTheme} -      > -        <PostHeader intro={intro} meta={meta} title={title} /> -        <Sidebar -          position="left" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Table of Contents', -            description: 'ArticlePage: ToC sidebar aria-label', -            id: '9nhYRA', -          })} -        > -          <ToC /> -        </Sidebar> -        <div -          className={styles.body} -          dangerouslySetInnerHTML={{ __html: content }} -        ></div> -        <PostFooter topics={topics} /> -        <Sidebar -          position="right" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Sidebar', -            description: 'ArticlePage: right sidebar aria-label', -            id: 'JeYOeA', -          })} -        > -          <Sharing title={title} excerpt={intro} /> -        </Sidebar> -        <section id="comments" className={styles.comments}> -          <CommentsList articleId={databaseId} comments={comments} /> -          <CommentForm articleId={databaseId} /> -        </section> -      </article> -    </> -  ); -}; - -SingleArticle.getLayout = getLayout; - -interface PostParams extends ParsedUrlQuery { -  slug: string; -} - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const { locale } = context; -  const translation = await loadTranslation(locale); -  const { slug } = context.params as PostParams; -  const post = await getPostBySlug(slug); -  const comments = await getCommentsByPostId(post.databaseId); -  const breadcrumbTitle = post.title; - -  return { -    props: { -      breadcrumbTitle, -      comments, -      post, -      translation, -    }, -  }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { -  const allSlugs = await getAllPostsSlug(); -  const paths = getFormattedPaths(allSlugs); - -  return { -    paths, -    fallback: true, -  }; -}; - -export default SingleArticle; diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx deleted file mode 100644 index b5ced07..0000000 --- a/src/pages/blog/index.tsx +++ /dev/null @@ -1,269 +0,0 @@ -import { Button } from '@components/Buttons'; -import { getLayout } from '@components/Layouts/Layout'; -import Pagination from '@components/Pagination/Pagination'; -import PaginationCursor from '@components/PaginationCursor/PaginationCursor'; -import PostHeader from '@components/PostHeader/PostHeader'; -import PostsList from '@components/PostsList/PostsList'; -import Sidebar from '@components/Sidebar/Sidebar'; -import Spinner from '@components/Spinner/Spinner'; -import { ThematicsList, TopicsList } from '@components/Widgets'; -import { -  getAllThematics, -  getAllTopics, -  getPostsTotal, -  getPublishedPosts, -} from '@services/graphql/queries'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { BlogPageProps, PostsList as PostsListData } from '@ts/types/blog'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useEffect, useRef, useState } from 'react'; -import { useIntl } from 'react-intl'; -import { Blog as BlogSchema, Graph, WebPage } from 'schema-dts'; -import useSWRInfinite from 'swr/infinite'; - -const Blog: NextPageWithLayout<BlogPageProps> = ({ -  allThematics, -  allTopics, -  posts, -  totalPosts, -}) => { -  const intl = useIntl(); -  const lastPostRef = useRef<HTMLSpanElement>(null); -  const router = useRouter(); -  const [isMounted, setIsMounted] = useState<boolean>(false); - -  useEffect(() => { -    if (typeof window !== undefined) setIsMounted(true); -  }, []); - -  const getKey = (pageIndex: number, previousData: PostsListData) => { -    if (previousData && !previousData.posts) return null; - -    return pageIndex === 0 -      ? { first: settings.postsPerPage } -      : { -          first: settings.postsPerPage, -          after: previousData.pageInfo.endCursor, -        }; -  }; - -  const { data, error, size, setSize } = useSWRInfinite( -    getKey, -    getPublishedPosts, -    { fallbackData: [posts] } -  ); -  const [totalPostsCount, setTotalPostsCount] = useState<number>(totalPosts); - -  useEffect(() => { -    if (data) setTotalPostsCount(data[0].pageInfo.total); -  }, [data]); - -  const [loadedPostsCount, setLoadedPostsCount] = useState<number>( -    settings.postsPerPage -  ); - -  useEffect(() => { -    if (data && data.length > 0) { -      const newCount = -        settings.postsPerPage + -        data[0].pageInfo.total - -        data[data.length - 1].pageInfo.total; -      setLoadedPostsCount(newCount); -    } -  }, [data]); - -  const isLoadingInitialData = !data && !error; -  const isLoadingMore: boolean = -    isLoadingInitialData || -    (size > 0 && data !== undefined && typeof data[size - 1] === 'undefined'); - -  const hasNextPage = data && data[data.length - 1].pageInfo.hasNextPage; - -  const loadMorePosts = () => { -    if (lastPostRef.current) { -      lastPostRef.current.focus(); -    } -    setSize(size + 1); -  }; - -  const getPostsList = () => { -    if (error) -      return intl.formatMessage({ -        defaultMessage: 'Failed to load.', -        description: 'BlogPage: failed to load text', -        id: 'C/XGkH', -      }); -    if (!data) return <Spinner />; - -    return <PostsList ref={lastPostRef} data={data} showYears={true} />; -  }; - -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Blog: development, open source - {websiteName}', -      description: 'BlogPage: SEO - Page title', -      id: '+Y+tLK', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        "Discover {websiteName}'s writings. He talks about web development, Linux and open source mostly.", -      description: 'BlogPage: SEO - Meta description', -      id: '18h/t0', -    }, -    { websiteName: settings.name } -  ); -  const pageUrl = `${settings.url}${router.asPath}`; - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    inLanguage: settings.locales.defaultLocale, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${settings.url}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const blogSchema: BlogSchema = { -    '@id': `${settings.url}/#blog`, -    '@type': 'Blog', -    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', -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, blogSchema], -  }; - -  const title = intl.formatMessage({ -    defaultMessage: 'Blog', -    description: 'BlogPage: page title', -    id: '7TbbIk', -  }); - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="website" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={pageDescription} /> -      </Head> -      <Script -        id="schema-blog" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="blog" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader title={title} meta={{ results: totalPostsCount }} /> -        <div className={styles.body}> -          {getPostsList()} -          {hasNextPage && -            (isMounted ? ( -              <> -                <PaginationCursor -                  current={loadedPostsCount} -                  total={totalPostsCount} -                /> -                <Button -                  isDisabled={isLoadingMore} -                  clickHandler={loadMorePosts} -                  position="center" -                  spacing={true} -                > -                  {intl.formatMessage({ -                    defaultMessage: 'Load more?', -                    description: 'BlogPage: load more text', -                    id: 'Kqq2cm', -                  })} -                </Button> -              </> -            ) : ( -              <Pagination baseUrl="/blog" total={totalPostsCount} /> -            ))} -        </div> -        <Sidebar -          position="right" -          title={intl.formatMessage({ -            defaultMessage: 'Filter by:', -            description: 'BlogPage: sidebar title', -            id: 'KERk7L', -          })} -        > -          <ThematicsList -            initialData={allThematics} -            title={intl.formatMessage({ -              defaultMessage: 'Thematics', -              description: 'BlogPage: thematics list widget title', -              id: 'HriY57', -            })} -          /> -          <TopicsList -            initialData={allTopics} -            title={intl.formatMessage({ -              defaultMessage: 'Topics', -              description: 'BlogPage: topics list widget title', -              id: '2D9tB5', -            })} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -Blog.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const intl = await getIntlInstance(); -  const breadcrumbTitle = intl.formatMessage({ -    defaultMessage: 'Blog', -    description: 'BlogPage: breadcrumb item', -    id: 'R0eDmw', -  }); -  const firstPosts = await getPublishedPosts({ first: settings.postsPerPage }); -  const totalPosts = await getPostsTotal(); -  const allThematics = await getAllThematics(); -  const allTopics = await getAllTopics(); -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      allThematics, -      allTopics, -      breadcrumbTitle, -      locale, -      posts: firstPosts, -      totalPosts, -      translation, -    }, -  }; -}; - -export default Blog; diff --git a/src/pages/blog/page/[id].tsx b/src/pages/blog/page/[id].tsx deleted file mode 100644 index 6c4d2f8..0000000 --- a/src/pages/blog/page/[id].tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import Pagination from '@components/Pagination/Pagination'; -import PostHeader from '@components/PostHeader/PostHeader'; -import PostsList from '@components/PostsList/PostsList'; -import Sidebar from '@components/Sidebar/Sidebar'; -import { ThematicsList, TopicsList } from '@components/Widgets'; -import { -  getAllThematics, -  getAllTopics, -  getEndCursor, -  getPostsTotal, -  getPublishedPosts, -} from '@services/graphql/queries'; -import { NextPageWithLayout } from '@ts/types/app'; -import { BlogPageProps } from '@ts/types/blog'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useIntl } from 'react-intl'; -import { Blog, Graph, WebPage } from 'schema-dts'; -import styles from '@styles/pages/Page.module.scss'; -import { getFormattedPageNumbers } from '@utils/helpers/format'; -import { useEffect } from 'react'; -import Spinner from '@components/Spinner/Spinner'; - -const BlogPage: NextPageWithLayout<BlogPageProps> = ({ -  allThematics, -  allTopics, -  posts, -  totalPosts, -}) => { -  const intl = useIntl(); -  const router = useRouter(); -  const pageNumber = Number(router.query.id); - -  useEffect(() => { -    if (router.query.id === '1') router.push('/blog'); -  }, [router]); - -  if (router.isFallback) return <Spinner />; - -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Blog - Page {number} - {websiteName}', -      description: 'BlogPage: SEO - Page title', -      id: '8w+jnD', -    }, -    { number: pageNumber, websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        "Discover {websiteName}'s writings. He talks about web development, Linux and open source mostly.", -      description: 'BlogPage: SEO - Meta description', -      id: '18h/t0', -    }, -    { websiteName: settings.name } -  ); -  const pageUrl = `${settings.url}${router.asPath}`; - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    inLanguage: settings.locales.defaultLocale, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${settings.url}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const blogSchema: Blog = { -    '@id': `${settings.url}/#blog`, -    '@type': 'Blog', -    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', -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, blogSchema], -  }; - -  const title = intl.formatMessage({ -    defaultMessage: 'Blog', -    description: 'BlogPage: page title', -    id: '7TbbIk', -  }); - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="website" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={pageDescription} /> -      </Head> -      <Script -        id="schema-blog" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="blog" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader title={title} meta={{ results: totalPosts }} /> -        <div className={styles.body}> -          <PostsList data={[posts]} showYears={true} /> -          <Pagination baseUrl="/blog" total={totalPosts} /> -        </div> -        <Sidebar -          position="right" -          title={intl.formatMessage({ -            defaultMessage: 'Filter by:', -            description: 'BlogPage: sidebar title', -            id: 'KERk7L', -          })} -        > -          <ThematicsList -            initialData={allThematics} -            title={intl.formatMessage({ -              defaultMessage: 'Thematics', -              description: 'BlogPage: thematics list widget title', -              id: 'HriY57', -            })} -          /> -          <TopicsList -            initialData={allTopics} -            title={intl.formatMessage({ -              defaultMessage: 'Topics', -              description: 'BlogPage: topics list widget title', -              id: '2D9tB5', -            })} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -BlogPage.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const intl = await getIntlInstance(); -  const breadcrumbTitle = intl.formatMessage({ -    defaultMessage: 'Blog', -    description: 'BlogPage: breadcrumb item', -    id: 'R0eDmw', -  }); -  const { locale, params } = context; -  const queriedPageNumber = params ? Number(params.id) : 1; -  const queriedPostsNumber = settings.postsPerPage * queriedPageNumber; -  const endCursor = -    queriedPostsNumber === 1 -      ? undefined -      : await getEndCursor({ first: queriedPostsNumber }); -  const posts = await getPublishedPosts({ -    first: settings.postsPerPage, -    after: endCursor, -  }); -  const totalPosts = await getPostsTotal(); -  const allThematics = await getAllThematics(); -  const allTopics = await getAllTopics(); -  const translation = await loadTranslation(locale); - -  return { -    props: { -      allThematics, -      allTopics, -      breadcrumbTitle, -      locale, -      posts, -      totalPosts, -      translation, -    }, -  }; -}; - -export default BlogPage; - -export const getStaticPaths: GetStaticPaths = async () => { -  const totalPosts = await getPostsTotal(); -  const totalPages = Math.floor(totalPosts / settings.postsPerPage); -  const paths = getFormattedPageNumbers(totalPages); - -  return { -    paths, -    fallback: true, -  }; -}; diff --git a/src/pages/contact.tsx b/src/pages/contact.tsx deleted file mode 100644 index 5934dd9..0000000 --- a/src/pages/contact.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import ContactForm from '@components/ContactForm/ContactForm'; -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import Sidebar from '@components/Sidebar/Sidebar'; -import { SocialMedia } from '@components/Widgets'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useIntl } from 'react-intl'; -import { ContactPage as ContactPageSchema, Graph, WebPage } from 'schema-dts'; - -const ContactPage: NextPageWithLayout = () => { -  const intl = useIntl(); -  const router = useRouter(); - -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Contact form - {websiteName}', -      description: 'ContactPage: SEO - Page title', -      id: 'Y3qRib', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        "Contact {websiteName} through its website. All you need to do it's to fill the contact form.", -      description: 'ContactPage: SEO - Meta description', -      id: 'OIffB4', -    }, -    { websiteName: settings.name } -  ); -  const pageUrl = `${settings.url}${router.asPath}`; -  const title = intl.formatMessage({ -    defaultMessage: 'Contact', -    description: 'ContactPage: page title', -    id: 'AN9iy7', -  }); -  const intro = intl.formatMessage({ -    defaultMessage: 'Please fill the form to contact me.', -    description: 'ContactPage: page introduction', -    id: '8Ls2mD', -  }); - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${pageUrl}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const contactSchema: ContactPageSchema = { -    '@id': `${settings.url}/#contact`, -    '@type': 'ContactPage', -    name: title, -    description: intro, -    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', -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, contactSchema], -  }; - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={intro} /> -      </Head> -      <Script -        id="schema-contact" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="contact" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader title={title} intro={intro} /> -        <div className={styles.body}> -          <p> -            {intl.formatMessage({ -              defaultMessage: 'All fields marked with * are required.', -              description: 'ContactPage: required fields text', -              id: 'txusHd', -            })} -          </p> -          <ContactForm /> -        </div> -        <Sidebar position="right"> -          <SocialMedia -            title={intl.formatMessage({ -              defaultMessage: 'Find me elsewhere', -              description: 'ContactPage: social media widget title', -              id: 'Qh2CwH', -            })} -            github={true} -            gitlab={true} -            linkedin={true} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -ContactPage.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const intl = await getIntlInstance(); -  const breadcrumbTitle = intl.formatMessage({ -    defaultMessage: 'Contact', -    description: 'ContactPage: breadcrumb item', -    id: 'CzTbM4', -  }); -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      translation, -    }, -  }; -}; - -export default ContactPage; diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx deleted file mode 100644 index 71eb449..0000000 --- a/src/pages/cv.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import Sidebar from '@components/Sidebar/Sidebar'; -import { CVPreview, SocialMedia, ToC } from '@components/Widgets'; -import CVContent, { intro, meta, pdf, image } from '@content/pages/cv.mdx'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { ArticleMeta } from '@ts/types/articles'; -import { settings } from '@utils/config'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useIntl } from 'react-intl'; -import { AboutPage, Graph, WebPage } from 'schema-dts'; - -const CV: NextPageWithLayout = () => { -  const intl = useIntl(); -  const router = useRouter(); -  const dates = { -    publication: meta.publishedOn, -    update: meta.updatedOn, -  }; - -  const pageMeta: ArticleMeta = { -    dates, -  }; -  const pageUrl = `${settings.url}${router.asPath}`; -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'CV Front-end developer - {websiteName}', -      description: 'CVPage: SEO - Page title', -      id: 'Y1ZdJ6', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        'Discover the curriculum of {websiteName}, front-end developer located in France: skills, experiences and training.', -      description: 'CVPage: SEO - Meta description', -      id: 'bBdMGm', -    }, -    { websiteName: settings.name } -  ); - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${pageUrl}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const publicationDate = new Date(dates.publication); -  const updateDate = new Date(dates.update); - -  const cvSchema: AboutPage = { -    '@id': `${settings.url}/#cv`, -    '@type': 'AboutPage', -    name: pageTitle, -    description: intro, -    author: { '@id': `${settings.url}/#branding` }, -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    image, -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    thumbnailUrl: image, -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, cvSchema], -  }; - -  const title = intl.formatMessage( -    { -      defaultMessage: "{name}'s CV", -      description: 'CVPage: page title', -      id: 'Mj2BQf', -    }, -    { name: settings.name } -  ); - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={intro} /> -        <meta property="og:image" content={image} /> -        <meta property="og:image:alt" content={title} /> -      </Head> -      <Script -        id="schema-cv" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="cv" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader intro={intro} meta={pageMeta} title={meta.title} /> -        <Sidebar -          position="left" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Table of Contents', -            description: 'CVPage: ToC sidebar aria-label', -            id: 'g4DckL', -          })} -        > -          <ToC /> -        </Sidebar> -        <div className={styles.body}> -          <CVContent /> -        </div> -        <Sidebar -          position="right" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Sidebar', -            description: 'CVPage: right sidebar aria-label', -            id: 'QHOm5t', -          })} -        > -          <CVPreview -            title={intl.formatMessage({ -              defaultMessage: 'Others formats', -              description: 'CVPage: cv preview widget title', -              id: 'B9OCyV', -            })} -            imgSrc={image} -            pdf={pdf} -          /> -          <SocialMedia -            title={intl.formatMessage({ -              defaultMessage: 'Open-source projects', -              description: 'CVPage: social media widget title', -              id: '+Dre5J', -            })} -            github={true} -            gitlab={true} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -CV.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const breadcrumbTitle = meta.title; -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      translation, -    }, -  }; -}; - -export default CV; diff --git a/src/pages/index.tsx b/src/pages/index.tsx deleted file mode 100644 index ca0a809..0000000 --- a/src/pages/index.tsx +++ /dev/null @@ -1,241 +0,0 @@ -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 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 { NestedMDXComponents } from 'mdx/types'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import Script from 'next/script'; -import type { ReactElement } from 'react'; -import { useIntl } from 'react-intl'; -import { Graph, WebPage } from 'schema-dts'; - -type HomePageProps = { -  recentPosts: PostsList; -}; - -const Home: NextPageWithLayout<HomePageProps> = ({ -  recentPosts, -}: { -  recentPosts: PostsList; -}) => { -  const intl = useIntl(); - -  const CodingLinks = () => { -    return ( -      <ul className={styles['links-list']}> -        <li> -          <ButtonLink target="/thematique/developpement-web"> -            {intl.formatMessage({ -              defaultMessage: 'Web development', -              description: 'HomePage: link to web development thematic', -              id: 'vkF/RP', -            })} -          </ButtonLink> -        </li> -        <li> -          <ButtonLink target="/projets"> -            {intl.formatMessage({ -              defaultMessage: 'Projects', -              description: 'HomePage: link to projects', -              id: 'N44SOc', -            })} -          </ButtonLink> -        </li> -      </ul> -    ); -  }; - -  const ColdarkRepos = () => { -    return ( -      <ul className={styles['links-list']}> -        <li> -          <ButtonLink -            target="https://github.com/ArmandPhilippot/coldark" -            isExternal={true} -          > -            Github -          </ButtonLink> -        </li> -        <li> -          <ButtonLink -            target="https://gitlab.com/ArmandPhilippot/coldark" -            isExternal={true} -          > -            Gitlab -          </ButtonLink> -        </li> -      </ul> -    ); -  }; - -  const LibreLinks = () => { -    return ( -      <ul className={styles['links-list']}> -        <li> -          <ButtonLink target="/thematique/libre"> -            {intl.formatMessage({ -              defaultMessage: 'Free', -              description: 'HomePage: link to free thematic', -              id: 'w8GrOf', -            })} -          </ButtonLink> -        </li> -        <li> -          <ButtonLink target="/thematique/linux"> -            {intl.formatMessage({ -              defaultMessage: 'Linux', -              description: 'HomePage: link to Linux thematic', -              id: 'jASD7k', -            })} -          </ButtonLink> -        </li> -      </ul> -    ); -  }; - -  const ShaarliLink = () => { -    return ( -      <ul className={styles['links-list']}> -        <li> -          <ButtonLink target="https://shaarli.armandphilippot.com/"> -            {intl.formatMessage({ -              defaultMessage: 'Shaarli', -              description: 'HomePage: link to Shaarli', -              id: 'i5L19t', -            })} -          </ButtonLink> -        </li> -      </ul> -    ); -  }; - -  const MoreLinks = () => { -    return ( -      <ul className={styles['links-list']}> -        <li> -          <ButtonLink target="/contact"> -            <ContactIcon /> -            {intl.formatMessage({ -              defaultMessage: 'Contact me', -              description: 'HomePage: contact button text', -              id: 'sO/Iwj', -            })} -          </ButtonLink> -        </li> -        <li> -          <ButtonLink target="/feed"> -            <FeedIcon className={styles['icon--feed']} /> -            {intl.formatMessage({ -              defaultMessage: 'Subscribe', -              description: 'HomePage: RSS feed subscription text', -              id: 'T4YA64', -            })} -          </ButtonLink> -        </li> -      </ul> -    ); -  }; - -  const getRecentPosts = () => { -    return <RecentPosts posts={recentPosts} />; -  }; - -  const components: NestedMDXComponents = { -    CodingLinks: CodingLinks, -    ColdarkRepos: ColdarkRepos, -    Image: (props: ResponsiveImageProps) => ResponsiveImage({ ...props }), -    LibreLinks: LibreLinks, -    MoreLinks: MoreLinks, -    RecentPosts: getRecentPosts, -    ShaarliLink: ShaarliLink, -  }; - -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: '{websiteName} | Front-end developer: WordPress/React', -      description: 'HomePage: SEO - Page title', -      id: 'PXp2hv', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        '{websiteName} is a front-end developer located in France. He codes and he writes mostly about web development and open-source.', -      description: 'HomePage: SEO - Meta description', -      id: 'tMuNTy', -    }, -    { websiteName: settings.name } -  ); - -  const webpageSchema: WebPage = { -    '@id': `${settings.url}/#home`, -    '@type': 'WebPage', -    name: pageTitle, -    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], -  }; - -  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:title" content={pageTitle} /> -        <meta property="og:description" content={pageDescription} /> -      </Head> -      <Script -        id="schema-homepage" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <div id="home"> -        <HomePageContent components={components} /> -      </div> -    </> -  ); -}; - -Home.getLayout = function getLayout(page: ReactElement) { -  return <Layout isHome={true}>{page}</Layout>; -}; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const { locale } = context; -  const translation = await loadTranslation(locale); -  const recentPosts = await getPublishedPosts({ first: 3 }); - -  return { -    props: { -      recentPosts, -      translation, -    }, -  }; -}; - -export default Home; diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx deleted file mode 100644 index b103b5e..0000000 --- a/src/pages/mentions-legales.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import { Link } from '@components/MDX'; -import PostHeader from '@components/PostHeader/PostHeader'; -import Sidebar from '@components/Sidebar/Sidebar'; -import { ToC } from '@components/Widgets'; -import LegalNoticeContent, { -  intro, -  meta, -} from '@content/pages/legal-notice.mdx'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { ArticleMeta } from '@ts/types/articles'; -import { settings } from '@utils/config'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { NestedMDXComponents } from 'mdx/types'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useIntl } from 'react-intl'; -import { Article, Graph, WebPage } from 'schema-dts'; - -const LegalNotice: NextPageWithLayout = () => { -  const intl = useIntl(); -  const router = useRouter(); -  const dates = { -    publication: meta.publishedOn, -    update: meta.updatedOn, -  }; - -  const pageMeta: ArticleMeta = { -    dates, -  }; -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Legal notice - {websiteName}', -      description: 'LegalNoticePage: SEO - Page title', -      id: '4zAUSu', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: "Discover the legal notice of {websiteName}'s website.", -      description: 'LegalNoticePage: SEO - Meta description', -      id: 'uvB+32', -    }, -    { websiteName: settings.name } -  ); -  const pageUrl = `${settings.url}${router.asPath}`; -  const title = intl.formatMessage({ -    defaultMessage: 'Legal notice', -    description: 'LegalNoticePage: page title', -    id: '/IirIt', -  }); -  const publicationDate = new Date(dates.publication); -  const updateDate = new Date(dates.update); - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${pageUrl}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const articleSchema: Article = { -    '@id': `${settings.url}/#legal-notice`, -    '@type': 'Article', -    name: title, -    description: intro, -    author: { '@id': `${settings.url}/#branding` }, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    headline: title, -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, articleSchema], -  }; - -  const components: NestedMDXComponents = { -    Link: (props) => Link(props), -  }; - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={pageTitle} /> -        <meta property="og:description" content={intro} /> -      </Head> -      <Script -        id="schema-legal-notice" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="legal-notice" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader intro={intro} meta={pageMeta} title={meta.title} /> -        <Sidebar position="left"> -          <ToC /> -        </Sidebar> -        <div className={styles.body}> -          <LegalNoticeContent components={components} /> -        </div> -      </article> -    </> -  ); -}; - -LegalNotice.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const breadcrumbTitle = meta.title; -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      translation, -    }, -  }; -}; - -export default LegalNotice; diff --git a/src/pages/projet/[slug].tsx b/src/pages/projet/[slug].tsx deleted file mode 100644 index 1f09fed..0000000 --- a/src/pages/projet/[slug].tsx +++ /dev/null @@ -1,186 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import { CodeBlock, Gallery, Link, ResponsiveImage } from '@components/MDX'; -import PostHeader from '@components/PostHeader/PostHeader'; -import ProjectSummary from '@components/ProjectSummary/ProjectSummary'; -import Sidebar from '@components/Sidebar/Sidebar'; -import { Sharing, ToC } from '@components/Widgets'; -import styles from '@styles/pages/Page.module.scss'; -import { -  NextPageWithLayout, -  Project as ProjectData, -  ProjectProps, -} from '@ts/types/app'; -import { settings } from '@utils/config'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { -  getAllProjectsFilename, -  getProjectData, -} from '@utils/helpers/projects'; -import { MDXComponents, NestedMDXComponents } from 'mdx/types'; -import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { ParsedUrlQuery } from 'querystring'; -import { ComponentType } from 'react'; -import { useIntl } from 'react-intl'; -import { Article, Graph, WebPage } from 'schema-dts'; - -const Project: NextPageWithLayout<ProjectProps> = ({ -  project, -}: { -  project: ProjectData; -}) => { -  const intl = useIntl(); -  const router = useRouter(); -  const projectUrl = `${settings.url}${router.asPath}`; -  const { id, intro, meta, title, seo } = project; -  const dates = { -    publication: meta.publishedOn, -    update: meta.updatedOn, -  }; - -  const components: NestedMDXComponents = { -    CodeBlock: (props) => CodeBlock(props), -    Gallery: (props) => Gallery(props), -    Image: (props) => ResponsiveImage({ caption: props.caption, ...props }), -    Link: (props) => Link(props), -    pre: ({ children }) => CodeBlock(children.props), -  }; - -  const ProjectContent: ComponentType<MDXComponents> = -    require(`../../content/projects/${id}.mdx`).default; - -  const webpageSchema: WebPage = { -    '@id': `${projectUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: seo.title, -    description: seo.description, -    inLanguage: settings.locales.defaultLocale, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${settings.url}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const publicationDate = new Date(dates.publication); -  const updateDate = new Date(dates.update); - -  const articleSchema: Article = { -    '@id': `${settings.url}/project`, -    '@type': 'Article', -    name: title, -    description: intro, -    author: { '@id': `${settings.url}/#branding` }, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    headline: title, -    thumbnailUrl: meta.hasCover ? `/projects/${id}.jpg` : '', -    image: meta.hasCover ? `/projects/${id}.jpg` : '', -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${projectUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, articleSchema], -  }; - -  return ( -    <> -      <Head> -        <title>{seo.title}</title> -        <meta name="description" content={seo.description} /> -        <meta property="og:url" content={`${projectUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={title} /> -        <meta property="og:description" content={intro} /> -      </Head> -      <Script -        id="schema-project" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="project" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader title={title} intro={intro} meta={{ dates }} /> -        <Sidebar -          position="left" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Table of Contents', -            description: 'ProjectPage: ToC sidebar aria-label', -            id: '6dXfvr', -          })} -        > -          <ToC /> -        </Sidebar> -        <div className={styles.body}> -          <ProjectSummary id={id} title={title} meta={meta} /> -          <ProjectContent components={components} /> -        </div> -        <Sidebar -          position="right" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Sidebar', -            description: 'ProjectPage: right sidebar aria-label', -            id: 'hHrNd0', -          })} -        > -          <Sharing title={title} excerpt={intro} /> -        </Sidebar> -      </article> -    </> -  ); -}; - -Project.getLayout = getLayout; - -interface ProjectParams extends ParsedUrlQuery { -  slug: string; -} - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const { locale } = context; -  const translation = await loadTranslation(locale); -  const { slug } = context.params as ProjectParams; -  const project = await getProjectData(slug); -  const breadcrumbTitle = project.title; - -  return { -    props: { -      breadcrumbTitle, -      locale, -      project, -      translation, -    }, -  }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { -  const filenames = getAllProjectsFilename(); -  const paths = filenames.map((filename) => { -    return { -      params: { -        slug: filename, -      }, -    }; -  }); - -  return { -    paths, -    fallback: false, -  }; -}; - -export default Project; diff --git a/src/pages/projets.tsx b/src/pages/projets.tsx deleted file mode 100644 index 8a81f39..0000000 --- a/src/pages/projets.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import ProjectsList from '@components/ProjectsList/ProjectsList'; -import PageContent, { meta } from '@content/pages/projects.mdx'; -import styles from '@styles/pages/Projects.module.scss'; -import { Project } from '@ts/types/app'; -import { settings } from '@utils/config'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { getSortedProjects } from '@utils/helpers/projects'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { useIntl } from 'react-intl'; -import { Article, Graph, WebPage } from 'schema-dts'; - -const Projects = ({ projects }: { projects: Project[] }) => { -  const intl = useIntl(); -  const dates = { -    publication: meta.publishedOn, -    update: meta.updatedOn, -  }; -  const publicationDate = new Date(dates.publication); -  const updateDate = new Date(dates.update); -  const router = useRouter(); -  const pageUrl = `${settings.url}${router.asPath}`; -  const pageTitle = intl.formatMessage( -    { -      defaultMessage: 'Projects: open-source makings - {websiteName}', -      description: 'ProjectsPage: SEO - Page title', -      id: 'SX1z3t', -    }, -    { websiteName: settings.name } -  ); -  const pageDescription = intl.formatMessage( -    { -      defaultMessage: -        'Discover {websiteName} projects. Mostly related to web development and open source.', -      description: 'ProjectsPage: SEO - Meta description', -      id: 's6U1Xt', -    }, -    { websiteName: settings.name } -  ); - -  const webpageSchema: WebPage = { -    '@id': `${pageUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: pageTitle, -    description: pageDescription, -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${pageUrl}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const articleSchema: Article = { -    '@id': `${settings.url}/#projects`, -    '@type': 'Article', -    name: meta.title, -    description: pageDescription, -    author: { '@id': `${settings.url}/#branding` }, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    headline: meta.title, -    inLanguage: settings.locales.defaultLocale, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${pageUrl}` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, articleSchema], -  }; - -  return ( -    <> -      <Head> -        <title>{pageTitle}</title> -        <meta name="description" content={pageDescription} /> -        <meta property="og:url" content={`${pageUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={meta.title} /> -        <meta property="og:description" content={pageDescription} /> -      </Head> -      <Script -        id="schema-projects" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article id="projects" className={styles.article}> -        <PostHeader title={meta.title} intro={<PageContent />} /> -        <div className={styles.body}> -          {projects.length > 0 && <ProjectsList projects={projects} />} -        </div> -      </article> -    </> -  ); -}; - -Projects.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const breadcrumbTitle = meta.title; -  const { locale } = context; -  const projects: Project[] = await getSortedProjects(); -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      projects, -      translation, -    }, -  }; -}; - -export default Projects; diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx deleted file mode 100644 index b843f8d..0000000 --- a/src/pages/recherche/index.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { Button } from '@components/Buttons'; -import { getLayout } from '@components/Layouts/Layout'; -import PaginationCursor from '@components/PaginationCursor/PaginationCursor'; -import PostHeader from '@components/PostHeader/PostHeader'; -import PostsList from '@components/PostsList/PostsList'; -import Sidebar from '@components/Sidebar/Sidebar'; -import Spinner from '@components/Spinner/Spinner'; -import { ThematicsList, TopicsList } from '@components/Widgets'; -import { getPublishedPosts } from '@services/graphql/queries'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { PostsList as PostsListData } from '@ts/types/blog'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import { useEffect, useRef, useState } from 'react'; -import { useIntl } from 'react-intl'; -import useSWRInfinite from 'swr/infinite'; - -const Search: NextPageWithLayout = () => { -  const intl = useIntl(); -  const [query, setQuery] = useState(''); -  const router = useRouter(); -  const lastPostRef = useRef<HTMLSpanElement>(null); - -  useEffect(() => { -    if (!router.isReady) return; - -    if (router.query?.s && typeof router.query.s === 'string') { -      setQuery(router.query.s); -    } -  }, [router.isReady, router.query.s]); - -  const getKey = (pageIndex: number, previousData: PostsListData) => { -    if (previousData && !previousData.posts) return null; - -    return pageIndex === 0 -      ? { first: settings.postsPerPage, searchQuery: query } -      : { -          first: settings.postsPerPage, -          after: previousData.pageInfo.endCursor, -          searchQuery: query, -        }; -  }; - -  const { data, error, size, setSize } = useSWRInfinite( -    getKey, -    getPublishedPosts -  ); -  const [totalPostsCount, setTotalPostsCount] = useState<number>(0); - -  useEffect(() => { -    if (data) setTotalPostsCount(data[0].pageInfo.total); -  }, [data]); - -  const [loadedPostsCount, setLoadedPostsCount] = useState<number>( -    settings.postsPerPage -  ); - -  useEffect(() => { -    if (data && data.length > 0) { -      const newCount = -        settings.postsPerPage + -        data[0].pageInfo.total - -        data[data.length - 1].pageInfo.total; -      setLoadedPostsCount(newCount); -    } -  }, [data]); - -  const isLoadingInitialData = !data && !error; -  const isLoadingMore: boolean = -    isLoadingInitialData || -    (size > 0 && data !== undefined && typeof data[size - 1] === 'undefined'); - -  const hasNextPage = data && data[data.length - 1].pageInfo.hasNextPage; - -  const title = query -    ? intl.formatMessage( -        { -          defaultMessage: 'Search results for {query}', -          description: 'SearchPage: search results text', -          id: 'VSGuGE', -        }, -        { query } -      ) -    : intl.formatMessage({ -        defaultMessage: 'Search', -        description: 'SearchPage: page title', -        id: 'U+35YD', -      }); - -  const description = query -    ? intl.formatMessage( -        { -          defaultMessage: 'Discover search results for {query}', -          description: 'SearchPage: meta description with query', -          id: 'A4LTGq', -        }, -        { query } -      ) -    : intl.formatMessage( -        { -          defaultMessage: 'Search for a post on {websiteName}', -          description: 'SearchPage: meta description without query', -          id: 'PrIz5o', -        }, -        { websiteName: settings.name } -      ); - -  const head = { -    title: `${title} | ${settings.name}`, -    description, -  }; - -  const loadMorePosts = () => { -    if (lastPostRef.current) { -      lastPostRef.current.focus(); -    } -    setSize(size + 1); -  }; - -  const getPostsList = () => { -    if (error) -      return intl.formatMessage({ -        defaultMessage: 'Failed to load.', -        description: 'SearchPage: failed to load text', -        id: 'fOe8rH', -      }); -    if (!data) return <Spinner />; - -    return <PostsList ref={lastPostRef} data={data} showYears={false} />; -  }; - -  return ( -    <> -      <Head> -        <title>{head.title}</title> -        <meta name="description" content={head.description} /> -      </Head> -      <article -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader title={title} meta={{ results: totalPostsCount }} /> -        <div className={styles.body}> -          {getPostsList()} -          {hasNextPage && ( -            <> -              <PaginationCursor -                current={loadedPostsCount} -                total={totalPostsCount} -              /> -              <Button -                isDisabled={isLoadingMore} -                clickHandler={loadMorePosts} -                position="center" -                spacing={true} -              > -                {intl.formatMessage({ -                  defaultMessage: 'Load more?', -                  description: 'SearchPage: load more text', -                  id: 'pEtJik', -                })} -              </Button> -            </> -          )} -        </div> -        <Sidebar position="right"> -          <ThematicsList -            title={intl.formatMessage({ -              defaultMessage: 'Thematics', -              description: 'SearchPage: thematics list widget title', -              id: 'Dq6+WH', -            })} -          /> -          <TopicsList -            title={intl.formatMessage({ -              defaultMessage: 'Topics', -              description: 'SearchPage: topics list widget title', -              id: 'N804XO', -            })} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -Search.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const intl = await getIntlInstance(); -  const breadcrumbTitle = intl.formatMessage({ -    defaultMessage: 'Search', -    description: 'SearchPage: breadcrumb item', -    id: 'TfU6Qm', -  }); -  const { locale } = context; -  const translation = await loadTranslation(locale); - -  return { -    props: { -      breadcrumbTitle, -      locale, -      translation, -    }, -  }; -}; - -export default Search; diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx deleted file mode 100644 index 30dd36c..0000000 --- a/src/pages/sujet/[slug].tsx +++ /dev/null @@ -1,224 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import PostPreview from '@components/PostPreview/PostPreview'; -import Sidebar from '@components/Sidebar/Sidebar'; -import Spinner from '@components/Spinner/Spinner'; -import { RelatedThematics, ToC, TopicsList } from '@components/Widgets'; -import { -  getAllTopics, -  getAllTopicsSlug, -  getTopicBySlug, -} from '@services/graphql/queries'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { ArticleMeta } from '@ts/types/articles'; -import { TopicProps, ThematicPreview } from '@ts/types/taxonomies'; -import { settings } from '@utils/config'; -import { getFormattedPaths } from '@utils/helpers/format'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { ParsedUrlQuery } from 'querystring'; -import { useRef } from 'react'; -import { useIntl } from 'react-intl'; -import { Article as Article, Graph, WebPage } from 'schema-dts'; - -const Topic: NextPageWithLayout<TopicProps> = ({ topic, allTopics }) => { -  const intl = useIntl(); -  const relatedThematics = useRef<ThematicPreview[]>([]); -  const router = useRouter(); - -  if (router.isFallback) return <Spinner />; - -  const updateRelatedThematics = (newThematics: ThematicPreview[]) => { -    newThematics.forEach((thematic) => { -      const thematicIndex = relatedThematics.current.findIndex( -        (relatedThematic) => relatedThematic.id === thematic.id -      ); -      const hasThematic = thematicIndex === -1 ? false : true; - -      if (!hasThematic) relatedThematics.current.push(thematic); -    }); -  }; - -  const getPostsList = () => { -    return [...topic.posts].reverse().map((post) => { -      updateRelatedThematics(post.thematics); - -      return ( -        <li key={post.id} className={styles.item}> -          <PostPreview post={post} titleLevel={3} /> -        </li> -      ); -    }); -  }; - -  const meta: ArticleMeta = { -    dates: topic.dates, -    results: topic.posts.length, -    website: topic.officialWebsite, -  }; -  const topicUrl = `${settings.url}${router.asPath}`; - -  const webpageSchema: WebPage = { -    '@id': `${topicUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: topic.seo.title, -    description: topic.seo.metaDesc, -    inLanguage: settings.locales.defaultLocale, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${settings.url}`, -    isPartOf: { -      '@id': `${settings.url}`, -    }, -  }; - -  const publicationDate = new Date(topic.dates.publication); -  const updateDate = new Date(topic.dates.update); - -  const articleSchema: Article = { -    '@id': `${settings.url}/#topic`, -    '@type': 'Article', -    name: topic.title, -    description: topic.intro, -    author: { '@id': `${settings.url}/#branding` }, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    headline: topic.title, -    thumbnailUrl: topic.featuredImage?.sourceUrl, -    image: topic.featuredImage?.sourceUrl, -    inLanguage: settings.locales.defaultLocale, -    isPartOf: { '@id': `${settings.url}/blog` }, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${topicUrl}` }, -    subjectOf: { '@id': `${settings.url}/blog` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, articleSchema], -  }; - -  return ( -    <> -      <Head> -        <title>{topic.seo.title}</title> -        <meta name="description" content={topic.seo.metaDesc} /> -        <meta property="og:url" content={`${topicUrl}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={topic.title} /> -        <meta property="og:description" content={topic.intro} /> -        <meta property="og:image" content={topic.featuredImage?.sourceUrl} /> -        <meta property="og:image:alt" content={topic.featuredImage?.altText} /> -      </Head> -      <Script -        id="schema-subject" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="topic" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader -          cover={topic.featuredImage} -          intro={topic.intro} -          meta={meta} -          title={topic.title} -        /> -        <Sidebar -          position="left" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Table of Contents', -            description: 'TopicPage: ToC sidebar aria-label', -            id: 'lsDB5G', -          })} -        > -          <ToC /> -        </Sidebar> -        <div className={styles.body}> -          <div dangerouslySetInnerHTML={{ __html: topic.content }}></div> -          {topic.posts.length > 0 && ( -            <section className={styles.section}> -              <h2> -                {intl.formatMessage( -                  { -                    defaultMessage: 'All posts in {name}', -                    description: 'TopicPage: posts list title', -                    id: 'FLkF2R', -                  }, -                  { name: topic.title } -                )} -              </h2> -              <ol className={styles.list}>{getPostsList()}</ol> -            </section> -          )} -        </div> -        <Sidebar -          position="right" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Sidebar', -            description: 'TopicPage: right sidebar aria-label', -            id: 'eu3beS', -          })} -        > -          <RelatedThematics thematics={relatedThematics.current} /> -          <TopicsList -            initialData={allTopics} -            title={intl.formatMessage({ -              defaultMessage: 'Others topics', -              description: 'TopicPage: topics list widget title', -              id: '+4tiVb', -            })} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -Topic.getLayout = getLayout; - -interface PostParams extends ParsedUrlQuery { -  slug: string; -} - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const { locale } = context; -  const translation = await loadTranslation(locale); -  const { slug } = context.params as PostParams; -  const topic = await getTopicBySlug(slug); -  const allTopics = await getAllTopics(); -  const breadcrumbTitle = topic.title; - -  return { -    props: { -      allTopics, -      breadcrumbTitle, -      locale, -      topic, -      translation, -    }, -  }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { -  const allTopics = await getAllTopicsSlug(); -  const paths = getFormattedPaths(allTopics); - -  return { -    paths, -    fallback: true, -  }; -}; - -export default Topic; diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx deleted file mode 100644 index db22214..0000000 --- a/src/pages/thematique/[slug].tsx +++ /dev/null @@ -1,214 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import PostPreview from '@components/PostPreview/PostPreview'; -import Sidebar from '@components/Sidebar/Sidebar'; -import Spinner from '@components/Spinner/Spinner'; -import { RelatedTopics, ThematicsList, ToC } from '@components/Widgets'; -import { -  getAllThematics, -  getAllThematicsSlug, -  getThematicBySlug, -} from '@services/graphql/queries'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { ArticleMeta } from '@ts/types/articles'; -import { TopicPreview, ThematicProps } from '@ts/types/taxonomies'; -import { settings } from '@utils/config'; -import { getFormattedPaths } from '@utils/helpers/format'; -import { loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import Script from 'next/script'; -import { ParsedUrlQuery } from 'querystring'; -import { useRef } from 'react'; -import { useIntl } from 'react-intl'; -import { Article, Graph, WebPage } from 'schema-dts'; - -const Thematic: NextPageWithLayout<ThematicProps> = ({ -  thematic, -  allThematics, -}) => { -  const intl = useIntl(); -  const relatedTopics = useRef<TopicPreview[]>([]); -  const router = useRouter(); - -  if (router.isFallback) return <Spinner />; - -  const updateRelatedTopics = (newTopics: TopicPreview[]) => { -    newTopics.forEach((topic) => { -      const topicIndex = relatedTopics.current.findIndex( -        (relatedTopic) => relatedTopic.id === topic.id -      ); -      const hasTopic = topicIndex === -1 ? false : true; - -      if (!hasTopic) relatedTopics.current.push(topic); -    }); -  }; - -  const getPostsList = () => { -    return [...thematic.posts].reverse().map((post) => { -      updateRelatedTopics(post.topics); - -      return ( -        <li key={post.id} className={styles.item}> -          <PostPreview post={post} titleLevel={3} /> -        </li> -      ); -    }); -  }; - -  const meta: ArticleMeta = { -    dates: thematic.dates, -    results: thematic.posts.length, -  }; -  const thematicUrl = `${settings.url}${router.asPath}`; - -  const webpageSchema: WebPage = { -    '@id': `${thematicUrl}`, -    '@type': 'WebPage', -    breadcrumb: { '@id': `${settings.url}/#breadcrumb` }, -    name: thematic.seo.title, -    description: thematic.seo.metaDesc, -    inLanguage: settings.locales.defaultLocale, -    reviewedBy: { '@id': `${settings.url}/#branding` }, -    url: `${settings.url}`, -  }; - -  const publicationDate = new Date(thematic.dates.publication); -  const updateDate = new Date(thematic.dates.update); - -  const articleSchema: Article = { -    '@id': `${settings.url}/#thematic`, -    '@type': 'Article', -    name: thematic.title, -    description: thematic.intro, -    author: { '@id': `${settings.url}/#branding` }, -    copyrightYear: publicationDate.getFullYear(), -    creator: { '@id': `${settings.url}/#branding` }, -    dateCreated: publicationDate.toISOString(), -    dateModified: updateDate.toISOString(), -    datePublished: publicationDate.toISOString(), -    editor: { '@id': `${settings.url}/#branding` }, -    headline: thematic.title, -    inLanguage: settings.locales.defaultLocale, -    isPartOf: { '@id': `${settings.url}/blog` }, -    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', -    mainEntityOfPage: { '@id': `${thematicUrl}` }, -    subjectOf: { '@id': `${settings.url}/blog` }, -  }; - -  const schemaJsonLd: Graph = { -    '@context': 'https://schema.org', -    '@graph': [webpageSchema, articleSchema], -  }; - -  return ( -    <> -      <Head> -        <title>{thematic.seo.title}</title> -        <meta name="description" content={thematic.seo.metaDesc} /> -        <meta property="og:url" content={`${thematic}`} /> -        <meta property="og:type" content="article" /> -        <meta property="og:title" content={thematic.title} /> -        <meta property="og:description" content={thematic.intro} /> -      </Head> -      <Script -        id="schema-thematic" -        type="application/ld+json" -        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} -      /> -      <article -        id="thematic" -        className={`${styles.article} ${styles['article--no-comments']}`} -      > -        <PostHeader intro={thematic.intro} meta={meta} title={thematic.title} /> -        <Sidebar -          position="left" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Table of Contents', -            description: 'ThematicPage: ToC sidebar aria-label', -            id: 'YwvYfw', -          })} -        > -          <ToC /> -        </Sidebar> -        <div className={styles.body}> -          <div dangerouslySetInnerHTML={{ __html: thematic.content }}></div> -          {thematic.posts.length > 0 && ( -            <section className={styles.section}> -              <h2> -                {intl.formatMessage( -                  { -                    defaultMessage: 'All posts in {name}', -                    description: 'ThematicPage: posts list title', -                    id: 'P7fxX2', -                  }, -                  { name: thematic.title } -                )} -              </h2> -              <ol className={styles.list}>{getPostsList()}</ol> -            </section> -          )} -        </div> -        <Sidebar -          position="right" -          ariaLabel={intl.formatMessage({ -            defaultMessage: 'Sidebar', -            description: 'ThematicPage: right sidebar aria-label', -            id: 'syLgY9', -          })} -        > -          <RelatedTopics topics={relatedTopics.current} /> -          <ThematicsList -            initialData={allThematics} -            title={intl.formatMessage({ -              defaultMessage: 'Others thematics', -              description: 'ThematicPage: thematics list widget title', -              id: 'norrGp', -            })} -          /> -        </Sidebar> -      </article> -    </> -  ); -}; - -Thematic.getLayout = getLayout; - -interface PostParams extends ParsedUrlQuery { -  slug: string; -} - -export const getStaticProps: GetStaticProps = async ( -  context: GetStaticPropsContext -) => { -  const { locale } = context; -  const translation = await loadTranslation(locale); -  const { slug } = context.params as PostParams; -  const thematic = await getThematicBySlug(slug); -  const allThematics = await getAllThematics(); -  const breadcrumbTitle = thematic.title; - -  return { -    props: { -      allThematics, -      breadcrumbTitle, -      locale, -      thematic, -      translation, -    }, -  }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { -  const allSlugs = await getAllThematicsSlug(); -  const paths = getFormattedPaths(allSlugs); - -  return { -    paths, -    fallback: true, -  }; -}; - -export default Thematic; | 
