From a52dd5d7acd06d92e27c8a96fe010963ec5b8275 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 21 Dec 2021 16:42:56 +0100 Subject: chore: add a sharing component --- src/components/Sharing/Sharing.module.scss | 190 +++++++++++++++++++++++++++++ src/components/Sharing/Sharing.tsx | 106 ++++++++++++++++ src/config/sharing.ts | 72 +++++++++++ src/pages/article/[slug].tsx | 2 + src/styles/base/_colors.scss | 1 + 5 files changed, 371 insertions(+) create mode 100644 src/components/Sharing/Sharing.module.scss create mode 100644 src/components/Sharing/Sharing.tsx create mode 100644 src/config/sharing.ts (limited to 'src') diff --git a/src/components/Sharing/Sharing.module.scss b/src/components/Sharing/Sharing.module.scss new file mode 100644 index 0000000..3186675 --- /dev/null +++ b/src/components/Sharing/Sharing.module.scss @@ -0,0 +1,190 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/mixins" as mix; +@use "@styles/abstracts/placeholders"; + +.list { + @extend %flex-list; + + gap: var(--spacing-sm); + margin-bottom: var(--spacing-md); +} + +.link { + display: flex; + flex-flow: row nowrap; + align-items: center; + padding: var(--spacing-2xs) var(--spacing-xs); + border-radius: fun.convert-px(3); + color: var(--color-fg-inverted); + font-weight: 600; + text-decoration: none; + text-shadow: fun.convert-px(2) fun.convert-px(1) fun.convert-px(1) + var(--color-shadow-dark); + transition: all 0.3s ease-in-out 0s; + + @include mix.media("screen") { + @include mix.dimensions("sm") { + font-size: var(--font-size-sm); + } + } + + &:hover, + &:focus { + color: hsl(0, 0%, 100%); + transform: translateX(#{fun.convert-px(-3)}) + translateY(#{fun.convert-px(-3)}); + + @include mix.motion("reduce") { + text-decoration: underline; + } + } + + &:active { + color: hsl(0, 0%, 100%); + transform: translateX(#{fun.convert-px(2)}) translateY(#{fun.convert-px(2)}); + + @include mix.motion("reduce") { + transform: none; + } + } + + &::before { + display: block; + background-repeat: no-repeat; + content: ""; + filter: drop-shadow( + #{fun.convert-px(1)} #{fun.convert-px(1)} #{fun.convert-px(1)} hsl(0, 0%, 0%) + ); + width: 2ex; + height: 2ex; + margin-right: var(--spacing-2xs); + } + + &--diaspora { + background: hsl(0, 0%, 13%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(0, 0%, 3%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 hsl(0, 0%, 3%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 hsl(0, 0%, 3%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } + + &--email { + background: hsl(0, 0%, 44%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(0, 0%, 34%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 hsl(0, 0%, 34%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 hsl(0, 0%, 34%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } + + &--facebook { + background: hsl(214, 89%, 52%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(214, 89%, 42%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 + hsl(214, 89%, 42%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 + hsl(214, 89%, 42%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } + + &--journal-du-hacker { + background: hsl(210, 24%, 51%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(210, 24%, 41%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 + hsl(210, 24%, 41%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 + hsl(210, 24%, 41%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } + + &--linkedin { + background: hsl(210, 90%, 40%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(210, 90%, 30%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 + hsl(210, 90%, 30%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 + hsl(210, 90%, 30%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } + + &--twitter { + background: hsl(203, 89%, 53%); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(203, 89%, 43%); + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 + hsl(203, 89%, 43%); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 + hsl(203, 89%, 43%); + } + + &::before { + background-image: url(fun.encode-svg( + '' + )); + } + } +} diff --git a/src/components/Sharing/Sharing.tsx b/src/components/Sharing/Sharing.tsx new file mode 100644 index 0000000..9f8383b --- /dev/null +++ b/src/components/Sharing/Sharing.tsx @@ -0,0 +1,106 @@ +import sharingMedia from '@config/sharing'; +import { t } from '@lingui/macro'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import styles from './Sharing.module.scss'; + +type Parameters = { + content: string; + image: string; + title: string; + url: string; +}; + +type Website = { + id: string; + name: string; + parameters: Parameters; + url: string; +}; + +const Sharing = ({ excerpt, title }: { excerpt: string; title: string }) => { + const [pageExcerpt, setPageExcerpt] = useState(''); + const [pageUrl, setPageUrl] = useState(''); + const router = useRouter(); + + useEffect(() => { + const divEl = document.createElement('div'); + divEl.innerHTML = excerpt; + const cleanExcerpt = divEl.textContent!; + setPageExcerpt(cleanExcerpt); + }, [excerpt]); + + useEffect(() => { + const { protocol, hostname, port } = window.location; + const fullUrl = `${protocol}//${hostname}${port ? `:${port}` : ''}${ + router.asPath + }`; + + setPageUrl(fullUrl); + }, [router.asPath]); + + const getSharingUrl = (website: Website): string => { + const { id, parameters, url } = website; + let sharingUrl = `${url}?`; + let count = 0; + + for (const [key, value] of Object.entries(parameters)) { + if (!value) continue; + + sharingUrl += count > 0 ? `&${value}=` : `${value}=`; + + switch (key) { + case 'content': + if (id === 'email') { + const body = `${t`Introduction:`}\n\n"${pageExcerpt}"\n\n${t`Read more here:`} ${pageUrl}`; + sharingUrl += encodeURI(body); + } else { + sharingUrl += encodeURI(pageExcerpt); + } + break; + case 'title': + const prefix = + id === 'email' ? t`Seen on ${window.location.hostname}:` : ''; + sharingUrl += encodeURI(`${prefix} ${title}`); + break; + case 'url': + sharingUrl += encodeURI(pageUrl); + default: + break; + } + + count++; + } + + return sharingUrl; + }; + + const getItems = () => { + const websites: Website[] = sharingMedia; + + return websites.map((website) => { + const { id, name } = website; + const sharingUrl = getSharingUrl(website); + + return ( +
  • + + {name} + +
  • + ); + }); + }; + + return ( +
    +

    {t`Share`}

    + +
    + ); +}; + +export default Sharing; diff --git a/src/config/sharing.ts b/src/config/sharing.ts new file mode 100644 index 0000000..580145e --- /dev/null +++ b/src/config/sharing.ts @@ -0,0 +1,72 @@ +import { t } from '@lingui/macro'; + +const sharingMedia = [ + { + id: 'diaspora', + name: 'Diaspora', + parameters: { + content: '', + image: '', + title: 'title', + url: 'url', + }, + url: 'https://share.diasporafoundation.org/', + }, + { + id: 'facebook', + name: 'Facebook', + parameters: { + content: '', + image: '', + title: '', + url: 'u', + }, + url: 'https://www.facebook.com/sharer/sharer.php', + }, + { + id: 'linkedin', + name: 'LinkedIn', + parameters: { + content: '', + image: '', + title: '', + url: 'url', + }, + url: 'https://www.linkedin.com/sharing/share-offsite/', + }, + { + id: 'twitter', + name: 'Twitter', + parameters: { + content: '', + image: '', + title: 'text', + url: 'url', + }, + url: 'https://twitter.com/intent/tweet', + }, + { + id: 'journal-du-hacker', + name: 'Journal du Hacker', + parameters: { + content: '', + image: '', + title: 'title', + url: 'url', + }, + url: 'https://www.journalduhacker.net/stories/new', + }, + { + id: 'email', + name: t`Email`, + parameters: { + content: 'body', + image: '', + title: 'subject', + url: '', + }, + url: 'mailto:', + }, +]; + +export default sharingMedia; diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx index 1fa65fa..54391fc 100644 --- a/src/pages/article/[slug].tsx +++ b/src/pages/article/[slug].tsx @@ -3,6 +3,7 @@ import CommentsList from '@components/CommentsList/CommentsList'; import { getLayout } from '@components/Layouts/Layout'; import PostFooter from '@components/PostFooter/PostFooter'; import PostHeader from '@components/PostHeader/PostHeader'; +import Sharing from '@components/Sharing/Sharing'; import ToC from '@components/ToC/ToC'; import { t } from '@lingui/macro'; import { getAllPostsSlug, getPostBySlug } from '@services/graphql/queries'; @@ -43,6 +44,7 @@ const SingleArticle: NextPageWithLayout = ({ post }) => {
    +

    {t`Comments`}

    diff --git a/src/styles/base/_colors.scss b/src/styles/base/_colors.scss index 31733b9..cd66341 100644 --- a/src/styles/base/_colors.scss +++ b/src/styles/base/_colors.scss @@ -16,4 +16,5 @@ --color-shadow: #{var.$color_grey-dark-o70}; --color-shadow-light: #{var.$color_grey-dark-o40}; --color-shadow-lighter: #{var.$color_grey-dark-o20}; + --color-shadow-dark: #{var.$color_grey-dark}; } -- cgit v1.2.3