aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/organisms/widgets/index.ts2
-rw-r--r--src/components/organisms/widgets/sharing-widget/index.ts1
-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.tsx167
-rw-r--r--src/components/organisms/widgets/sharing-widget/sharing-widget.tsx161
-rw-r--r--src/components/organisms/widgets/sharing.module.scss8
-rw-r--r--src/components/organisms/widgets/sharing.test.tsx24
-rw-r--r--src/components/organisms/widgets/sharing.tsx259
-rw-r--r--src/components/templates/page/page-layout.stories.tsx8
-rw-r--r--src/i18n/en.json74
-rw-r--r--src/i18n/fr.json74
-rw-r--r--src/pages/article/[slug].tsx11
-rw-r--r--src/pages/projets/[slug].tsx10
-rw-r--r--src/styles/pages/article.module.scss5
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('&nbsp;', ' ');
+ 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;
+ }
}
}
}