mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
Implement image fit toggle in GalleryModal for better image display options and lightbox fix
This commit is contained in:
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.
|
||||
|
||||
Reference in new issue
Block a user