From 947a06bfdfdc5bca62c27fa2ee27f0ab9fefa0ea Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 22 Apr 2022 18:33:04 +0200 Subject: chore: add a TableOfContents component --- .../organisms/widgets/table-of-contents.tsx | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/components/organisms/widgets/table-of-contents.tsx (limited to 'src/components/organisms/widgets/table-of-contents.tsx') diff --git a/src/components/organisms/widgets/table-of-contents.tsx b/src/components/organisms/widgets/table-of-contents.tsx new file mode 100644 index 0000000..3778e02 --- /dev/null +++ b/src/components/organisms/widgets/table-of-contents.tsx @@ -0,0 +1,53 @@ +import useHeadingsTree, { type Heading } from '@utils/hooks/use-headings-tree'; +import { FC } from 'react'; +import { useIntl } from 'react-intl'; +import LinksListWidget, { type LinksListItems } from './links-list-widget'; + +type TableOfContentsProps = { + /** + * A reference to the HTML element that contains the headings. + */ + wrapper: HTMLElement; +}; + +/** + * Table of Contents widget component + * + * Render a table of contents. + */ +const TableOfContents: FC = ({ wrapper }) => { + const intl = useIntl(); + const headingsTree = useHeadingsTree(wrapper); + const title = intl.formatMessage({ + defaultMessage: 'Table of Contents', + description: 'TableOfContents: the widget title', + id: 'WKG9wj', + }); + + /** + * Convert an headings tree to list items. + * + * @param {Heading[]} tree - The headings tree. + * @returns {LinksListItems[]} The list items. + */ + const getItems = (tree: Heading[]): LinksListItems[] => { + return tree.map((heading) => { + return { + name: heading.title, + url: `#${heading.id}`, + child: getItems(heading.children), + }; + }); + }; + + return ( + + ); +}; + +export default TableOfContents; -- cgit v1.2.3 From 83a029084f1bbfd78b7099d9bea3371d4533c6d9 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 3 May 2022 16:51:22 +0200 Subject: chore: add a LegalNotice page --- mdx.d.ts | 10 +- .../molecules/buttons/heading-button.module.scss | 4 +- src/components/molecules/layout/meta.module.scss | 8 +- .../molecules/layout/page-header.module.scss | 7 +- .../widgets/links-list-widget.module.scss | 10 +- .../organisms/widgets/links-list-widget.tsx | 5 +- .../widgets/table-of-contents.module.scss | 4 + .../organisms/widgets/table-of-contents.tsx | 2 + src/pages/mentions-legales.tsx | 140 +++++++++++++++++++++ src/ts/types/app.ts | 16 ++- src/ts/types/mdx.ts | 20 +++ src/ts/types/raw-data.ts | 6 +- src/utils/helpers/author.ts | 10 +- 13 files changed, 209 insertions(+), 33 deletions(-) create mode 100644 src/components/organisms/widgets/table-of-contents.module.scss create mode 100644 src/pages/mentions-legales.tsx create mode 100644 src/ts/types/mdx.ts (limited to 'src/components/organisms/widgets/table-of-contents.tsx') diff --git a/mdx.d.ts b/mdx.d.ts index f3a9a90..b4e333d 100644 --- a/mdx.d.ts +++ b/mdx.d.ts @@ -1,13 +1,9 @@ declare module '*.mdx' { + import { MDXData, MDXPageMeta, MDXProjectMeta } from '@ts/types/mdx'; import { MDXProps } from 'mdx/types'; - import { Meta } from '@ts/types/app'; let MDXComponent: (props: MDXProps) => JSX.Element; export default MDXComponent; - export const cover: string; - export const image: string; - export const intro: string; - export const meta: Meta; - export const pdf: string; - export const seo: { title: string; description: string }; + export const data: MDXData; + export const meta: MDXPageMeta | MDXProjectMeta; } diff --git a/src/components/molecules/buttons/heading-button.module.scss b/src/components/molecules/buttons/heading-button.module.scss index 1d16410..9c278e4 100644 --- a/src/components/molecules/buttons/heading-button.module.scss +++ b/src/components/molecules/buttons/heading-button.module.scss @@ -36,6 +36,8 @@ } .heading { - background: none; padding: var(--spacing-2xs) 0; + background: none; + font-size: var(--font-size-xl); + text-align: left; } diff --git a/src/components/molecules/layout/meta.module.scss b/src/components/molecules/layout/meta.module.scss index f7cc55b..0485545 100644 --- a/src/components/molecules/layout/meta.module.scss +++ b/src/components/molecules/layout/meta.module.scss @@ -2,12 +2,18 @@ .list { display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-columns: repeat(1, minmax(0, 1fr)); + gap: var(--spacing-sm); @include mix.media("screen") { + @include mix.dimensions("2xs") { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + @include mix.dimensions("sm") { display: flex; flex-flow: column nowrap; + gap: var(--spacing-2xs); } } } diff --git a/src/components/molecules/layout/page-header.module.scss b/src/components/molecules/layout/page-header.module.scss index 93f7595..4c7df5f 100644 --- a/src/components/molecules/layout/page-header.module.scss +++ b/src/components/molecules/layout/page-header.module.scss @@ -1,5 +1,4 @@ @use "@styles/abstracts/functions" as fun; -@use "@styles/abstracts/mixins" as mix; @use "@styles/abstracts/placeholders"; .wrapper { @@ -55,9 +54,5 @@ } .meta { - @include mix.media("screen") { - @include mix.dimensions("xs") { - font-size: var(--font-size-sm); - } - } + font-size: var(--font-size-sm); } diff --git a/src/components/organisms/widgets/links-list-widget.module.scss b/src/components/organisms/widgets/links-list-widget.module.scss index cbad83e..4444df4 100644 --- a/src/components/organisms/widgets/links-list-widget.module.scss +++ b/src/components/organisms/widgets/links-list-widget.module.scss @@ -3,6 +3,12 @@ .widget { .list { + .list { + > *:first-child { + border-top: fun.convert-px(1) solid var(--color-primary); + } + } + &__link { display: block; padding: var(--spacing-2xs) var(--spacing-xs); @@ -50,9 +56,7 @@ &__item { &:not(:last-child) { - .list__link { - border-bottom: fun.convert-px(1) solid var(--color-primary); - } + border-bottom: fun.convert-px(1) solid var(--color-primary); } > .list { diff --git a/src/components/organisms/widgets/links-list-widget.tsx b/src/components/organisms/widgets/links-list-widget.tsx index 559d0b6..37a20fc 100644 --- a/src/components/organisms/widgets/links-list-widget.tsx +++ b/src/components/organisms/widgets/links-list-widget.tsx @@ -24,7 +24,7 @@ export type LinksListItems = { }; export type LinksListWidgetProps = Pick & - Pick & { + Pick & { /** * An array of name/url couple. */ @@ -37,6 +37,7 @@ export type LinksListWidgetProps = Pick & * Render a list of links inside a widget. */ const LinksListWidget: FC = ({ + className = '', items, kind = 'unordered', ...props @@ -74,7 +75,7 @@ const LinksListWidget: FC = ({ items={getListItems(items)} kind={kind} withMargin={false} - className={`${styles.list} ${styles[listKindClass]}`} + className={`${styles.list} ${styles[listKindClass]} ${className}`} itemsClassName={styles.list__item} /> diff --git a/src/components/organisms/widgets/table-of-contents.module.scss b/src/components/organisms/widgets/table-of-contents.module.scss new file mode 100644 index 0000000..36217ed --- /dev/null +++ b/src/components/organisms/widgets/table-of-contents.module.scss @@ -0,0 +1,4 @@ +.list { + font-size: var(--font-size-sm); + font-weight: 500; +} diff --git a/src/components/organisms/widgets/table-of-contents.tsx b/src/components/organisms/widgets/table-of-contents.tsx index 3778e02..800ff58 100644 --- a/src/components/organisms/widgets/table-of-contents.tsx +++ b/src/components/organisms/widgets/table-of-contents.tsx @@ -2,6 +2,7 @@ import useHeadingsTree, { type Heading } from '@utils/hooks/use-headings-tree'; import { FC } from 'react'; import { useIntl } from 'react-intl'; import LinksListWidget, { type LinksListItems } from './links-list-widget'; +import styles from './table-of-contents.module.scss'; type TableOfContentsProps = { /** @@ -46,6 +47,7 @@ const TableOfContents: FC = ({ wrapper }) => { title={title} level={2} items={getItems(headingsTree)} + className={styles.list} /> ); }; diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx new file mode 100644 index 0000000..8dd0a1d --- /dev/null +++ b/src/pages/mentions-legales.tsx @@ -0,0 +1,140 @@ +import Link from '@components/atoms/links/link'; +import ResponsiveImage from '@components/molecules/images/responsive-image'; +import { type BreadcrumbItem } from '@components/molecules/nav/breadcrumb'; +import PageLayout, { + type PageLayoutProps, +} from '@components/templates/page/page-layout'; +import LegalNoticeContent, { meta } from '@content/pages/legal-notice.mdx'; +import { getFormattedDate } from '@utils/helpers/dates'; +import { loadTranslation } from '@utils/helpers/i18n'; +import useSettings from '@utils/hooks/use-settings'; +import { NestedMDXComponents } from 'mdx/types'; +import { GetStaticProps, NextPage } 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'; + +/** + * Legal Notice page. + */ +const LegalNoticePage: NextPage = () => { + const intl = useIntl(); + const { dates, intro, seo, title } = meta; + const homeLabel = intl.formatMessage({ + defaultMessage: 'Home', + description: 'Breadcrumb: home label', + id: 'j5k9Fe', + }); + const breadcrumb: BreadcrumbItem[] = [ + { id: 'home', name: homeLabel, url: '/' }, + { id: 'legal-notice', name: title, url: '/mentions-legales' }, + ]; + + const publicationLabel = intl.formatMessage({ + defaultMessage: 'Published on:', + description: 'Meta: publication date label', + id: 'QGi5uD', + }); + + const updateLabel = intl.formatMessage({ + defaultMessage: 'Updated on:', + description: 'Meta: update date label', + id: 'tLC7bh', + }); + + const headerMeta: PageLayoutProps['headerMeta'] = { + publication: { + name: publicationLabel, + value: getFormattedDate(dates.publication), + }, + update: { name: updateLabel, value: getFormattedDate(dates.update) }, + }; + + const components: NestedMDXComponents = { + Image: (props) => , + Link: (props) => , + }; + + const { website } = useSettings(); + const { asPath } = useRouter(); + const pageUrl = `${website.url}${asPath}`; + const pagePublicationDate = new Date(dates.publication); + const pageUpdateDate = new Date(dates.update); + + const webpageSchema: WebPage = { + '@id': `${pageUrl}`, + '@type': 'WebPage', + breadcrumb: { '@id': `${website.url}/#breadcrumb` }, + name: seo.title, + description: seo.description, + inLanguage: website.locales.default, + license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr', + reviewedBy: { '@id': `${website.url}/#branding` }, + url: `${pageUrl}`, + isPartOf: { + '@id': `${website.url}`, + }, + }; + + const articleSchema: Article = { + '@id': `${website.url}/#legal-notice`, + '@type': 'Article', + name: title, + description: intro, + author: { '@id': `${website.url}/#branding` }, + copyrightYear: pagePublicationDate.getFullYear(), + creator: { '@id': `${website.url}/#branding` }, + dateCreated: pagePublicationDate.toISOString(), + dateModified: pageUpdateDate.toISOString(), + datePublished: pagePublicationDate.toISOString(), + editor: { '@id': `${website.url}/#branding` }, + headline: title, + inLanguage: website.locales.default, + 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 ( + + + {`${seo.title} - ${website.name}`} + + + + + + +