Skip to content

Commit 3528faa

Browse files
authored
add README copy button, improve copy interaction, spacing tweaks (#2277)
1 parent 2bd6ed9 commit 3528faa

6 files changed

Lines changed: 88 additions & 26 deletions

File tree

components/Icons/index.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,33 @@ export function Copy({ width = 24, height = 24, style }: IconProps) {
694694
);
695695
}
696696

697+
export function CheckSquare({ width = 24, height = 24, style }: IconProps) {
698+
return (
699+
<Svg width={width} height={height} viewBox="0 0 256 256" style={style}>
700+
<Polyline
701+
points="88 136 112 160 168 104"
702+
fill="none"
703+
stroke="currentColor"
704+
strokeLinecap="round"
705+
strokeLinejoin="round"
706+
strokeWidth="16"
707+
/>
708+
<Rect
709+
x="40"
710+
y="40"
711+
width="176"
712+
height="176"
713+
rx="8"
714+
fill="none"
715+
stroke="currentColor"
716+
strokeLinecap="round"
717+
strokeLinejoin="round"
718+
strokeWidth="16"
719+
/>
720+
</Svg>
721+
);
722+
}
723+
697724
export function Link({ width = 24, height = 24, style }: IconProps) {
698725
return (
699726
<Svg width={width} height={height} viewBox="0 0 256 256" style={style}>

components/Package/CopyButton.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { useState } from 'react';
2+
import { type StyleProp } from 'react-native';
3+
import { type Style } from 'twrnc';
4+
5+
import { Button } from '~/components/Button';
6+
import { CheckSquare, Copy } from '~/components/Icons';
7+
import Tooltip from '~/components/Tooltip';
8+
import tw from '~/util/tailwind';
9+
10+
type Props = {
11+
data: string;
12+
tooltip: string;
13+
label: string;
14+
style?: StyleProp<Style>;
15+
};
16+
17+
export default function CopyButton({ data, tooltip, label, style }: Props) {
18+
const [copied, setCopied] = useState(false);
19+
const Icon = copied ? CheckSquare : Copy;
20+
21+
return (
22+
<Tooltip
23+
sideOffset={2}
24+
trigger={
25+
<Button
26+
containerStyle={[tw`absolute right-3 top-3`, style]}
27+
style={tw`bg-transparent`}
28+
onPress={async () => {
29+
if (navigator.clipboard && navigator.clipboard.writeText) {
30+
await navigator.clipboard.writeText(data);
31+
setCopied(true);
32+
setTimeout(() => {
33+
setCopied(false);
34+
}, 1000);
35+
}
36+
}}
37+
aria-label={label}>
38+
<Icon
39+
style={[tw`size-5 text-palette-gray4 dark:text-pewter`, copied && tw`text-success`]}
40+
/>
41+
</Button>
42+
}>
43+
{copied ? 'Copied' : tooltip}
44+
</Tooltip>
45+
);
46+
}

components/Package/ReadmeBox.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import useSWR from 'swr';
1111

1212
import { A, P } from '~/common/styleguide';
1313
import { Check, ReadmeFile } from '~/components/Icons';
14+
import CopyButton from '~/components/Package/CopyButton';
1415
import ReadmeHeading from '~/components/Package/ReadmeHeading';
1516
import rndDark from '~/styles/shiki/rnd-dark.json';
1617
import rndLight from '~/styles/shiki/rnd-light.json';
@@ -73,7 +74,15 @@ export default function ReadmeBox({ packageName, githubUrl, isTemplate, loader =
7374
<View
7475
style={tw`flex-row items-center gap-2 border-b border-palette-gray2 px-4 py-3 dark:border-default`}>
7576
<ReadmeFile style={tw`text-tertiary dark:text-pewter`} />
76-
<P>Readme</P>
77+
<P>README</P>
78+
{!noData && data && (
79+
<CopyButton
80+
data={data}
81+
tooltip="Copy README"
82+
label="Copy README to clipboard"
83+
style={tw`right-4 top-3.5`}
84+
/>
85+
)}
7786
</View>
7887
<View style={tw`p-4 pt-3 font-light`}>
7988
{noData ? (

components/Package/ReadmeCodeBlock.tsx

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { type Theme, useShikiHighlighter } from 'react-shiki';
22

3-
import { Button } from '~/components/Button';
4-
import { Copy } from '~/components/Icons';
5-
import Tooltip from '~/components/Tooltip';
3+
import CopyButton from '~/components/Package/CopyButton';
64
import tw from '~/util/tailwind';
75

86
type Props = {
@@ -16,25 +14,7 @@ const SHIKI_OPTS = { langAlias: { gradle: 'groovy' } } as const;
1614
export default function ReadmeCodeBlock({ code, theme, lang }: Props) {
1715
const highlighter = useShikiHighlighter(code, lang, theme, SHIKI_OPTS);
1816

19-
const copyButton = (
20-
<Tooltip
21-
sideOffset={2}
22-
trigger={
23-
<Button
24-
containerStyle={tw`absolute right-3 top-3`}
25-
style={tw`bg-transparent`}
26-
onPress={async () => {
27-
if (navigator.clipboard && navigator.clipboard.writeText) {
28-
await navigator.clipboard.writeText(code);
29-
}
30-
}}
31-
aria-label="Copy to clipboard">
32-
<Copy width={20} height={20} style={tw`text-palette-gray4 dark:text-pewter`} />
33-
</Button>
34-
}>
35-
Copy code
36-
</Tooltip>
37-
);
17+
const copyButton = <CopyButton data={code} tooltip="Copy code" label="Copy code to clipboard" />;
3818

3919
if (!highlighter) {
4020
return (

components/Package/VersionBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ export default function VersionBox({ label, time, versionData, downloads = 0 }:
3838
</View>
3939
<Label style={tw`flex min-h-4 flex-wrap items-center font-light text-secondary`}>
4040
Released <RelativeTime time={time} dateOnly /> by
41-
{versionData._npmUser?.trustedPublisher && <TrustedBadge style={tw`mx-[3px]`} />}
41+
{versionData._npmUser?.trustedPublisher && <TrustedBadge style={tw`mx-1`} />}
4242
{publisherMetadata && !versionData._npmUser?.trustedPublisher && (
4343
<UserAvatar
4444
src={`https://gravatar.com/avatar/${SHA256(publisherMetadata).toString()}?d=retro`}
4545
alt={`${versionData._npmUser?.name} avatar`}
46-
style={tw`relative top-px mx-[3px] size-3.5 border border-default`}
46+
style={tw`relative top-px mx-1 size-3.5 border border-default`}
4747
/>
4848
)}
4949
{versionData._npmUser?.name ?? 'Unknown'}

components/Score/ScoringCriterion.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function ScoringCriterion({ children, headline, style, score = undefined
1414
const isPositiveModifier = (score ?? 0) > 0;
1515

1616
return (
17-
<View style={[tw`mb-4 rounded-md border border-default px-5 py-3.5`, style]}>
17+
<View style={[tw`mb-3 rounded-lg border border-default px-5 py-3.5`, style]}>
1818
<Headline style={tw`mb-1 flex gap-3 text-[17px] font-semibold leading-[22px]`}>
1919
{score && (
2020
<Headline

0 commit comments

Comments
 (0)