Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Share button #10422

Merged
merged 38 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
73950f6
share button
DanielCliftonGuardian Jan 31, 2024
230d991
renaming
DanielCliftonGuardian Jan 31, 2024
f41fcaa
Update ShareButton.importable.tsx
DanielCliftonGuardian Jan 31, 2024
dae8f9d
Add useEffect
DanielCliftonGuardian Feb 1, 2024
eecb087
Merge branch 'main' into share-button
DanielCliftonGuardian Feb 8, 2024
989699c
Add new styles
DanielCliftonGuardian Feb 8, 2024
b12ac3d
Add stories
DanielCliftonGuardian Feb 9, 2024
588a8ca
Add to palette
DanielCliftonGuardian Feb 9, 2024
98c473e
fix add story
DanielCliftonGuardian Feb 12, 2024
77cb8fb
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 12, 2024
a80557e
Refactors
DanielCliftonGuardian Feb 13, 2024
e499917
Update NewsletterSignupLayout.tsx
DanielCliftonGuardian Feb 13, 2024
2b0e092
update island defer until visible
DanielCliftonGuardian Feb 13, 2024
84ae3a1
Refactor
DanielCliftonGuardian Feb 13, 2024
ab2f4d3
Update link-icon.svg
DanielCliftonGuardian Feb 13, 2024
5758113
Fix liveblogmobile copyLinkButton styles
DanielCliftonGuardian Feb 13, 2024
2c89049
update fill colour
DanielCliftonGuardian Feb 14, 2024
81976dd
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
505d324
Refactors
DanielCliftonGuardian Feb 14, 2024
81fd81d
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
759f0f4
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
0925622
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
06735fa
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
8213c81
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 14, 2024
ee27ea3
Improvements
DanielCliftonGuardian Feb 19, 2024
c35e66f
Merge branch 'main' into share-button
DanielCliftonGuardian Feb 19, 2024
88fbf5a
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 20, 2024
f89edea
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 20, 2024
45d38aa
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 20, 2024
50d55d4
Update ShareButton.importable.tsx
DanielCliftonGuardian Feb 20, 2024
a5f38bc
Add email link button
DanielCliftonGuardian Feb 21, 2024
fe45066
Fix fall back href
DanielCliftonGuardian Feb 21, 2024
4030d46
Update ShareButton.stories.tsx
DanielCliftonGuardian Feb 21, 2024
c6761e1
Switch to linkButton
DanielCliftonGuardian Feb 21, 2024
efe9779
Update Island.test.tsx
DanielCliftonGuardian Feb 21, 2024
69a12b7
Merge branch 'main' into share-button
DanielCliftonGuardian Feb 21, 2024
a88e86c
Update Island.test.tsx
DanielCliftonGuardian Feb 21, 2024
24cf0ea
Merge branch 'share-button' of https://github.com/guardian/dotcom-ren…
DanielCliftonGuardian Feb 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const FormatHeading = ({ format }: { format: ArticleFormat }) => (
// ----- Decorators ----- //

/** A list of the most typical formats */
const defaultFormats = [
export const defaultFormats = [
{
display: ArticleDisplay.Standard,
design: ArticleDesign.Standard,
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/playwright/fixtures/tweet-block.js

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions dotcom-rendering/src/components/ArticleMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Contributor } from './Contributor';
import { Dateline } from './Dateline';
import { Island } from './Island';
import { SendAMessage } from './SendAMessage.importable';
import { ShareIcons } from './ShareIcons';
import { ShareButton } from './ShareButton.importable';

type Props = {
format: ArticleFormat;
Expand Down Expand Up @@ -415,14 +415,17 @@ export const ArticleMeta = ({
),
]}
>
<ShareIcons
pageId={pageId}
webTitle={webTitle}
format={format}
displayIcons={['facebook', 'twitter', 'email']}
size="medium"
context="ArticleMeta"
/>
<Island
priority="feature"
defer={{ until: 'visible' }}
>
<ShareButton
pageId={pageId}
webTitle={webTitle}
format={format}
context="ArticleMeta"
/>
</Island>
</div>
)}
<div
Expand Down
22 changes: 12 additions & 10 deletions dotcom-rendering/src/components/LiveBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { isUndefined } from '@guardian/libs';
import type { EditionId } from '../lib/edition';
import { RenderArticleElement } from '../lib/renderElement';
import type { ServerSideTests, Switches } from '../types/config';
import { Island } from './Island';
import { LastUpdated } from './LastUpdated';
import { LiveBlockContainer } from './LiveBlockContainer';
import { ShareIcons } from './ShareIcons';
import { ShareButton } from './ShareButton.importable';

type Props = {
format: ArticleFormat;
Expand Down Expand Up @@ -93,15 +94,16 @@ export const LiveBlock = ({
justify-content: space-between;
`}
>
<ShareIcons
pageId={pageId}
blockId={block.id}
webTitle={webTitle}
displayIcons={['facebook', 'twitter']}
format={format}
size="small"
context="LiveBlock"
/>
<Island priority="feature" defer={{ until: 'visible' }}>
<ShareButton
size="xsmall"
pageId={pageId}
blockId={block.id}
webTitle={webTitle}
format={format}
context="LiveBlock"
/>
</Island>
{!isUndefined(lastUpdated) && (
<LastUpdated
lastUpdated={lastUpdated}
Expand Down
233 changes: 233 additions & 0 deletions dotcom-rendering/src/components/ShareButton.importable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import { css } from '@emotion/react';
import { ArticleDesign } from '@guardian/libs';
import { palette, until } from '@guardian/source-foundations';
import type { Size } from '@guardian/source-react-components';
import {
Button,
SvgCheckmark,
SvgShare,
} from '@guardian/source-react-components';
import { useEffect, useState } from 'react';
import { palette as themePalette } from '../palette';
import LinkIcon from '../static/icons/link-icon.svg';

type Props = {
size?: Size;
pageId: string;
blockId?: string;
webTitle: string;
format: ArticleFormat;
context: Context;
};

type Context = 'ArticleMeta' | 'LiveBlock' | 'SubMeta';

const sharedButtonStyles = (sizeXSmall: boolean) => css`
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
border-color: ${themePalette('--share-button-border')};
min-width: ${sizeXSmall ? '101px' : '132px'};
max-width: ${sizeXSmall ? '101px' : '132px'};
height: ${sizeXSmall ? '24px' : '36px'};
`;

const buttonStyles = css`
color: ${themePalette('--share-button')};
svg {
fill: ${themePalette('--share-button')};
}
:hover {
background-color: ${themePalette('--share-button')};
border-color: ${themePalette('--share-button')};
color: ${themePalette('--share-button-hover')};
svg {
fill: ${themePalette('--share-button-hover')};
}
}
`;
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved

const copiedButtonStyles = (sizeXSmall: boolean) => css`
color: ${themePalette('--share-button-copied')};
padding: ${sizeXSmall ? '0 4px;' : '0 10px;'} svg {
fill: ${palette.success[400]};
}
`;

const nativeShare = (sizeXSmall: boolean) => css`
min-width: ${sizeXSmall ? '79px' : '105px'};
max-width: ${sizeXSmall ? '79px' : '105px'};
border-color: ${themePalette('--share-button-border')};
`;

const liveBlogMobile = (isCopied: boolean) => css`
${until.desktop} {
color: ${palette.neutral[100]};
border-color: rgba(255, 255, 255, 0.4);
svg {
fill: ${isCopied ? palette.success[500] : palette.neutral[100]};
}
${!isCopied &&
`:hover {
color: ${themePalette('--share-button-liveblog-mobile')};
background-color: ${palette.neutral[100]};
svg {
fill: ${themePalette('--share-button-liveblog-mobile')};
}
}`}
}
`;

const getUrl = ({
pageId,
CMP,
blockId,
}: {
pageId: string;
CMP?: string;
blockId?: string;
}) => {
const searchParams = new URLSearchParams({});
if (CMP) searchParams.append('CMP', CMP); // Do we want to track this?
if (blockId) searchParams.append('page', `with:block-${blockId}`);

const blockHash = blockId ? `#block-${blockId}` : '';
const paramsString = searchParams.toString();
return new URL(
`${pageId}${paramsString ? '?' + paramsString : ''}${blockHash}`,
'https://www.theguardian.com/',
).href;
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
};

export const NativeShareButton = ({
onShare,
size,
isLiveBlogMeta,
}: {
onShare: () => void;
size?: Size;
isLiveBlogMeta: boolean;
}) => {
const sizeXSmall = size === 'xsmall';

return (
<Button
onClick={() => onShare()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid creating the extra function on each render?

Suggested change
onClick={() => onShare()}
onClick={onShare}

size={size}
type="button"
priority="tertiary"
iconSide="left"
icon={<SvgShare />}
css={[
buttonStyles,
nativeShare(sizeXSmall),
isLiveBlogMeta && liveBlogMobile(false),
]}
>
Share
</Button>
);
};

export const CopyLinkButton = ({
onShare,
size,
isLiveBlogMeta,
isCopied,
}: {
onShare: () => void;
size?: Size;
isLiveBlogMeta: boolean;
isCopied: boolean;
}) => {
const sizeXSmall = size === 'xsmall';
return (
<Button
onClick={() => onShare()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid creating the extra function on each render?

Suggested change
onClick={() => onShare()}
onClick={onShare}

size={size}
type="button"
priority="tertiary"
iconSide="left"
icon={isCopied ? <SvgCheckmark /> : <LinkIcon />}
css={[
...(isCopied
? [copiedButtonStyles(sizeXSmall)]
: [buttonStyles]),
sharedButtonStyles(sizeXSmall),
isLiveBlogMeta && liveBlogMobile(isCopied),
]}
>
{isCopied ? 'Link copied' : 'Copy link'}
</Button>
);
};

export const ShareButton = ({
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
size = 'small',
pageId,
blockId,
webTitle,
format,
context,
}: Props) => {
const [isCopied, setIsCopied] = useState(false);
const [isShareSupported, setIsShareSupported] = useState(false);

const isLiveBlogMeta =
(format.design === ArticleDesign.LiveBlog &&
context === 'ArticleMeta') ||
context === 'SubMeta';
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved

const shareData = {
title: `${webTitle}`,
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
text: `${webTitle}:`,
url: getUrl({
pageId,
blockId,
}),
};

useEffect(() => {
setIsShareSupported(
typeof navigator !== 'undefined' &&
'share' in navigator &&
navigator.canShare(shareData),
);
// eslint-disable-next-line react-hooks/exhaustive-deps
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
}, []);

useEffect(() => {
if (!isCopied) return;
const timer = setTimeout(() => {
setIsCopied(false);
}, 3000);
return () => clearTimeout(timer);
}, [isCopied]);

return isShareSupported ? (
<NativeShareButton
onShare={() => {
navigator.share(shareData).catch(() => {});
}}
size={size}
isLiveBlogMeta={isLiveBlogMeta}
/>
) : (
<CopyLinkButton
onShare={() => {
if (!('clipboard' in navigator)) return;
DanielCliftonGuardian marked this conversation as resolved.
Show resolved Hide resolved
navigator.clipboard
.writeText(
getUrl({
pageId,
blockId,
}),
)
.then(() => {
setIsCopied(true);
})
.catch(() => {});
}}
size={size}
isCopied={isCopied}
isLiveBlogMeta={isLiveBlogMeta}
/>
);
};
Loading
Loading