mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
media class support and tooltip integration
This commit is contained in:
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));
|
||||
|
||||
Reference in new issue
Block a user