Skip to content

Commit

Permalink
Update Copy button (#1168)
Browse files Browse the repository at this point in the history
- Updated the Copy button
- Added the copy button to the popup for long alleles in VEP results table:
  • Loading branch information
azangru authored Sep 27, 2024
1 parent f4a65c0 commit b4d91f3
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@
font-size: 11px;
font-weight: var(--font-weight-light);
}

.copy {
margin-bottom: 0.5rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import useRefWithRerender from 'src/shared/hooks/useRefWithRerender';

import TextButton from 'src/shared/components/text-button/TextButton';
import { Toolbox, ToolboxPosition } from 'src/shared/components/toolbox';
import Copy from 'src/shared/components/copy/Copy';

import styles from './VepResultsAllele.module.css';

Expand Down Expand Up @@ -49,13 +50,15 @@ const AlleleSequence = ({ sequence }: Props) => {

return (
<div>
<TextButton
ref={setAnchorRef}
onClick={onClick}
style={{ position: 'relative' }}
>
{displaySequence}
</TextButton>
{/* Wrapping TextButton into a span to use the span as an anchor,
because can't render PointerBox directly inside TextButton,
because the pointer box will contain the Copy button,
and having a button inside another button is invalid html.
*/}
<span ref={setAnchorRef} style={{ position: 'relative' }}>
<TextButton onClick={onClick}>{displaySequence}</TextButton>
</span>

<div className={styles.sequenceLength}>{sequence.length}</div>
{anchorRef.current && shouldShowTooltip && (
<Toolbox
Expand All @@ -64,6 +67,7 @@ const AlleleSequence = ({ sequence }: Props) => {
position={ToolboxPosition.RIGHT}
>
<div className={styles.toolboxContents}>
<Copy value={sequence} className={styles.copy} />
<div className={styles.sequence}>{sequence}</div>
</div>
</Toolbox>
Expand Down
60 changes: 30 additions & 30 deletions src/shared/components/copy/Copy.module.css
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
.copyLozenge {
display: inline-flex;
width: 68px;
align-items: center;
.copy {
position: relative;
font-size: var(--copy-button-font-size, 12px);
}

/*
Considering that when the copy button is pressed, it shows
a lozenge that is wider than the initial text "Copy"
(the lozenge text says "Copied", and the lozenge itself
has padding left and right), below are three alignment classes
to position the initial label ("Copy") within the space taken by the lozenge.
The label "Copy" can be aligned to the left of the lozenge space,
or to its right, or to the middle.
Notice that the text "Copied" is always middle-aligned
*/

.alignLeft {
justify-content: flex-start;
.copyText {
color: var(--color-blue);
line-height: inherit;
position: relative;
z-index: 0;
}

.alignMiddle {
justify-content: center;
.copied .copyText {
visibility: hidden;
}

.alignRight {
justify-content: flex-end;
.checkmark {
fill: var(--color-green);
height: 13px;
position: absolute;
left: 50%;
translate: -50%;
scale: 1;
z-index: 1;
animation: checkmark-pulse 0.3s ease-in-out;
}

.copy {
color: var(--color-blue);
line-height: inherit;
}
@keyframes checkmark-pulse {
0% {
scale: 0.6;
}

70% {
scale: 1.1;
}

.copyLozengeCopied {
color: var(--color-white);
background-color: var(--color-black);
border-radius: 30px;
100% {
scale: 1;
}
}
27 changes: 9 additions & 18 deletions src/shared/components/copy/Copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
import { useEffect, useState } from 'react';
import classNames from 'classnames';

import styles from './Copy.module.css';
import Checkmark from 'static/icons/icon_tick.svg';

type Alignment = 'left' | 'middle' | 'right';
import styles from './Copy.module.css';

type Props = {
value: string;
onCopy?: () => void;
className?: string;
align?: Alignment; // by default, the component aligns the text "Copy" to middle
};

const Copy = (props: Props) => {
Expand All @@ -42,7 +41,7 @@ const Copy = (props: Props) => {
props.onCopy?.();
navigator.clipboard.writeText(props.value);

timeout = setTimeout(() => setCopied(false), 1500);
timeout = setTimeout(() => setCopied(false), 2000);
};

// check if the browser exposes the clipboard api (it won't be available e.g. over http)
Expand All @@ -53,26 +52,18 @@ const Copy = (props: Props) => {
}

const componentStyles = classNames(
styles.copyLozenge,
styles.copy,
{
[styles.alignLeft]: props.align === 'left' && !copied,
[styles.alignMiddle]: props.align === 'middle' || !props.align || copied,
[styles.alignRight]: props.align === 'right' && !copied,
[styles.copyLozengeCopied]: copied
[styles.copied]: copied
},
props.className
);

return (
<span className={componentStyles}>
{copied ? (
'Copied'
) : (
<button className={styles.copy} onClick={copy}>
Copy
</button>
)}
</span>
<button className={componentStyles} onClick={copy}>
<span className={styles.copyText}>Copy</span>
{copied && <Checkmark className={styles.checkmark} />}
</button>
);
};

Expand Down
1 change: 1 addition & 0 deletions src/shared/components/variant-vcf/VariantVCF.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.container {
display: flex;
flex-direction: column;
align-items: start;
row-gap: 1ch;
}

Expand Down
4 changes: 1 addition & 3 deletions src/shared/components/variant-vcf/VariantVCF.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ const VariantVCF = (props: Props) => {

return (
<div className={componentClasses}>
{props.withCopy && (
<Copy value={vcfSequenceParts.vcfString} align="left" />
)}
{props.withCopy && <Copy value={vcfSequenceParts.vcfString} />}
<span className={styles.vcfString}>
<span>{vcfSequenceParts.regionName}</span>
<span>{vcfSequenceParts.startCoordinate}</span>
Expand Down
5 changes: 0 additions & 5 deletions stories/shared-components/copy/Copy.stories.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,3 @@
border: 1px dashed var(--color-medium-light-grey);
width: fit-content;
}

.inFrameContainer {
display: flex;
column-gap: 0.6rem;
}
22 changes: 14 additions & 8 deletions stories/shared-components/copy/Copy.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,37 @@ const textToCopy = 'Hello world!';
const DefaultCopyButtonStory = () => (
<>
<section className={styles.section}>
<p>Middle alignment of the "Copy" label (default)</p>
<div className={styles.frame}>
<div className={styles.inFrameContainer}>
<Copy value={textToCopy} />
<span>Some text to the right</span>
<div>Some text below</div>
</div>
</div>
</section>

<section className={styles.section}>
<p>Left alignment of the "Copy" label</p>
<div className={styles.frame}>
<div className={styles.inFrameContainer}>
<Copy value={textToCopy} align="left" />
<span>Some text to the right</span>
<Copy value={textToCopy} />
<span style={{ marginLeft: '1rem' }}>Some text to the right</span>
</div>
</div>
</section>

<section className={styles.section}>
<div className={styles.frame}>
<div className={styles.inFrameContainer}>
<span style={{ marginRight: '1rem' }}>Some text to the left</span>
<Copy value={textToCopy} />
</div>
</div>
</section>

<section className={styles.section}>
<p>Right alignment of the "Copy" label</p>
<div className={styles.frame}>
<div className={styles.inFrameContainer}>
<span>Some text to the left</span>
<Copy value={textToCopy} align="right" />
<div>Some text above</div>
<Copy value={textToCopy} />
</div>
</div>
</section>
Expand Down

0 comments on commit b4d91f3

Please sign in to comment.