mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-07-22 23:12:02 +00:00
feat(stls): enlarge candidate images in preview picker
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Each loaded candidate gets an enlarge button that opens the ImageLightbox without changing selection, so the right preview is easier to choose. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
Check,
|
Check,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
ImageOff,
|
ImageOff,
|
||||||
|
Maximize2,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -20,6 +21,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { setPreviewFromExtract } from "../actions";
|
import { setPreviewFromExtract } from "../actions";
|
||||||
|
import { ImageLightbox } from "./image-lightbox";
|
||||||
|
|
||||||
interface ArchiveImage {
|
interface ArchiveImage {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -65,6 +67,7 @@ export function ArchivePreviewPicker({
|
|||||||
const [thumbnails, setThumbnails] = useState<Map<string, ThumbnailState>>(new Map());
|
const [thumbnails, setThumbnails] = useState<Map<string, ThumbnailState>>(new Map());
|
||||||
const [selectedPath, setSelectedPath] = useState<string | null>(null);
|
const [selectedPath, setSelectedPath] = useState<string | null>(null);
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
|
const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);
|
||||||
const pollTimers = useRef<Map<string, ReturnType<typeof setInterval>>>(new Map());
|
const pollTimers = useRef<Map<string, ReturnType<typeof setInterval>>>(new Map());
|
||||||
// Track which paths have already been requested to avoid re-requesting
|
// Track which paths have already been requested to avoid re-requesting
|
||||||
const requestedPaths = useRef<Set<string>>(new Set());
|
const requestedPaths = useRef<Set<string>>(new Set());
|
||||||
@@ -290,12 +293,25 @@ export function ArchivePreviewPicker({
|
|||||||
const isFailed = thumbState?.status === "failed";
|
const isFailed = thumbState?.status === "failed";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div key={img.id} className="group relative">
|
||||||
|
{isLoaded && thumbState?.imageUrl && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="absolute top-1.5 left-1.5 z-10 flex h-6 w-6 items-center justify-center rounded-md bg-black/60 text-white opacity-0 transition-opacity hover:bg-black/80 group-hover:opacity-100"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setLightboxSrc(thumbState.imageUrl!);
|
||||||
|
}}
|
||||||
|
title="Enlarge"
|
||||||
|
>
|
||||||
|
<Maximize2 className="h-3.5 w-3.5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
key={img.id}
|
|
||||||
type="button"
|
type="button"
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative aspect-square rounded-lg overflow-hidden border-2 transition-all",
|
"relative aspect-square w-full rounded-lg overflow-hidden border-2 transition-all",
|
||||||
"hover:border-primary/50 cursor-pointer group",
|
"hover:border-primary/50 cursor-pointer",
|
||||||
isSelected
|
isSelected
|
||||||
? "border-primary ring-2 ring-primary/30"
|
? "border-primary ring-2 ring-primary/30"
|
||||||
: "border-border",
|
: "border-border",
|
||||||
@@ -355,6 +371,7 @@ export function ArchivePreviewPicker({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@@ -394,6 +411,13 @@ export function ArchivePreviewPicker({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
<ImageLightbox
|
||||||
|
src={lightboxSrc}
|
||||||
|
open={!!lightboxSrc}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) setLightboxSrc(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user