Implement image fit toggle in GalleryModal for better image display options and lightbox fix

This commit is contained in:
bflatastic committed 2025-05-21 19:29:56 +07:00
1 parent 6d98604cc2
commit ff75ebc92f
3 files changed
+31 -10

No files matched your search

@@ -16,6 +16,7 @@ interface GalleryDraggableItemProps {
onClick: () => void;
onImageError: () => void;
disableTooltipAndBadge?: boolean;
imageFit?: "cover" | "contain";
}
export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
@@ -26,6 +27,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
onClick,
onImageError,
disableTooltipAndBadge = false,
imageFit = "cover",
}) => {
const imgRef = useRef<HTMLImageElement>(null);
const dragStarted = useRef(false);
@@ -72,7 +74,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
<div
className={twMerge(
"group relative w-full",
activeFilter === "video" ? "aspect-video" : "aspect-square"
activeFilter === "video" ? "aspect-square" : "aspect-square"
)}
>
{/* Media class badge on hover */}
@@ -88,7 +90,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
tabIndex={0}
className={twMerge(
"w-full group relative overflow-visible rounded-md border-[3px] transition-all focus:outline-none focus:ring-2 focus:ring-primary",
activeFilter === "video" ? "aspect-video" : "aspect-square",
activeFilter === "video" ? "aspect-square" : "aspect-square",
selected
? "border-primary"
: "border-transparent hover:border-primary"
@@ -110,7 +112,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
alt={item.label}
className={twMerge(
"h-full w-full bg-black/30",
activeFilter === "video" ? "object-contain" : "object-cover"
imageFit === "contain" ? "object-contain" : "object-cover"
)}
draggable={false}
onError={onImageError}
@@ -148,7 +150,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
tabIndex={0}
className={twMerge(
"w-full group relative overflow-visible rounded-md border-[3px] transition-all focus:outline-none focus:ring-2 focus:ring-primary",
activeFilter === "video" ? "aspect-video" : "aspect-square",
activeFilter === "video" ? "aspect-square" : "aspect-square",
selected
? "border-primary"
: "border-transparent hover:border-primary"
@@ -170,7 +172,7 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
alt={item.label}
className={twMerge(
"h-full w-full bg-black/30",
activeFilter === "video" ? "object-contain" : "object-cover"
imageFit === "contain" ? "object-contain" : "object-cover"
)}
draggable={false}
onError={onImageError}
@@ -24,6 +24,8 @@ import {
faVideo,
faCube,
faUpload,
faExpand,
faCompress,
} from "@fortawesome/pro-solid-svg-icons";
import { PopoverMenu } from "@storyteller/ui-popover";
import { SliderV2 } from "@storyteller/ui-sliderv2";
@@ -87,6 +89,7 @@ export const GalleryModal = React.memo(
maxColumns - (defaultGridColumns - minColumns)
);
const gridColumns = maxColumns - (sliderValue - minColumns);
const [imageFit, setImageFit] = useState<"cover" | "contain">("contain");
const imageUrl = lightboxImage?.fullImage || "";
@@ -322,8 +325,23 @@ export const GalleryModal = React.memo(
)}
</div>
<div className="flex justify-end gap-2 items-center">
{/* Image fit toggle button */}
<Button
variant="action"
onClick={() =>
setImageFit((fit) =>
fit === "cover" ? "contain" : "cover"
)
}
className="relative z-[51] h-9 w-9 mr-3 bg-[#5F5F68]/60 hover:bg-[#5F5F68]/90"
>
<FontAwesomeIcon
icon={imageFit === "cover" ? faExpand : faCompress}
className="text-lg text-white"
/>
</Button>
{/* Slider */}
<div className="w-48 mr-4 relative z-[51] flex items-center gap-2">
<div className="w-48 mr-3 relative z-[51] flex items-center gap-2">
<SliderV2
min={minColumns}
max={maxColumns}
@@ -408,6 +426,7 @@ export const GalleryModal = React.memo(
handleImageError(item.thumbnail!)
}
disableTooltipAndBadge={mode === "select"}
imageFit={imageFit}
/>
))}
</div>
@@ -459,7 +478,7 @@ export const GalleryModal = React.memo(
mediaId={lightboxImage?.id}
onDownloadClicked={onDownloadClicked}
onAddToSceneClicked={onAddToSceneClicked}
activeTab={activeFilter}
mediaClass={lightboxImage?.mediaClass}
/>
</>
);
@@ -26,7 +26,7 @@ interface LightboxModalProps {
url: string,
media_id: string | undefined
) => Promise<void>;
activeTab?: string;
mediaClass?: string;
}
export function LightboxModal({
@@ -43,7 +43,7 @@ export function LightboxModal({
mediaId, // media id of the image
onDownloadClicked,
onAddToSceneClicked,
activeTab,
mediaClass,
}: LightboxModalProps) {
return createPortal(
<Transition appear show={isOpen}>
@@ -94,7 +94,7 @@ export function LightboxModal({
<div className="flex h-full w-full items-center justify-center bg-gray-800">
<span className="text-white/60">Image not available</span>
</div>
) : activeTab === "videos" ? (
) : mediaClass === "video" ? (
<video controls className="h-full w-full object-contain">
<source src={imageUrl} type="video/mp4" />
Your browser does not support the video tag.