feat: redesign code and attribute

This commit is contained in:
Aarnav Tale 2025-02-01 18:11:33 -05:00
parent 68babd7fe9
commit 31ac25d510
No known key found for this signature in database
2 changed files with 82 additions and 56 deletions

View File

@ -1,18 +1,23 @@
import { CopyIcon } from '@primer/octicons-react';
import { Check, Copy } from 'lucide-react';
import cn from '~/utils/cn';
import toast from '~/utils/toast';
interface Props {
export interface AttributeProps {
name: string;
value: string;
isCopyable?: boolean;
link?: string;
}
export default function Attribute({ name, value, link, isCopyable }: Props) {
const canCopy = isCopyable ?? false;
export default function Attribute({
name,
value,
link,
isCopyable,
}: AttributeProps) {
return (
<dl className="flex gap-1 text-sm w-full">
<dt className="w-1/2 shrink-0 min-w-0 truncate text-gray-700 dark:text-gray-300 py-1">
<dl className="flex items-center w-full gap-x-1">
<dt className="font-semibold w-1/4 shrink-0 text-sm">
{link ? (
<a className="hover:underline" href={link}>
{name}
@ -21,22 +26,42 @@ export default function Attribute({ name, value, link, isCopyable }: Props) {
name
)}
</dt>
<dd
className={cn(
'rounded-lg truncate w-full px-2.5 py-1 text-sm',
'flex items-center gap-x-1',
'focus-within:outline-none focus-within:ring-2',
isCopyable && 'hover:bg-headplane-100 dark:hover:bg-headplane-800',
)}
>
{isCopyable ? (
<button
type="button"
className="w-full flex items-center gap-x-1 outline-none"
onClick={async (event) => {
const svgs = event.currentTarget.querySelectorAll('svg');
for (const svg of svgs) {
svg.toggleAttribute('data-copied', true);
}
{canCopy ? (
<button
type="button"
className="focus:outline-none flex items-center gap-x-1 truncate hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-md"
onClick={async () => {
await navigator.clipboard.writeText(value);
toast(`Copied ${name}`);
}}
>
<dd className="min-w-0 truncate px-2 py-1">{value}</dd>
<CopyIcon className="text-gray-600 dark:text-gray-200 pr-2 w-max h-3" />
</button>
) : (
<dd className="min-w-0 truncate px-2 py-1">{value}</dd>
)}
await navigator.clipboard.writeText(value);
toast('Copied to clipboard');
setTimeout(() => {
for (const svg of svgs) {
svg.toggleAttribute('data-copied', false);
}
}, 1000);
}}
>
{value}
<Check className="h-4.5 w-4.5 p-1 hidden data-[copied]:block" />
<Copy className="h-4.5 w-4.5 p-1 block data-[copied]:hidden" />
</button>
) : (
value
)}
</dd>
</dl>
);
}

View File

@ -1,52 +1,53 @@
import { CheckIcon, CopyIcon } from '@primer/octicons-react';
import { HTMLProps, useState } from 'react';
import { Check, Copy } from 'lucide-react';
import { HTMLProps } from 'react';
import cn from '~/utils/cn';
import toast from '~/utils/toast';
interface Props extends HTMLProps<HTMLSpanElement> {
export interface CodeProps extends HTMLProps<HTMLSpanElement> {
isCopyable?: boolean;
children: string | string[];
}
export default function Code(props: Props) {
const [isCopied, setIsCopied] = useState(false);
export default function Code({ isCopyable, children, className }: CodeProps) {
return (
<>
<code
className={cn(
'bg-ui-100 dark:bg-ui-800 p-0.5 rounded-md',
props.className,
)}
>
{props.children}
</code>
{props.isCopyable ? (
<code
className={cn(
'bg-headplane-100 dark:bg-headplane-800 px-1 py-0.5 font-mono',
'rounded-lg focus-within:outline-none focus-within:ring-2',
className,
)}
>
{isCopyable ? (
<button
type="button"
className={cn(
'ml-1 p-1 rounded-md',
'bg-ui-100 dark:bg-ui-800',
'text-ui-500 dark:text-ui-400',
'inline-flex items-center justify-center',
)}
onClick={() => {
if (!props.children) {
throw new Error('Made copyable without children');
className="inline-flex items-center gap-x-1"
onClick={async (event) => {
const text = Array.isArray(children)
? children.join(' ')
: children;
const svgs = event.currentTarget.querySelectorAll('svg');
for (const svg of svgs) {
svg.toggleAttribute('data-copied', true);
}
navigator.clipboard.writeText(props.children.join(''));
await navigator.clipboard.writeText(text);
toast('Copied to clipboard');
setIsCopied(true);
setTimeout(() => setIsCopied(false), 1000);
setTimeout(() => {
for (const svg of svgs) {
svg.toggleAttribute('data-copied', false);
}
}, 1000);
}}
>
{isCopied ? (
<CheckIcon className="h-3 w-3" />
) : (
<CopyIcon className="h-3 w-3" />
)}
{children}
<Check className="h-4.5 w-4.5 p-1 hidden data-[copied]:block" />
<Copy className="h-4.5 w-4.5 p-1 block data-[copied]:hidden" />
</button>
) : undefined}
</>
) : (
children
)}
</code>
);
}