Created
June 22, 2023 17:40
-
-
Save diego3g/9a7567e6d62a4dfed3427567ad97175e to your computer and use it in GitHub Desktop.
Tailwind with Tailwind Variants Slots API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Button } from '@/components/Button' | |
import { CheckCircle2, Image as ImageIcon, Trash2 } from 'lucide-react' | |
import { useMemo } from 'react' | |
import { tv, VariantProps } from 'tailwind-variants' | |
const fileItem = tv({ | |
slots: { | |
base: 'group flex items-start gap-4 rounded-lg border border-zinc-200 p-4', | |
icon: 'relative rounded-full border-4 border-violet-100 bg-violet-200 p-2 text-violet-600', | |
deleteButton: 'text-zinc-500 hover:text-violet-500', | |
}, | |
variants: { | |
state: { | |
progress: {}, | |
complete: { | |
base: 'border-violet-500', | |
}, | |
error: { | |
base: 'bg-error-25 border-error-300', | |
icon: 'border-error-50 bg-error-100 text-error-600', | |
deleteButton: 'text-error-700 hover:text-error-900', | |
}, | |
}, | |
}, | |
defaultVariants: { | |
state: 'progress', | |
}, | |
}) | |
export interface FileItemProps extends VariantProps<typeof fileItem> { | |
name: string | |
size: number | |
type: string | |
} | |
export function FileItem({ state, name, size, type }: FileItemProps) { | |
const uploadProgress = state === 'complete' ? '100%' : '25%' | |
const fileSize = useMemo(() => { | |
const fileSizeInKB = size / 1024 | |
if (fileSizeInKB > 1024) { | |
const fileSizeInMB = fileSizeInKB / 1024 | |
return fileSizeInMB.toFixed(1).concat(' MB') | |
} | |
return fileSizeInKB.toFixed(1).concat(' KB') | |
}, [size]) | |
const { base, icon, deleteButton } = fileItem({ state }) | |
return ( | |
<div className={base()}> | |
<span className={icon()}> | |
<ImageIcon className="h-4 w-4" /> | |
</span> | |
{state === 'error' ? ( | |
<div className="flex flex-1 flex-col items-start gap-1"> | |
<div className="flex flex-col leading-relaxed"> | |
<span className="text-sm font-medium text-error-700"> | |
Upload failed, please try again | |
</span> | |
<span className="text-sm text-error-600">{name}</span> | |
</div> | |
<button | |
type="button" | |
className="text-sm font-semibold text-error-700 hover:text-error-900" | |
> | |
Try again | |
</button> | |
</div> | |
) : ( | |
<div className="flex flex-1 flex-col items-start gap-1"> | |
<div className="flex flex-col leading-relaxed"> | |
<span className="text-sm font-medium text-zinc-700">{name}</span> | |
<span className="text-sm text-zinc-500">{fileSize}</span> | |
</div> | |
<div className="flex w-full items-center gap-3"> | |
<div className="h-2 flex-1 rounded-full bg-zinc-100"> | |
<div | |
className="h-2 rounded-full bg-violet-600" | |
style={{ width: uploadProgress }} | |
/> | |
</div> | |
<span className="text-sm font-medium text-zinc-700"> | |
{uploadProgress} | |
</span> | |
</div> | |
</div> | |
)} | |
{state === 'complete' ? ( | |
<CheckCircle2 className="h-5 w-5 fill-violet-600 text-white" /> | |
) : ( | |
<Button type="button" variant="ghost" className={deleteButton()}> | |
<Trash2 className="h-5 w-5" /> | |
</Button> | |
)} | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment