66 lines
1.6 KiB
TypeScript
66 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import {
|
|
Dialog,
|
|
DialogClose,
|
|
DialogContent,
|
|
DialogTitle,
|
|
DialogTrigger
|
|
} from "@/components/ui/dialog";
|
|
|
|
type ZoomableImageProps = {
|
|
src: string;
|
|
alt: string;
|
|
width: number;
|
|
height: number;
|
|
className?: string;
|
|
};
|
|
|
|
/** 点击图片放大预览,再点任意区域关闭 */
|
|
export const ZoomableImage = ({
|
|
src,
|
|
alt,
|
|
width,
|
|
height,
|
|
className
|
|
}: ZoomableImageProps) => {
|
|
const imageSrc = src || "/placeholder.svg";
|
|
const previewLabel = alt || "图片预览";
|
|
|
|
return (
|
|
<Dialog>
|
|
<DialogTrigger
|
|
className={`block w-full cursor-zoom-in border-0 bg-transparent p-0 ${className ?? ""}`}
|
|
aria-label={alt ? `放大查看:${alt}` : "放大查看图片"}
|
|
>
|
|
<Image
|
|
src={imageSrc}
|
|
alt={alt}
|
|
width={width}
|
|
height={height}
|
|
className="h-auto w-full"
|
|
/>
|
|
</DialogTrigger>
|
|
|
|
<DialogContent
|
|
showCloseButton={false}
|
|
overlayClassName="cursor-zoom-out bg-background/90 backdrop-blur-sm"
|
|
className="w-full max-w-none border-0 bg-transparent p-0 px-2 shadow-none ring-0 md:w-auto md:px-0"
|
|
>
|
|
<DialogTitle className="sr-only">{previewLabel}</DialogTitle>
|
|
{/* 点击预览图本身也会关闭 */}
|
|
<DialogClose className="block w-full cursor-zoom-out border-0 bg-transparent p-0 md:w-[80vw]">
|
|
<Image
|
|
src={imageSrc}
|
|
alt={alt}
|
|
width={width * 2}
|
|
height={height * 2}
|
|
className="h-auto max-h-svh w-full object-contain"
|
|
/>
|
|
</DialogClose>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|