view/share/web_share.jsx

/**
 * Native Web Share button JSX component.
 * @module view/share/web_share
 */
const { Component } = require('inferno');
const { cacheComponent } = require('../../util/cache');

// Brand colors only: the consuming theme owns button geometry and interaction.
const NETWORKS = [
  { id: 'x', name: 'X', background: '#000000', foreground: '#ffffff' },
  {
    id: 'facebook',
    name: 'Facebook',
    icon: 'fab fa-facebook-f',
    background: '#0866ff',
    foreground: '#ffffff',
  },
  {
    id: 'weibo',
    name: 'Weibo',
    icon: 'fab fa-weibo',
    background: '#e6162d',
    foreground: '#ffffff',
  },
  {
    id: 'telegram',
    name: 'Telegram',
    icon: 'fab fa-telegram-plane',
    background: '#26a5e4',
    foreground: '#ffffff',
  },
  {
    id: 'linkedin',
    name: 'LinkedIn',
    icon: 'fab fa-linkedin-in',
    background: '#0a66c2',
    foreground: '#ffffff',
  },
];

function shareUrl(network, url, title) {
  const link = encodeURIComponent(url);
  const text = encodeURIComponent(title);
  return {
    x: 'https://twitter.com/intent/tweet?url=' + link + '&text=' + text,
    facebook: 'https://www.facebook.com/sharer/sharer.php?u=' + link,
    weibo: 'https://service.weibo.com/share/share.php?url=' + link + '&title=' + text,
    telegram: 'https://t.me/share/url?url=' + link + '&text=' + text,
    linkedin: 'https://www.linkedin.com/sharing/share-offsite/?url=' + link,
  }[network];
}

/**
 * Native Web Share button JSX component.
 *
 * @example
 * <WebShare />
 */
class WebShare extends Component {
  render() {
    const { label = 'More', url, title } = this.props;
    const js = `(function () {
      ${shareUrl.toString()}
      document.querySelectorAll('.hexo-component-share').forEach(function (container) {
        var button = container.querySelector('button');
        var status = container.querySelector('[role="status"]');
        var native = container.querySelector('[data-share-native]');
        var data = { title: container.dataset.title || document.title, url: container.dataset.url || window.location.href };
        container.querySelectorAll('[data-share-network]').forEach(function (link) {
          link.href = shareUrl(link.dataset.shareNetwork, data.url, data.title);
        });
        button.hidden = false;
        native.hidden = false;
        button.disabled = typeof navigator.share !== 'function';
        status.hidden = !button.disabled;
        button.onclick = async function () {
          status.hidden = true;
          try {
            await navigator.share({ title: container.dataset.title || document.title, url: container.dataset.url || window.location.href });
          } catch (error) {
            if (error && error.name === 'AbortError') return;
            status.hidden = false;
          }
        };
      });
    })();`;
    return (
      <>
        <div
          class="hexo-component-share"
          data-share-provider="web_share"
          data-url={url}
          data-title={title}>
          <div class="buttons is-centered">
            {NETWORKS.map((network) => (
              <a
                key={network.id}
                class="button"
                style={`background-color:${network.background};border-color:${network.background};color:${network.foreground}`}
                data-share-network={network.id}
                href={shareUrl(network.id, url || '', title || '')}
                target="_blank"
                rel="noopener noreferrer"
                aria-label={`Share on ${network.name}`}>
                <span class="icon" aria-hidden="true">
                  {network.icon ? (
                    <i class={network.icon}></i>
                  ) : (
                    <svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
                      <path d="M18.9 2H22l-6.8 7.8L23.2 22h-6.3L12 14.6 5.5 22H2.4l7.9-9L.8 2h6.5l4.5 6.7L18.9 2Zm-1.1 18h1.7L6.4 3.9H4.6L17.8 20Z" />
                    </svg>
                  )}
                </span>
                <span>{network.name}</span>
              </a>
            ))}
            <span data-share-native="" class="has-text-centered" hidden={true}>
              <button type="button" class="button" hidden={true}>
                <span class="icon" aria-hidden="true">
                  <i class="fas fa-share-alt"></i>
                </span>
                <span>{label}</span>
              </button>
            </span>
          </div>
          <p role="status" hidden={true}>
            System sharing is unavailable in this browser. You can use the platform buttons above.
          </p>
        </div>
        <script dangerouslySetInnerHTML={{ __html: js }}></script>
      </>
    );
  }
}

/**
 * Cacheable Web Share button JSX component.
 * <p>
 * This class is supposed to be used in combination with the <code>locals</code> hexo filter
 * ({@link module:hexo/filter/locals}).
 *
 * @see module:util/cache.cacheComponent
 * @example
 * <WebShare.Cacheable />
 */
WebShare.Cacheable = cacheComponent(WebShare, 'share.web_share', ({ config = {}, page = {} }) => {
  const language = page.lang || page.language || config.language || 'en';
  return {
    label: /^zh(?:-|$)/i.test([].concat(language)[0]) ? '更多' : 'More',
    url: page.permalink,
    title: page.title,
  };
});

module.exports = WebShare;