Skip to content

Commit

Permalink
add an indicator of content being copied to clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
mat-sz committed Oct 24, 2023
1 parent c9e57b9 commit 5cf1780
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 4 deletions.
3 changes: 2 additions & 1 deletion web/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"cancel": "Cancel",
"accept": "Accept",
"download": "Download",
"copy": "Copy to clipboard",
"copy": "Copy",
"copied": "Copied to clipboard!",
"paste": "Paste",
"save": "Save",
"settings": {
Expand Down
1 change: 1 addition & 0 deletions web/public/locales/pl/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"accept": "Akceptuj",
"download": "Pobierz",
"copy": "Kopiuj",
"copied": "Skopiowano do schowka!",
"paste": "Wklej",
"save": "Zapisz",
"settings": {
Expand Down
20 changes: 20 additions & 0 deletions web/src/components/CopyButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.feedback {
pointer-events: none;
transition: 0.1s ease-in-out all;
background: var(--color-bg);
color: var(--color-fg);
border-radius: 5px;
padding: 5px 10px;
position: absolute;
top: -0.5rem;
left: 50%;
font-weight: normal;
font-size: 0.8rem;
transform: translate(-50%, -100%);
opacity: 0;
width: 9rem;

&.visible {
opacity: 1;
}
}
25 changes: 22 additions & 3 deletions web/src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
import React from 'react';
import { useTranslation } from 'react-i18not';
import { IoCopy } from 'react-icons/io5/index.js';
import { clsx } from 'clsx';

import { useTimedState } from '../utils/hooks.js';
import styles from './CopyButton.module.scss';
import { IconButton, IconButtonProps } from './IconButton.js';

export interface CopyButtonProps
extends Omit<IconButtonProps, 'title' | 'href' | 'download' | 'children'> {}
extends Omit<IconButtonProps, 'title' | 'href' | 'download' | 'children'> {
onClick: () => void;
}

export const CopyButton: React.FC<CopyButtonProps> = ({ ...props }) => {
export const CopyButton: React.FC<CopyButtonProps> = ({
onClick,
...props
}) => {
const { t } = useTranslation();
const [copied, setCopied] = useTimedState(false);

return (
<IconButton {...props} title={t('copy')}>
<IconButton
onClick={() => {
onClick();
setCopied(true);
}}
{...props}
title={t('copy')}
>
<div className={clsx(styles.feedback, { [styles.visible]: copied })}>
{t('copied')}
</div>
<IoCopy />
</IconButton>
);
Expand Down
1 change: 1 addition & 0 deletions web/src/components/IconButton.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
padding: 0;
color: var(--color-fg-soft);
font-size: 1rem;
position: relative;

&:hover {
color: var(--color-fg);
Expand Down
20 changes: 20 additions & 0 deletions web/src/utils/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useRef, useState } from 'react';

export function useTimedState<T>(
initialValue: T,
timeoutMs = 2000
): [T, (value: T) => void] {
const [value, setValue] = useState(initialValue);
const timeoutRef = useRef<any>();

return [
value,
(value: T) => {
clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => {
setValue(initialValue);
}, timeoutMs);
setValue(value);
},
];
}

0 comments on commit 5cf1780

Please sign in to comment.