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

feat: add code container #96

Merged
merged 5 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions src/components/__tests__/code.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { fireEvent, render } from '@testing-library/react'
import React from 'react'

import { Code } from '../code'

describe('Code', () => {
it('should render the code component', () => {
const { queryByRole, container } = render(<Code value="test" />)
const code = container.querySelector('code')

expect(code).toBeInTheDocument()
expect(code).toHaveTextContent('test')
expect(queryByRole('button')).toHaveAttribute('aria-label', 'copy')
})

it('calls clipboard.writeText with the correct value', () => {
Object.assign(navigator, {
clipboard: {
writeText: jest.fn(),
},
})

const { getByRole } = render(<Code value="test" />)
const copyButton = getByRole('button')
expect(copyButton).toBeInTheDocument()

fireEvent.click(copyButton)
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('test')
})
})
2 changes: 2 additions & 0 deletions src/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ const buttonVariants = cva(
variant: {
default: 'bg-button-base text-white hover:bg-button-base-hover',
destructive: 'bg-error text-error hover:bg-error-hover',
ghost: '',
},
size: {
default: 'py-4 px-6 font-medium',
icon: 'h-6 w-6',
},
fullWidth: {
true: 'w-full',
Expand Down
55 changes: 55 additions & 0 deletions src/components/code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'

import { cn } from '@/utils/cn'

import { Button } from './button'
import { CheckIcon, ClipboardIcon } from './icons'

interface CodeProps extends React.HTMLAttributes<HTMLDivElement> {
value: string
}

export const Code = ({ value, className, ...props }: CodeProps) => {
return (
<div
className={cn(
'flex items-center justify-between gap-x-2 rounded-xl bg-nav-active p-4 text-medium break-all',
className,
)}
{...props}>
<code>{value}</code>
<CopyButton value={value} />
</div>
)
}

interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
value: string
}

const CopyButton = ({ value, ...props }: CopyButtonProps) => {
const [hasCopied, setHasCopied] = React.useState(false)

React.useEffect(() => {
if (hasCopied === true) {
setTimeout(() => {
setHasCopied(false)
}, 2000)
}
}, [hasCopied])

return (
<Button
{...props}
aria-label="copy"
variant="ghost"
size="icon"
className="text-primary rounded-sm"
onClick={() => {
navigator.clipboard.writeText(value)
setHasCopied(true)
}}>
{hasCopied ? <CheckIcon className="h-6 w-6" /> : <ClipboardIcon className="h-6 w-6" />}
</Button>
)
}
32 changes: 32 additions & 0 deletions src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,35 @@ export const DollarSign = (props: React.SVGProps<SVGSVGElement>) => {
</svg>
)
}

export const ClipboardIcon = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<path
d="M9 18C8.45 18 7.97933 17.8043 7.588 17.413C7.196 17.021 7 16.55 7 16V4C7 3.45 7.196 2.979 7.588 2.587C7.97933 2.19567 8.45 2 9 2H18C18.55 2 19.021 2.19567 19.413 2.587C19.8043 2.979 20 3.45 20 4V16C20 16.55 19.8043 17.021 19.413 17.413C19.021 17.8043 18.55 18 18 18H9ZM9 16H18V4H9V16ZM5 22C4.45 22 3.979 21.8043 3.587 21.413C3.19567 21.021 3 20.55 3 20V6H5V20H16V22H5Z"
fill="currentColor"
/>
</svg>
)
}

export const CheckIcon = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-6 h-6"
{...props}>
<path strokeLinecap="round" strokeLinejoin="round" d="m4.5 12.75 6 6 9-13.5" />
</svg>
)
}
1 change: 1 addition & 0 deletions src/popup/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

/* Background colors */
--bg-primary: 59 130 246;
--bg-nav-active: 226 232 240;
--bg-error: 254 226 226;
--bg-error-hover: 254 202 202;
--bg-button-base: 86 183 181;
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = {
backgroundColor: {
primary: 'rgb(var(--bg-primary) / <alpha-value>)',
error: 'rgb(var(--bg-error) / <alpha-value>)',
'nav-active': 'rgb(var(--bg-nav-active) / <alpha-value>)',
'error-hover': 'rgb(var(--bg-error-hover) / <alpha-value>)',
'button-base': 'rgb(var(--bg-button-base) / <alpha-value>)',
'button-base-hover': 'rgb(var(--bg-button-base-hover) / <alpha-value>)',
Expand Down
Loading