aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/widgets/sharing.tsx
blob: 61d54d8bbd1ac2103cdffac1336110d380134882 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
import Image, { ImageProps } from 'next/image';
import Link from 'next/link';
import styles from './ResponsiveImage.module.scss';

type ResponsiveImageProps = ImageProps & {
  caption?: string;
  linkTarget?: string;
};

const ResponsiveImage = (props: ResponsiveImageProps) => {
  const { caption, 
import { FC } from 'react';
import { useIntl } from 'react-intl';
import { SharingLink, type SharingMedium } from '../../atoms';
import { Widget, type WidgetProps } from '../../molecules';
import styles from './sharing.module.scss';

export type SharingData = {
  /**
   * The content excerpt.
   */
  excerpt: string;
  /**
   * The content title.
   */
  title: string;
  /**
   * The content url.
   */
  url: string;
};

export type SharingProps = {
  /**
   * Set additional classnames to the sharing links list.
   */
  className?: string;
  /**
   * The page data to share.
   */
  data: SharingData;
  /**
   * The widget default state.
   */
  expanded?: WidgetProps['expanded'];
  /**
   * The HTML heading level.
   */
  level?: WidgetProps['level'];
  /**
   * 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,
  expanded = true,
  level = 2,
  ...props
}) => {
  const intl = useIntl();
  const widgetTitle = intl.formatMessage({
    defaultMessage: 'Share',
    id: 'q3U6uI',
    description: 'Sharing: widget title',
  });

  /**
   * 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 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}`;
  };

  /**
   * 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}`;
  };

  /**
   * 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[] => {
    return media.map((medium) => (
      <li key={medium}>
        <SharingLink medium={medium} url={getUrl(medium)} />
      </li>
    ));
  };

  return (
    <Widget {...props} expanded={expanded} level={level} title={widgetTitle}>
      <ul className={`${styles.list} ${className}`}>{getItems()}</ul>
    </Widget>
  );
};