media class support and tooltip integration

This commit is contained in:
bflatastic committed 2025-05-21 16:10:27 +07:00
1 parent 969214710b
commit d159501799
3 files changed
+81 -61

No files matched your search

@@ -20,34 +20,19 @@ export const GalleryDragComponent: React.FC = () => {
const { currX, currY, item } = dragState;
const size = 120;
const style: React.CSSProperties = {
position: "fixed",
left: currX + 1,
top: currY - size / 2,
zIndex: 10000,
width: size,
height: size,
pointerEvents: "none",
aspectRatio: "1 / 1",
display: "flex",
flexDirection: "column",
background: "rgba(0,0,0,0.7)",
borderRadius: 12,
overflow: "hidden",
boxShadow: "0 4px 16px rgba(0,0,0,0.25)",
};
return ReactDOM.createPortal(
<div style={style} className="absolute">
<div
style={style}
className="fixed z-[1000] w-[120px] h-[120px] pointer-events-none aspect-square flex flex-col bg-black/70 rounded-xl overflow-hidden shadow-lg"
>
<img
src={item.thumbnail || item.fullImage || ""}
alt={item.label}
className="pointer-events-none select-none w-full h-full object-cover"
style={{
borderRadius: 12,
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="pointer-events-none select-none w-full h-full object-cover rounded-xl"
/>
</div>,
document.body
@@ -4,6 +4,7 @@ import { faCheck } from "@fortawesome/pro-solid-svg-icons";
import { twMerge } from "tailwind-merge";
import type { GalleryItem } from "./gallery-modal";
import galleryDnd from "./galleryDnd";
import { Tooltip } from "@storyteller/ui-tooltip";
type ModalMode = "select" | "view";
@@ -50,47 +51,73 @@ export const GalleryDraggableItem: React.FC<GalleryDraggableItemProps> = ({
};
return (
<button
type="button"
onPointerDown={handlePointerDown}
className={twMerge(
"group relative overflow-hidden rounded-md border-[3px] transition-all focus:outline-none focus:ring-2 focus:ring-primary",
activeTab === "videos" ? "aspect-video" : "aspect-square",
mode === "select" && selected
? "border-primary"
: "border-transparent hover:border-white"
)}
aria-pressed={selected}
tabIndex={0}
style={{ cursor: "grab" }}
>
<div className="relative h-full w-full">
{!item.thumbnail ? (
<div className="flex h-full w-full items-center justify-center bg-gray-800">
<span className="text-white/60">Image not available</span>
</div>
) : (
<img
ref={imgRef}
src={item.thumbnail || item.fullImage || ""}
alt={item.label}
className={twMerge(
"h-full w-full bg-black/30",
activeTab === "videos" ? "object-contain" : "object-cover"
)}
onError={onImageError}
draggable={false}
/>
)}
{mode === "select" && selected && (
<div className="absolute inset-0 bg-white/30" />
)}
</div>
{mode === "select" && selected && (
<div className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-primary">
<FontAwesomeIcon icon={faCheck} className="text-sm" />
<Tooltip
position="bottom"
delay={200}
className="-mt-3 bg-black/90"
content={
<div className="flex flex-col items-center text-xs whitespace-nowrap">
{activeTab !== "videos" && (
<span>
<span className="font-medium">Drag</span>
<span className="opacity-60"> to add</span>
</span>
)}
<span>
<span className="font-medium">Click</span>
<span className="opacity-60"> to view</span>
</span>
</div>
)}
</button>
}
>
<button
type="button"
onPointerDown={handlePointerDown}
className={twMerge(
"w-full group relative overflow-visible rounded-md border-[3px] transition-all focus:outline-none focus:ring-2 focus:ring-primary",
activeTab === "videos" ? "aspect-video" : "aspect-square",
mode === "select" && selected
? "border-primary"
: "border-transparent hover:border-primary"
)}
aria-pressed={selected}
tabIndex={0}
style={{ cursor: "grab" }}
>
<div className="relative h-full w-full">
{/* Media class badge on hover */}
{item.mediaClass && (
<div className="pointer-events-none absolute right-1 top-1 z-20 rounded-full bg-black/50 backdrop-blur-lg px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-white opacity-0 group-hover:opacity-100 transition-opacity duration-150">
{item.mediaClass}
</div>
)}
{!item.thumbnail ? (
<div className="flex h-full w-full items-center justify-center bg-gray-800">
<span className="text-white/60">Image not available</span>
</div>
) : (
<img
ref={imgRef}
src={item.thumbnail || item.fullImage || ""}
alt={item.label}
className={twMerge(
"h-full w-full bg-black/30",
activeTab === "videos" ? "object-contain" : "object-cover"
)}
onError={onImageError}
draggable={false}
/>
)}
{mode === "select" && selected && (
<div className="absolute inset-0 bg-white/30" />
)}
</div>
{mode === "select" && selected && (
<div className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-primary">
<FontAwesomeIcon icon={faCheck} className="text-sm" />
</div>
)}
</button>
</Tooltip>
);
};
@@ -25,6 +25,7 @@ export interface GalleryItem {
thumbnail: string | null;
fullImage?: string | null;
createdAt: string;
mediaClass?: string;
}
interface GroupedItems {
@@ -169,6 +170,13 @@ export const GalleryModal = React.memo(
),
fullImage: item.media_links.cdn_url,
createdAt: item.created_at,
mediaClass:
item.media_class ||
(item.filter_media_classes
? item.filter_media_classes[0]
: activeTab === "videos"
? "video"
: "image"),
}));
console.log("Media files response:", newItems);
setGroupedItems(groupItemsByDate(newItems));