diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-11-14 12:39:09 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-14 12:50:32 +0100 |
| commit | 50f1c501a87ef5f5650750dbeca797e833ec7c3a (patch) | |
| tree | f1f55092696c7261eaa7f9f9a9338253ede65c2b /src | |
| parent | fb29b0f017fae162ffa7ad6bdfc80099346802de (diff) | |
refactor(components): replace Sharing with SharingWidget component
* all the widgets should have a coherent name
* fix mailto uri
* remove useless CSS
* add tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/organisms/widgets/index.ts | 2 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing-widget/index.ts | 1 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing-widget/sharing-widget.stories.tsx (renamed from src/components/organisms/widgets/sharing.stories.tsx) | 23 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing-widget/sharing-widget.test.tsx | 167 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing-widget/sharing-widget.tsx | 161 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing.module.scss | 8 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing.test.tsx | 24 | ||||
| -rw-r--r-- | src/components/organisms/widgets/sharing.tsx | 259 | ||||
| -rw-r--r-- | src/components/templates/page/page-layout.stories.tsx | 8 | ||||
| -rw-r--r-- | src/i18n/en.json | 74 | ||||
| -rw-r--r-- | src/i18n/fr.json | 74 | ||||
| -rw-r--r-- | src/pages/article/[slug].tsx | 11 | ||||
| -rw-r--r-- | src/pages/projets/[slug].tsx | 10 | ||||
| -rw-r--r-- | src/styles/pages/article.module.scss | 5 |
14 files changed, 431 insertions, 396 deletions
diff --git a/src/components/organisms/widgets/index.ts b/src/components/organisms/widgets/index.ts index 03f845f..2286898 100644 --- a/src/components/organisms/widgets/index.ts +++ b/src/components/organisms/widgets/index.ts @@ -1,5 +1,5 @@ export * from './image-widget'; export * from './links-list-widget'; -export * from './sharing'; +export * from './sharing-widget'; export * from './social-media-widget'; export * from './table-of-contents'; diff --git a/src/components/organisms/widgets/sharing-widget/index.ts b/src/components/organisms/widgets/sharing-widget/index.ts new file mode 100644 index 0000000..dd78023 --- /dev/null +++ b/src/components/organisms/widgets/sharing-widget/index.ts @@ -0,0 +1 @@ +export * from './sharing-widget'; diff --git a/src/components/organisms/widgets/sharing.stories.tsx b/src/components/organisms/widgets/sharing-widget/sharing-widget.stories.tsx index d2be621..3e3cb68 100644 --- a/src/components/organisms/widgets/sharing.stories.tsx +++ b/src/components/organisms/widgets/sharing-widget/sharing-widget.stories.tsx @@ -1,26 +1,14 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Sharing as SharingWidget } from './sharing'; +import { Heading } from '../../../atoms'; +import { SharingWidget } from './sharing-widget'; /** - * Sharing - Storybook Meta + * SharingWidget - Storybook Meta */ export default { - title: 'Organisms/Widgets', + title: 'Organisms/Widgets/Sharing', component: SharingWidget, argTypes: { - className: { - control: { - type: 'text', - }, - description: 'Set additional classnames to the sharing links list.', - table: { - category: 'Styles', - }, - type: { - name: 'string', - required: false, - }, - }, data: { description: 'The page data.', type: { @@ -47,7 +35,7 @@ const Template: ComponentStory<typeof SharingWidget> = (args) => ( ); /** - * Widgets Stories - Sharing + * SharingWidget Stories - Sharing */ export const Sharing = Template.bind({}); Sharing.args = { @@ -57,5 +45,6 @@ Sharing.args = { title: 'Accusantium totam nostrum', url: 'https://www.example.test', }, + heading: <Heading level={3}>Share</Heading>, media: ['diaspora', 'facebook', 'linkedin', 'twitter', 'email'], }; diff --git a/src/components/organisms/widgets/sharing-widget/sharing-widget.test.tsx b/src/components/organisms/widgets/sharing-widget/sharing-widget.test.tsx new file mode 100644 index 0000000..b8bc702 --- /dev/null +++ b/src/components/organisms/widgets/sharing-widget/sharing-widget.test.tsx @@ -0,0 +1,167 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '../../../../../tests/utils'; +import { Heading, type SharingMedium } from '../../../atoms'; +import { SharingWidget, type SharingData } from './sharing-widget'; + +const data: SharingData = { + excerpt: 'A post excerpt', + title: 'A post title', + url: 'https://sharing-website.test', +}; + +describe('SharingWidget', () => { + it('renders the widget heading and a list of links', () => { + const heading = 'dolorem necessitatibus voluptatem'; + const headingLvl = 3; + const media = ['facebook', 'twitter'] satisfies SharingMedium[]; + + render( + <SharingWidget + data={data} + heading={<Heading level={headingLvl}>{heading}</Heading>} + media={media} + /> + ); + + expect( + rtlScreen.getByRole('heading', { level: headingLvl }) + ).toHaveTextContent(heading); + expect(rtlScreen.getAllByRole('listitem')).toHaveLength(media.length); + expect(rtlScreen.getAllByRole('link')).toHaveLength(media.length); + }); + + it('can render a link to share on Diaspora', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['diaspora']} + /> + ); + + const link = rtlScreen.getByRole('link'); + + expect(link).toHaveTextContent('Share on Diaspora'); + expect(link).toHaveAttribute( + 'href', + `https://share.diasporafoundation.org/?title=${encodeURIComponent( + data.title + )}&url=${encodeURIComponent(data.url)}` + ); + }); + + it('can render a link to share on Facebook', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['facebook']} + /> + ); + + const link = rtlScreen.getByRole('link'); + + expect(link).toHaveTextContent('Share on Facebook'); + expect(link).toHaveAttribute( + 'href', + `https://www.facebook.com/sharer/sharer.php?$u=${encodeURIComponent( + data.url + )}` + ); + }); + + it('can render a link to share on Journal du Hacker', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['journal-du-hacker']} + /> + ); + + const link = rtlScreen.getByRole('link'); + + expect(link).toHaveTextContent('Share on Journal du Hacker'); + expect(link).toHaveAttribute( + 'href', + `https://www.journalduhacker.net/stories/new?title=${encodeURIComponent( + data.title + )}&url=${encodeURIComponent(data.url)}` + ); + }); + + it('can render a link to share on LinkedIn', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['linkedin']} + /> + ); + + const link = rtlScreen.getByRole('link'); + + expect(link).toHaveTextContent('Share on LinkedIn'); + expect(link).toHaveAttribute( + 'href', + `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent( + data.url + )}` + ); + }); + + it('can render a link to share on Twitter', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['twitter']} + /> + ); + + const link = rtlScreen.getByRole('link'); + + expect(link).toHaveTextContent('Share on Twitter'); + expect(link).toHaveAttribute( + 'href', + `https://twitter.com/intent/tweet?text=${encodeURIComponent( + data.title + )}&url=${encodeURIComponent(data.url)}` + ); + }); + + it('can render a link to share by Email', () => { + render( + <SharingWidget + data={data} + heading={<Heading level={3}>corrupti</Heading>} + media={['email']} + /> + ); + + const link = rtlScreen.getByRole('link'); + const subject = `You should read ${data.title}`; + const body = `${data.excerpt}\n\nRead more here: ${data.url}`; + + expect(link).toHaveTextContent('Share by Email'); + expect(link).toHaveAttribute( + 'href', + `mailto:?body=${encodeURIComponent(body)}&subject=${encodeURIComponent( + subject + )}` + ); + }); + + it('throws an error when a medium is invalid', () => { + expect(() => + render( + <SharingWidget + data={data} + heading={<Heading level={3}>maxime</Heading>} + // @ts-expect-error -- Unsupported medium + media={['not-supported']} + /> + ) + ).toThrowError('Unsupported social media.'); + }); +}); diff --git a/src/components/organisms/widgets/sharing-widget/sharing-widget.tsx b/src/components/organisms/widgets/sharing-widget/sharing-widget.tsx new file mode 100644 index 0000000..afac177 --- /dev/null +++ b/src/components/organisms/widgets/sharing-widget/sharing-widget.tsx @@ -0,0 +1,161 @@ +import { type ForwardRefRenderFunction, forwardRef, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import { + List, + ListItem, + SharingLink, + type SharingMedium, +} from '../../../atoms'; +import { Collapsible, type CollapsibleProps } from '../../../molecules'; + +export type SharingData = { + /** + * The content excerpt. + */ + excerpt: string; + /** + * The content title. + */ + title: string; + /** + * The content url. + */ + url: string; +}; + +const getUrl = ( + medium: Exclude<SharingMedium, 'email'>, + data: Omit<SharingData, 'excerpt'> +) => { + const title = encodeURIComponent(data.title); + const url = encodeURIComponent(data.url); + + switch (medium) { + case 'diaspora': + return `https://share.diasporafoundation.org/?title=${title}&url=${url}`; + case 'facebook': + return `https://www.facebook.com/sharer/sharer.php?$u=${url}`; + case 'journal-du-hacker': + return `https://www.journalduhacker.net/stories/new?title=${title}&url=${url}`; + case 'linkedin': + return `https://www.linkedin.com/sharing/share-offsite/?url=${url}`; + case 'twitter': + return `https://twitter.com/intent/tweet?text=${title}&url=${url}`; + default: + throw new Error('Unsupported social media.'); + } +}; + +export type SharingWidgetProps = Omit< + CollapsibleProps, + 'children' | 'disablePadding' | 'hasBorders' +> & { + /** + * The page data to share. + */ + data: SharingData; + /** + * An ordered list of sharing medium to activate. + */ + media: SharingMedium[]; +}; + +const SharingWidgetWithRef: ForwardRefRenderFunction< + HTMLDivElement, + SharingWidgetProps +> = ({ data, media, ...props }, ref) => { + const intl = useIntl(); + const labels: Record<SharingMedium, string> = { + 'journal-du-hacker': intl.formatMessage({ + defaultMessage: 'Share on Journal du Hacker', + description: 'SharingWidget: Journal du Hacker sharing link', + id: 'Hclr0a', + }), + diaspora: intl.formatMessage({ + defaultMessage: 'Share on Diaspora', + description: 'SharingWidget: Diaspora sharing link', + id: '0f7fty', + }), + email: intl.formatMessage({ + defaultMessage: 'Share by Email', + description: 'SharingWidget: Email sharing link', + id: 'OWygWB', + }), + facebook: intl.formatMessage({ + defaultMessage: 'Share on Facebook', + description: 'SharingWidget: Facebook sharing link', + id: 'WzYUm5', + }), + linkedin: intl.formatMessage({ + defaultMessage: 'Share on LinkedIn', + description: 'SharingWidget: LinkedIn sharing link', + id: 'ofQPC+', + }), + twitter: intl.formatMessage({ + defaultMessage: 'Share on Twitter', + description: 'SharingWidget: Twitter sharing link', + id: 'QdBC6q', + }), + }; + + /** + * Build the mailto url from provided data. + * + * @returns {string} The mailto url with params. + */ + const buildEmailUrl = useCallback((): string => { + const readMore = intl.formatMessage({ + defaultMessage: 'Read more here:', + description: 'SharingWidget: content link prefix', + id: 'AsXE0d', + }); + const excerpt = data.excerpt + .replace(/<[^>]+>/gi, '') + .replaceAll(' ', ' '); + const body = `${excerpt}\n\n${readMore} ${data.url}`; + const subject = intl.formatMessage( + { + defaultMessage: 'You should read {title}', + description: 'SharingWidget: subject text', + id: 'BLq3+e', + }, + { title: data.title } + ); + + return `mailto:?body=${encodeURIComponent( + body + )}&subject=${encodeURIComponent(subject)}`; + }, [data, intl]); + + return ( + <Collapsible {...props} ref={ref}> + <List + hideMarker + isInline + // eslint-disable-next-line react/jsx-no-literals + spacing="xs" + > + {media.map((medium) => ( + <ListItem key={medium}> + <SharingLink + label={labels[medium]} + medium={medium} + url={ + medium === 'email' + ? buildEmailUrl() + : getUrl(medium, { title: data.title, url: data.url }) + } + /> + </ListItem> + ))} + </List> + </Collapsible> + ); +}; + +/** + * Sharing widget component + * + * Render a list of sharing links inside a widget. + */ +export const SharingWidget = forwardRef(SharingWidgetWithRef); diff --git a/src/components/organisms/widgets/sharing.module.scss b/src/components/organisms/widgets/sharing.module.scss deleted file mode 100644 index 24f6fc9..0000000 --- a/src/components/organisms/widgets/sharing.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.list { - display: flex; - flex-flow: row wrap; - gap: var(--spacing-xs); - margin: 0; - padding: 0 var(--spacing-2xs); - list-style-type: none; -} diff --git a/src/components/organisms/widgets/sharing.test.tsx b/src/components/organisms/widgets/sharing.test.tsx deleted file mode 100644 index c7211f0..0000000 --- a/src/components/organisms/widgets/sharing.test.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen as rtlScreen } from '../../../../tests/utils'; -import { Sharing, type SharingData } from './sharing'; - -const postData: SharingData = { - excerpt: 'A post excerpt', - title: 'A post title', - url: 'https://sharing-website.test', -}; - -describe('Sharing', () => { - it('renders a sharing widget', () => { - render(<Sharing data={postData} media={['facebook', 'twitter']} />); - expect( - rtlScreen.getByRole('link', { name: 'Share on Facebook' }) - ).toBeInTheDocument(); - expect( - rtlScreen.getByRole('link', { name: 'Share on Twitter' }) - ).toBeInTheDocument(); - expect( - rtlScreen.queryByRole('link', { name: 'Share on LinkedIn' }) - ).not.toBeInTheDocument(); - }); -}); diff --git a/src/components/organisms/widgets/sharing.tsx b/src/components/organisms/widgets/sharing.tsx deleted file mode 100644 index 47ec49d..0000000 --- a/src/components/organisms/widgets/sharing.tsx +++ /dev/null @@ -1,259 +0,0 @@ -import type { FC } from 'react'; -import { useIntl } from 'react-intl'; -import { Heading, SharingLink, type SharingMedium } from '../../atoms'; -import { Collapsible, type CollapsibleProps } from '../../molecules'; -import styles from './sharing.module.scss'; - -/** - * Build the Diaspora sharing url with provided data. - * - * @param {string} title - The content title. - * @param {string} url - The content url. - * @returns {string} The Diaspora url. - */ -const buildDiasporaUrl = (title: string, url: string): string => { - const titleParam = `title=${encodeURI(title)}`; - const urlParam = `url=${encodeURI(url)}`; - return `https://share.diasporafoundation.org/?${titleParam}&${urlParam}`; -}; - -/** - * Build the Facebook sharing url with provided data. - * - * @param {string} url - The content url. - * @returns {string} The Facebook url. - */ -const buildFacebookUrl = (url: string): string => { - const urlParam = `u=${encodeURI(url)}`; - return `https://www.facebook.com/sharer/sharer.php?${urlParam}`; -}; - -/** - * Build the Journal du Hacker sharing url with provided data. - * - * @param {string} title - The content title. - * @param {string} url - The content url. - * @returns {string} The Journal du Hacker url. - */ -const buildJdHUrl = (title: string, url: string): string => { - const titleParam = `title=${encodeURI(title)}`; - const urlParam = `url=${encodeURI(url)}`; - return `https://www.journalduhacker.net/stories/new?${titleParam}&${urlParam}`; -}; - -/** - * Build the LinkedIn sharing url with provided data. - * - * @param {string} url - The content url. - * @returns {string} The LinkedIn url. - */ -const buildLinkedInUrl = (url: string): string => { - const urlParam = `url=${encodeURI(url)}`; - return `https://www.linkedin.com/sharing/share-offsite/?${urlParam}`; -}; - -/** - * Build the Twitter sharing url with provided data. - * - * @param {string} title - The content title. - * @param {string} url - The content url. - * @returns {string} The Twitter url. - */ -const buildTwitterUrl = (title: string, url: string): string => { - const titleParam = `text=${encodeURI(title)}`; - const urlParam = `url=${encodeURI(url)}`; - return `https://twitter.com/intent/tweet?${titleParam}&${urlParam}`; -}; - -export type SharingData = { - /** - * The content excerpt. - */ - excerpt: string; - /** - * The content title. - */ - title: string; - /** - * The content url. - */ - url: string; -}; - -export type SharingProps = Omit<CollapsibleProps, 'children' | 'heading'> & { - /** - * Set additional classnames to the sharing links list. - */ - className?: string; - /** - * The page data to share. - */ - data: SharingData; - /** - * A list of active and ordered sharing medium. - */ - media: SharingMedium[]; -}; - -/** - * Sharing widget component - * - * Render a list of sharing links inside a widget. - */ -export const Sharing: FC<SharingProps> = ({ - className = '', - data, - media, - ...props -}) => { - const listClass = `${styles.list} ${className}`; - const intl = useIntl(); - const widgetTitle = intl.formatMessage({ - defaultMessage: 'Share', - id: 'q3U6uI', - description: 'Sharing: widget title', - }); - - /** - * Build the mailto url from provided data. - * - * @param {string} excerpt - The content excerpt. - * @param {string} title - The content title. - * @param {string} url - The content url. - * @returns {string} The mailto url with params. - */ - const buildEmailUrl = ( - excerpt: string, - title: string, - url: string - ): string => { - const intro = intl.formatMessage({ - defaultMessage: 'Introduction:', - description: 'Sharing: email content prefix', - id: 'yfgMcl', - }); - const readMore = intl.formatMessage({ - defaultMessage: 'Read more here:', - description: 'Sharing: content link prefix', - id: 'UsQske', - }); - const body = `${intro}\n\n"${excerpt}"\n\n${readMore} ${url}`; - const bodyParam = excerpt ? `body=${encodeURI(body)}` : ''; - - const subject = intl.formatMessage( - { - defaultMessage: 'You should read {title}', - description: 'Sharing: subject text', - id: 'azgQuH', - }, - { title } - ); - const subjectParam = `subject=${encodeURI(subject)}`; - - return `mailto:?${bodyParam}&${subjectParam}`; - }; - - /** - * Retrieve the sharing label by medium id. - * - * @param {SharingMedium} medium - A sharing medium id. - * @returns {string} The sharing label. - */ - const getLabel = (medium: SharingMedium): string => { - switch (medium) { - case 'diaspora': - return intl.formatMessage({ - defaultMessage: 'Share on Diaspora', - description: 'Sharing: Diaspora sharing link', - id: 'oVLRW8', - }); - case 'email': - return intl.formatMessage({ - defaultMessage: 'Share by Email', - description: 'Sharing: Email sharing link', - id: '2ukj9H', - }); - case 'facebook': - return intl.formatMessage({ - defaultMessage: 'Share on Facebook', - description: 'Sharing: Facebook sharing link', - id: 'o0DAK4', - }); - case 'journal-du-hacker': - return intl.formatMessage({ - defaultMessage: 'Share on Journal du Hacker', - description: 'Sharing: Journal du Hacker sharing link', - id: 'vnbryZ', - }); - case 'linkedin': - return intl.formatMessage({ - defaultMessage: 'Share on LinkedIn', - description: 'Sharing: LinkedIn sharing link', - id: 'Y+DYja', - }); - case 'twitter': - default: - return intl.formatMessage({ - defaultMessage: 'Share on Twitter', - description: 'Sharing: Twitter sharing link', - id: 'NI5gXc', - }); - } - }; - - /** - * Retrieve the sharing url by medium id. - * - * @param {SharingMedium} medium - A sharing medium id. - * @returns {string} The sharing url. - */ - const getUrl = (medium: SharingMedium): string => { - const { excerpt, title, url } = data; - - switch (medium) { - case 'diaspora': - return buildDiasporaUrl(title, url); - case 'email': - return buildEmailUrl(excerpt, title, url); - case 'facebook': - return buildFacebookUrl(url); - case 'journal-du-hacker': - return buildJdHUrl(title, url); - case 'linkedin': - return buildLinkedInUrl(url); - case 'twitter': - return buildTwitterUrl(title, url); - default: - return '#'; - } - }; - - /** - * Get the sharing list items. - * - * @returns {JSX.Element[]} The sharing links wrapped with li element. - */ - const getItems = (): JSX.Element[] => - media.map((medium) => ( - <li key={medium}> - <SharingLink - label={getLabel(medium)} - medium={medium} - url={getUrl(medium)} - /> - </li> - )); - - return ( - <Collapsible - {...props} - heading={ - <Heading isFake level={3}> - {widgetTitle} - </Heading> - } - > - <ul className={listClass}>{getItems()}</ul> - </Collapsible> - ); -}; diff --git a/src/components/templates/page/page-layout.stories.tsx b/src/components/templates/page/page-layout.stories.tsx index 20740db..9f0cce1 100644 --- a/src/components/templates/page/page-layout.stories.tsx +++ b/src/components/templates/page/page-layout.stories.tsx @@ -1,6 +1,6 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; import { ButtonLink, Heading, Link } from '../../atoms'; -import { LinksListWidget, PostsList, Sharing } from '../../organisms'; +import { LinksListWidget, PostsList, SharingWidget } from '../../organisms'; import { LayoutBase } from '../layout/layout.stories'; import { PageLayout as PageLayoutComponent } from './page-layout'; @@ -239,9 +239,10 @@ SinglePage.args = { </> ), widgets: [ - <Sharing + <SharingWidget key="sidebar2-widget1" data={{ excerpt: pageIntro, title: pageTitle, url: '#' }} + heading={<Heading level={3}>Share</Heading>} media={[ 'diaspora', 'email', @@ -330,9 +331,10 @@ Post.args = { </> ), widgets: [ - <Sharing + <SharingWidget key="sidebar2-widget1" data={{ excerpt: pageIntro, title: pageTitle, url: '#' }} + heading={<Heading level={3}>Share</Heading>} media={[ 'diaspora', 'email', diff --git a/src/i18n/en.json b/src/i18n/en.json index 2b18178..02fe61b 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -31,6 +31,10 @@ "defaultMessage": "Related thematics", "description": "TopicPage: related thematics list widget title" }, + "0f7fty": { + "defaultMessage": "Share on Diaspora", + "description": "SharingWidget: Diaspora sharing link" + }, "0gVlI3": { "defaultMessage": "Tracking:", "description": "AckeeToggle: select label" @@ -75,10 +79,6 @@ "defaultMessage": "Written by:", "description": "PostPreviewMeta: author label" }, - "2ukj9H": { - "defaultMessage": "Share by Email", - "description": "Sharing: Email sharing link" - }, "310o3F": { "defaultMessage": "Error 404: Page not found - {websiteName}", "description": "404Page: SEO - Page title" @@ -191,6 +191,10 @@ "defaultMessage": "Pagination", "description": "BlogPage: pagination accessible name" }, + "AsXE0d": { + "defaultMessage": "Read more here:", + "description": "SharingWidget: content link prefix" + }, "B1lS/v": { "defaultMessage": "Reading time:", "description": "PostPreviewMeta: reading time label" @@ -203,6 +207,10 @@ "defaultMessage": "Others formats", "description": "CVPage: cv preview widget title" }, + "BLq3+e": { + "defaultMessage": "You should read {title}", + "description": "SharingWidget: subject text" + }, "BYdQze": { "defaultMessage": "Read more<a11y> about {postTitle}</a11y>", "description": "PostPreview: read more link" @@ -267,6 +275,14 @@ "defaultMessage": "Reading time:", "description": "ArticlePage: reading time label" }, + "HKKkQk": { + "defaultMessage": "Share", + "description": "SharingWidget: widget title" + }, + "Hclr0a": { + "defaultMessage": "Share on Journal du Hacker", + "description": "SharingWidget: Journal du Hacker sharing link" + }, "HohQPh": { "defaultMessage": "Thematics", "description": "Error404Page: thematics list widget title" @@ -343,10 +359,6 @@ "defaultMessage": "Topics", "description": "SearchPage: topics list widget title" }, - "NI5gXc": { - "defaultMessage": "Share on Twitter", - "description": "Sharing: Twitter sharing link" - }, "NfAn9N": { "defaultMessage": "{commentsCount, plural, =0 {No comments} one {# comment} other {# comments}}<a11y> about {title}</a11y>", "description": "PostPreviewMeta: comments count" @@ -367,6 +379,10 @@ "defaultMessage": "Technologies:", "description": "ProjectOverview: technologies label" }, + "OWygWB": { + "defaultMessage": "Share by Email", + "description": "SharingWidget: Email sharing link" + }, "OevMeU": { "defaultMessage": "{minutesCount} minutes {secondsCount} seconds", "description": "useReadingTime: minutes + seconds count" @@ -395,6 +411,10 @@ "defaultMessage": "Reply", "description": "CommentsList: reply button" }, + "QdBC6q": { + "defaultMessage": "Share on Twitter", + "description": "SharingWidget: Twitter sharing link" + }, "Qh2CwH": { "defaultMessage": "Find me elsewhere", "description": "ContactPage: social media widget title" @@ -435,10 +455,6 @@ "defaultMessage": "Published on:", "description": "ThematicPage: publication date label" }, - "UsQske": { - "defaultMessage": "Read more here:", - "description": "Sharing: content link prefix" - }, "VkAnvv": { "defaultMessage": "Send", "description": "ContactForm: send button" @@ -463,6 +479,10 @@ "defaultMessage": "Search", "description": "SearchForm: button accessible name" }, + "WzYUm5": { + "defaultMessage": "Share on Facebook", + "description": "SharingWidget: Facebook sharing link" + }, "X8oujO": { "defaultMessage": "Search for:", "description": "SearchForm: field accessible label" @@ -475,10 +495,6 @@ "defaultMessage": "Open search", "description": "Layout: search button label in navbar" }, - "Y+DYja": { - "defaultMessage": "Share on LinkedIn", - "description": "Sharing: LinkedIn sharing link" - }, "YV//MH": { "defaultMessage": "No results found.", "description": "SearchPage: no results" @@ -511,10 +527,6 @@ "defaultMessage": "{topicsCount, plural, =0 {Topics:} one {Topic:} other {Topics:}}", "description": "PostPreviewMeta: topics label" }, - "azgQuH": { - "defaultMessage": "You should read {title}", - "description": "Sharing: subject text" - }, "bPv0VG": { "defaultMessage": "Contact form", "description": "Contact: form accessible name" @@ -651,17 +663,13 @@ "defaultMessage": "Legal notice", "description": "Layout: Legal notice label" }, - "o0DAK4": { - "defaultMessage": "Share on Facebook", - "description": "Sharing: Facebook sharing link" - }, "o3WSz5": { "defaultMessage": "Settings", "description": "Layout: settings modal title in navbar" }, - "oVLRW8": { - "defaultMessage": "Share on Diaspora", - "description": "Sharing: Diaspora sharing link" + "ofQPC+": { + "defaultMessage": "Share on LinkedIn", + "description": "SharingWidget: LinkedIn sharing link" }, "og/zWL": { "defaultMessage": "Dark theme", @@ -683,10 +691,6 @@ "defaultMessage": "Discover search results for {query} on {websiteName}.", "description": "SearchPage: SEO - Meta description" }, - "q3U6uI": { - "defaultMessage": "Share", - "description": "Sharing: widget title" - }, "qnwsWV": { "defaultMessage": "Projects", "description": "Layout: main nav - projects link" @@ -751,10 +755,6 @@ "defaultMessage": "Web development", "description": "HomePage: link to web development thematic" }, - "vnbryZ": { - "defaultMessage": "Share on Journal du Hacker", - "description": "Sharing: Journal du Hacker sharing link" - }, "vtDLzG": { "defaultMessage": "Would you like to try a new search?", "description": "SearchPage: try a new search message" @@ -787,10 +787,6 @@ "defaultMessage": "Message:", "description": "ContactForm: message label" }, - "yfgMcl": { - "defaultMessage": "Introduction:", - "description": "Sharing: email content prefix" - }, "zEN3fd": { "defaultMessage": "All posts in {topicName}", "description": "TopicPage: posts list heading" diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 1dd1688..27eb582 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -31,6 +31,10 @@ "defaultMessage": "Thématiques liées", "description": "TopicPage: related thematics list widget title" }, + "0f7fty": { + "defaultMessage": "Partager sur Diaspora", + "description": "SharingWidget: Diaspora sharing link" + }, "0gVlI3": { "defaultMessage": "Suivi :", "description": "AckeeToggle: select label" @@ -75,10 +79,6 @@ "defaultMessage": "Écrit par :", "description": "PostPreviewMeta: author label" }, - "2ukj9H": { - "defaultMessage": "Partager par email", - "description": "Sharing: Email sharing link" - }, "310o3F": { "defaultMessage": "Erreur 404 : Page non trouvée - {websiteName}", "description": "404Page: SEO - Page title" @@ -191,6 +191,10 @@ "defaultMessage": "Pagination", "description": "BlogPage: pagination accessible name" }, + "AsXE0d": { + "defaultMessage": "En lire plus ici :", + "description": "SharingWidget: content link prefix" + }, "B1lS/v": { "defaultMessage": "Temps de lecture :", "description": "PostPreviewMeta: reading time label" @@ -203,6 +207,10 @@ "defaultMessage": "Autres formats", "description": "CVPage: cv preview widget title" }, + "BLq3+e": { + "defaultMessage": "Vous devriez lire {title}", + "description": "SharingWidget: subject text" + }, "BYdQze": { "defaultMessage": "En lire plus<a11y> à propos de {postTitle}</a11y>", "description": "PostPreview: read more link" @@ -267,6 +275,14 @@ "defaultMessage": "Temps de lecture :", "description": "ArticlePage: reading time label" }, + "HKKkQk": { + "defaultMessage": "Partager", + "description": "SharingWidget: widget title" + }, + "Hclr0a": { + "defaultMessage": "Partager sur le Journal du Hacker", + "description": "SharingWidget: Journal du Hacker sharing link" + }, "HohQPh": { "defaultMessage": "Thématiques", "description": "Error404Page: thematics list widget title" @@ -343,10 +359,6 @@ "defaultMessage": "Sujets", "description": "SearchPage: topics list widget title" }, - "NI5gXc": { - "defaultMessage": "Partager sur Twitter", - "description": "Sharing: Twitter sharing link" - }, "NfAn9N": { "defaultMessage": "{commentsCount, plural, =0 {0 commentaire} one {# commentaire} other {# commentaires}}<a11y> à propos de {title}</a11y>", "description": "PostPreviewMeta: comments count" @@ -367,6 +379,10 @@ "defaultMessage": "Technologies :", "description": "ProjectOverview: technologies label" }, + "OWygWB": { + "defaultMessage": "Partager par email", + "description": "SharingWidget: Email sharing link" + }, "OevMeU": { "defaultMessage": "{minutesCount} minutes {secondsCount} secondes", "description": "useReadingTime: minutes + seconds count" @@ -395,6 +411,10 @@ "defaultMessage": "Répondre", "description": "CommentsList: reply button" }, + "QdBC6q": { + "defaultMessage": "Partager sur Twitter", + "description": "SharingWidget: Twitter sharing link" + }, "Qh2CwH": { "defaultMessage": "Retrouvez-moi ailleurs", "description": "ContactPage: social media widget title" @@ -435,10 +455,6 @@ "defaultMessage": "Publié le :", "description": "ThematicPage: publication date label" }, - "UsQske": { - "defaultMessage": "En lire plus ici :", - "description": "Sharing: content link prefix" - }, "VkAnvv": { "defaultMessage": "Envoyer", "description": "ContactForm: send button" @@ -463,6 +479,10 @@ "defaultMessage": "Rechercher", "description": "SearchForm: button accessible name" }, + "WzYUm5": { + "defaultMessage": "Partager sur Facebook", + "description": "SharingWidget: Facebook sharing link" + }, "X8oujO": { "defaultMessage": "Rechercher :", "description": "SearchForm: field accessible label" @@ -475,10 +495,6 @@ "defaultMessage": "Ouvrir la recherche", "description": "Layout: search button label in navbar" }, - "Y+DYja": { - "defaultMessage": "Partager sur LinkedIn", - "description": "Sharing: LinkedIn sharing link" - }, "YV//MH": { "defaultMessage": "Aucun résultat.", "description": "SearchPage: no results" @@ -511,10 +527,6 @@ "defaultMessage": "{topicsCount, plural, =0 {Sujets :} one {Sujet :} other {Sujets :}}", "description": "PostPreviewMeta: topics label" }, - "azgQuH": { - "defaultMessage": "Vous devriez lire {title}", - "description": "Sharing: subject text" - }, "bPv0VG": { "defaultMessage": "Formulaire de contact", "description": "Contact: form accessible name" @@ -651,17 +663,13 @@ "defaultMessage": "Mentions légales", "description": "Layout: Legal notice label" }, - "o0DAK4": { - "defaultMessage": "Partager sur Facebook", - "description": "Sharing: Facebook sharing link" - }, "o3WSz5": { "defaultMessage": "Réglages", "description": "Layout: settings modal title in navbar" }, - "oVLRW8": { - "defaultMessage": "Partager sur Diaspora", - "description": "Sharing: Diaspora sharing link" + "ofQPC+": { + "defaultMessage": "Partager sur LinkedIn", + "description": "SharingWidget: LinkedIn sharing link" }, "og/zWL": { "defaultMessage": "Thème sombre", @@ -683,10 +691,6 @@ "defaultMessage": "Découvrez les résultats de recherche pour {query} sur {websiteName}.", "description": "SearchPage: SEO - Meta description" }, - "q3U6uI": { - "defaultMessage": "Partager", - "description": "Sharing: widget title" - }, "qnwsWV": { "defaultMessage": "Projets", "description": "Layout: main nav - projects link" @@ -751,10 +755,6 @@ "defaultMessage": "Développement web", "description": "HomePage: link to web development thematic" }, - "vnbryZ": { - "defaultMessage": "Partager sur le Journal du Hacker", - "description": "Sharing: Journal du Hacker sharing link" - }, "vtDLzG": { "defaultMessage": "Souhaitez-vous essayer une nouvelle recherche ?", "description": "SearchPage: try a new search message" @@ -787,10 +787,6 @@ "defaultMessage": "Message :", "description": "ContactForm: message label" }, - "yfgMcl": { - "defaultMessage": "Introduction :", - "description": "Sharing: email content prefix" - }, "zEN3fd": { "defaultMessage": "Tous les articles dans {topicName}", "description": "TopicPage: posts list heading" diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx index d35541a..4eb7f2b 100644 --- a/src/pages/article/[slug].tsx +++ b/src/pages/article/[slug].tsx @@ -13,11 +13,12 @@ import { getLayout, Link, PageLayout, - Sharing, + SharingWidget, Spinner, type MetaItemData, Time, type CommentData, + Heading, } from '../../components'; import { getAllArticlesSlugs, @@ -301,6 +302,11 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ ); const pageUrl = `${website.url}${slug}`; + const sharingWidgetTitle = intl.formatMessage({ + defaultMessage: 'Share', + id: 'HKKkQk', + description: 'SharingWidget: widget title', + }); return ( <> @@ -335,11 +341,12 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ title={title} withToC={true} widgets={[ - <Sharing + <SharingWidget // eslint-disable-next-line react/jsx-no-literals -- Key allowed key="sharing-widget" className={styles.widget} data={{ excerpt: intro, title, url: pageUrl }} + heading={<Heading level={3}>{sharingWidgetTitle}</Heading>} media={[ 'diaspora', 'email', diff --git a/src/pages/projets/[slug].tsx b/src/pages/projets/[slug].tsx index 58c03ce..fa8f43a 100644 --- a/src/pages/projets/[slug].tsx +++ b/src/pages/projets/[slug].tsx @@ -13,7 +13,7 @@ import { getLayout, Link, PageLayout, - Sharing, + SharingWidget, Spinner, Heading, List, @@ -289,6 +289,11 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => { title, }); const schemaJsonLd = getSchemaJson([webpageSchema, articleSchema]); + const sharingWidgetTitle = intl.formatMessage({ + defaultMessage: 'Share', + id: 'HKKkQk', + description: 'SharingWidget: widget title', + }); return ( <> @@ -317,10 +322,11 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => { headerMeta={filteredHeaderMeta} withToC={true} widgets={[ - <Sharing + <SharingWidget // eslint-disable-next-line react/jsx-no-literals -- Key allowed key="sharing-widget" data={{ excerpt: intro, title, url: page.url }} + heading={<Heading level={3}>{sharingWidgetTitle}</Heading>} media={[ 'diaspora', 'email', diff --git a/src/styles/pages/article.module.scss b/src/styles/pages/article.module.scss index 5e7d520..7aac5a7 100644 --- a/src/styles/pages/article.module.scss +++ b/src/styles/pages/article.module.scss @@ -66,8 +66,9 @@ .widget { @include mix.media("screen") { @include mix.dimensions("md") { - width: min-content; - gap: var(--spacing-2xs); + ul { + width: min-content; + } } } } |
