combine upload and add popover

This commit is contained in:
bflatastic committed 2025-07-22 20:15:45 +07:00
1 parent 5afdc85fc1
commit 800e22ccab
2 files changed
+144 -156

No files matched your search

@@ -5,8 +5,8 @@ import {
faPlus,
faUpRightAndDownLeftFromCenter,
faCube,
faArrowUpFromBracket,
faImages,
faArrowUpFromBracket,
} from "@fortawesome/pro-solid-svg-icons";
import { ButtonIconSelect } from "@storyteller/ui-button-icon-select";
import { Button } from "@storyteller/ui-button";
@@ -44,7 +44,7 @@ import {
galleryModalVisibleDuringDrag,
} from "@storyteller/ui-gallery-modal";
import { twMerge } from "tailwind-merge";
import { UploadModalImage } from "~/components/reusable/UploadModalImage";
import { UploadModalImage } from "../../../../components/reusable/UploadModalImage";
export const Controls3D = () => {
useSignals();
@@ -190,19 +190,6 @@ export const Controls3D = () => {
}
};
const handleUploadAction = (action: string) => {
switch (action) {
case "3d":
setUpload3DIsShowing(true);
break;
case "image":
setUploadImageIsShowing(true);
break;
default:
break;
}
};
// Open global Gallery modal
const handleOpenGalleryModal = () => {
galleryModalVisibleViewMode.value = true;
@@ -217,6 +204,12 @@ export const Controls3D = () => {
case "library":
handleOpenGalleryModal();
break;
case "upload-3d":
setUpload3DIsShowing(true);
break;
case "upload-image":
setUploadImageIsShowing(true);
break;
default:
break;
}
@@ -286,7 +279,7 @@ export const Controls3D = () => {
<PopoverMenu
mode="button"
position="bottom"
panelTitle="Add asset from"
panelTitle="Add an asset to scene"
onOpenChange={setIsAddAssetPopoverOpen}
items={[
{
@@ -307,6 +300,29 @@ export const Controls3D = () => {
/>
),
action: "library",
divider: true,
},
{
label: "Upload 3D Model",
selected: false,
icon: (
<FontAwesomeIcon
icon={faArrowUpFromBracket}
className="h-4 w-4"
/>
),
action: "upload-3d",
},
{
label: "Upload Image",
selected: false,
icon: (
<FontAwesomeIcon
icon={faArrowUpFromBracket}
className="h-4 w-4"
/>
),
action: "upload-image",
},
]}
onPanelAction={handleAddAssetAction}
@@ -322,45 +338,6 @@ export const Controls3D = () => {
/>
</Tooltip>
</div>
<Tooltip
content="Upload an asset"
position="bottom"
delay={300}
closeOnClick
>
<PopoverMenu
mode="button"
position="bottom"
panelTitle="Upload an asset"
items={[
{
label: "3D Model",
selected: false,
icon: (
<FontAwesomeIcon icon={faCube} className="h-4 w-4" />
),
action: "3d",
},
{
label: "Image",
selected: false,
icon: (
<FontAwesomeIcon icon={faImages} className="h-4 w-4" />
),
action: "image",
},
]}
onPanelAction={handleUploadAction}
showIconsInList
buttonClassName="h-9 w-9 rounded-[10px] text-lg bg-white/15 transition-colors hover:bg-white/25"
triggerIcon={
<FontAwesomeIcon
icon={faArrowUpFromBracket}
className="text-lg"
/>
}
/>
</Tooltip>
<Tooltip
content="Create 3D model from image"
position="bottom"
@@ -21,6 +21,7 @@ export interface PopoverItem {
icon?: ReactNode;
action?: string;
disabled?: boolean;
divider?: boolean;
description?: string;
badges?: Array<{
label: string;
@@ -272,70 +273,74 @@ export const PopoverMenu = ({
) : mode === "hoverSelect" ? (
<div className="flex flex-col gap-0 text-sm text-white">
{items.map((item, index) => (
<div
key={index}
onClick={() => {
if (!item.disabled) {
handleItemClick(item, close);
}
}}
className={twMerge(
"group flex cursor-pointer items-start gap-2 rounded-lg px-2 py-2 transition-all",
item.selected
? "bg-black/40 border-l-4 border-primary"
: "hover:bg-black/20",
item.disabled
? "!cursor-not-allowed opacity-50"
: ""
)}
style={{ minHeight: 48 }}
>
<div className="flex items-center gap-2 w-full">
<div className="flex items-start gap-2 grow">
{showIconsInList && (
<span className="mt-1 flex h-5 w-5 items-center justify-center text-lg text-white/80">
{item.icon}
</span>
)}
<div className="flex flex-1 flex-col min-w-0">
<div className="flex items-center gap-2 min-w-0">
<span className="truncate font-semibold text-white text-base">
{item.label}
<div key={index}>
<div
onClick={() => {
if (!item.disabled) {
handleItemClick(item, close);
}
}}
className={twMerge(
"group flex cursor-pointer items-start gap-2 rounded-lg px-2 py-2 transition-all",
item.selected
? "bg-black/40 border-l-4 border-primary"
: "hover:bg-black/20",
item.disabled
? "!cursor-not-allowed opacity-50"
: ""
)}
style={{ minHeight: 48 }}
>
<div className="flex items-center gap-2 w-full">
<div className="flex items-start gap-2 grow">
{showIconsInList && (
<span className="mt-1 flex h-5 w-5 items-center justify-center text-lg text-white/80">
{item.icon}
</span>
</div>
{item.description && (
<div className="truncate text-xs text-white/60 mt-0.5">
{item.description}
</div>
)}
<div className="flex flex-1 flex-col min-w-0">
<div className="flex items-center gap-2 min-w-0">
<span className="truncate font-semibold text-white text-base">
{item.label}
</span>
</div>
<div className="flex flex-row gap-1 flex-wrap mt-1.5">
{item.badges &&
Array.isArray(item.badges) &&
item.badges.map((badge, i) => (
<div
key={i}
className="flex items-center gap-1 min-w-0"
>
<span className="inline-flex items-center rounded bg-black/40 px-1.5 py-0.5 text-xs font-medium text-white gap-1">
{badge?.icon && (
<span>{badge.icon}</span>
)}
{badge?.label || ""}
</span>
</div>
))}
{item.description && (
<div className="truncate text-xs text-white/60 mt-0.5">
{item.description}
</div>
)}
<div className="flex flex-row gap-1 flex-wrap mt-1.5">
{item.badges &&
Array.isArray(item.badges) &&
item.badges.map((badge, i) => (
<div
key={i}
className="flex items-center gap-1 min-w-0"
>
<span className="inline-flex items-center rounded bg-black/40 px-1.5 py-0.5 text-xs font-medium text-white gap-1">
{badge?.icon && (
<span>{badge.icon}</span>
)}
{badge?.label || ""}
</span>
</div>
))}
</div>
</div>
</div>
</div>
{item.selected && (
<span className="text-primary text-xl font-bold bg-white rounded-full p-0 h-4 w-4 flex items-center justify-center mr-1">
<FontAwesomeIcon icon={faCircleCheck} />
</span>
)}
{item.selected && (
<span className="text-primary text-xl font-bold bg-white rounded-full p-0 h-4 w-4 flex items-center justify-center mr-1">
<FontAwesomeIcon icon={faCircleCheck} />
</span>
)}
</div>
</div>
{item.divider && (
<div className="my-1 border-t border-white/10" />
)}
</div>
))}
{showAddButton && onAdd && (
@@ -357,57 +362,63 @@ export const PopoverMenu = ({
) : (
<div className="flex flex-col gap-0 text-sm text-white">
{items.map((item, index) => (
<Button
key={index}
className={twMerge(
"flex w-full items-center justify-between border-transparent bg-transparent px-1.5",
"hover:bg-[#63636B]/60",
mode === "toggle" && item.selected
? "hover:bg-[#63636B]"
: "bg-transparent",
item.disabled
? "!cursor-not-allowed opacity-50"
: ""
)}
onClick={() =>
!item.disabled && handleItemClick(item, close)
}
variant="secondary"
disabled={item.disabled}
>
<div className="flex items-center gap-2 truncate">
{showIconsInList && item.icon}
{mode === "toggle" ? (
<div key={index}>
<Button
className={twMerge(
"flex w-full items-center justify-between border-transparent bg-transparent px-1.5",
"hover:bg-[#63636B]/60",
mode === "toggle" && item.selected
? "hover:bg-[#63636B]"
: "bg-transparent",
item.disabled
? "!cursor-not-allowed opacity-50"
: ""
)}
onClick={() =>
!item.disabled && handleItemClick(item, close)
}
variant="secondary"
disabled={item.disabled}
>
<div className="flex items-center gap-2 truncate">
{showIconsInList && item.icon}
{mode === "toggle" ? (
<span
className={twMerge(
"truncate",
item.selected
? "text-white"
: "text-white/70"
)}
>
{item.label}
</span>
) : (
<span className="truncate">{item.label}</span>
)}
</div>
{mode === "toggle" && (
<span
className={twMerge(
"truncate",
item.selected ? "text-white" : "text-white/70"
"ml-2 h-5 w-5 rounded-full border flex items-center justify-center transition-colors",
item.selected
? "border-primary bg-primary"
: "border-transparent bg-transparent"
)}
>
{item.label}
{item.selected && (
<FontAwesomeIcon
icon={faCheck}
className="text-white text-xs font-bold"
/>
)}
</span>
) : (
<span className="truncate">{item.label}</span>
)}
</div>
{mode === "toggle" && (
<span
className={twMerge(
"ml-2 h-5 w-5 rounded-full border flex items-center justify-center transition-colors",
item.selected
? "border-primary bg-primary"
: "border-transparent bg-transparent"
)}
>
{item.selected && (
<FontAwesomeIcon
icon={faCheck}
className="text-white text-xs font-bold"
/>
)}
</span>
</Button>
{item.divider && (
<div className="my-1 border-t border-white/10" />
)}
</Button>
</div>
))}
{showAddButton && onAdd && (
<Button