Image Button
A compact image button.
Loading…
Utils.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Packages
npm i lucide-react"use client";
import { cn } from "@/lib/utils";
import Image from "next/image";
import { X } from "lucide-react";
interface ImageButtonProps {
image: {
dataUrl: string;
};
displayName: string;
isExpanded: boolean;
onToggle: () => void;
}
const ImageButton = ({
image,
displayName,
isExpanded,
onToggle,
}: ImageButtonProps) => (
<div className="relative group flex-shrink-0">
{/* Main button */}
<button
type="button"
onClick={onToggle}
aria-expanded={isExpanded}
className={cn(
"relative flex items-center overflow-hidden cursor-pointer rounded-[6px]",
"bg-gradient-to-br from-zinc-50 to-zinc-100 dark:from-zinc-900 dark:to-zinc-950",
"border border-zinc-200/80 dark:border-zinc-800",
"shadow-[0_1px_3px_rgba(0,0,0,0.05),inset_0_1px_0_rgba(255,255,255,0.6)]",
"dark:shadow-[0_1px_3px_rgba(0,0,0,0.3),inset_0_1px_0_rgba(255,255,255,0.05)]",
"hover:shadow-[0_4px_12px_rgba(0,0,0,0.08),inset_0_1px_0_rgba(255,255,255,0.6)]",
"dark:hover:shadow-[0_4px_12px_rgba(0,0,0,0.4),inset_0_1px_0_rgba(255,255,255,0.05)]",
"transition-all duration-300 ease-out",
isExpanded ? "w-44 h-32 p-0" : "w-40 h-10 pl-1.5 pr-9 gap-2.5"
)}
>
{/* Expanded image view */}
{isExpanded && (
<div
className={cn(
"absolute inset-0 transition-opacity duration-200",
"opacity-100 delay-75"
)}
>
<div className="relative w-full h-full overflow-hidden">
<Image
src={image.dataUrl}
alt={displayName}
fill
unoptimized
className="object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" />
{/* Shimmer effect */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent -translate-x-full group-hover:translate-x-full transition-transform duration-1000 ease-in-out" />
<div className="absolute bottom-2 left-3 right-3">
<p className="text-white text-xs font-medium truncate drop-shadow-xl">
{displayName}
</p>
</div>
</div>
</div>
)}
{!isExpanded && (
<span
className={cn(
"flex items-center gap-2.5 text-sm truncate leading-none transition-all duration-200",
)}
>
<span className="relative flex-shrink-0 w-7 h-7 rounded-[8px] overflow-hidden border border-zinc-200/50 dark:border-zinc-700/50 bg-background" >
<Image
src={image.dataUrl}
alt={displayName}
fill
unoptimized
className="object-cover"
/>
</span>
<span className="truncate font-medium text-zinc-700 dark:text-zinc-300">
{displayName}
</span>
</span>
)}
</button>
</div>
);
export ImageButton;