mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-22 09:39:31 -04:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6428fe0319 | ||
|
|
043dc47979 | ||
|
|
6eecd20587 |
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"frontendDist": "../../../frontend/apps/editor3d/dist",
|
||||
"beforeDevCommand": "echo 'no dev'",
|
||||
"devUrl": "http://localhost:5173",
|
||||
"beforeBuildCommand": "npx nx run editor3d:build"
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { getCurrentLocationWithoutParams } from "~/utilities";
|
||||
import { Activity } from "~/pages/PageEnigma/comps/GenerateModals/Activity";
|
||||
import {
|
||||
GalleryModal,
|
||||
galleryModalVisibleViewMode,
|
||||
galleryModalVisibleDuringDrag,
|
||||
} from "@storyteller/ui-gallery-modal";
|
||||
import { SettingsModal } from "@storyteller/ui-settings-modal";
|
||||
@@ -110,6 +111,7 @@ export const TopBar = ({
|
||||
};
|
||||
|
||||
const handleOpenGalleryModal = () => {
|
||||
galleryModalVisibleViewMode.value = true;
|
||||
galleryModalVisibleDuringDrag.value = true;
|
||||
};
|
||||
|
||||
@@ -185,8 +187,6 @@ export const TopBar = ({
|
||||
/>
|
||||
|
||||
<GalleryModal
|
||||
isOpen={galleryModalVisibleDuringDrag.value}
|
||||
onClose={() => (galleryModalVisibleDuringDrag.value = false)}
|
||||
mode="view"
|
||||
onDownloadClicked={downloadFileFromUrl}
|
||||
onAddToSceneClicked={handleAddToScene}
|
||||
|
||||
@@ -62,6 +62,22 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { MediaItem } from "~/pages/PageEnigma/models";
|
||||
import { GalleryItem } from "../../../../../../libs/components/gallery-modal/src/lib/gallery-modal";
|
||||
import { UploaderState } from "~/models";
|
||||
import * as THREE from "three";
|
||||
|
||||
// Utility to convert screen (client) coordinates to world coordinates for the image drop
|
||||
function screenToWorld(
|
||||
x: number,
|
||||
y: number,
|
||||
camera: THREE.Camera,
|
||||
renderer: THREE.WebGLRenderer,
|
||||
): THREE.Vector3 {
|
||||
const rect = renderer.domElement.getBoundingClientRect();
|
||||
const ndcX = ((x - rect.left) / rect.width) * 2 - 1;
|
||||
const ndcY = -((y - rect.top) / rect.height) * 2 + 1;
|
||||
const vector = new THREE.Vector3(ndcX, ndcY, 0.5); // z=0.5 for middle of the frustum
|
||||
vector.unproject(camera);
|
||||
return vector;
|
||||
}
|
||||
|
||||
export const PageEditor = () => {
|
||||
useSignals();
|
||||
@@ -78,6 +94,7 @@ export const PageEditor = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Image drop from gallery/library modal
|
||||
useEffect(() => {
|
||||
setOnImageDrop(
|
||||
async (item: GalleryItem, _position: { x: number; y: number }) => {
|
||||
@@ -91,12 +108,30 @@ export const PageEditor = () => {
|
||||
},
|
||||
});
|
||||
console.log("Upload complete, adding object to scene");
|
||||
|
||||
// Calculate world position from cursor
|
||||
let worldPosition = undefined;
|
||||
if (editorEngine?.camera && editorEngine?.renderer && _position) {
|
||||
worldPosition = screenToWorld(
|
||||
_position.x,
|
||||
_position.y,
|
||||
editorEngine.camera,
|
||||
editorEngine.renderer,
|
||||
);
|
||||
}
|
||||
|
||||
const mediaItem: MediaItem = {
|
||||
version: 1,
|
||||
type: AssetType.OBJECT,
|
||||
media_id: item.id || uuidv4(),
|
||||
name: item.label || "Image Plane",
|
||||
// Add other fields as needed
|
||||
...(worldPosition && {
|
||||
position: {
|
||||
x: worldPosition.x,
|
||||
y: worldPosition.y,
|
||||
z: worldPosition.z,
|
||||
},
|
||||
}),
|
||||
};
|
||||
addObject(mediaItem);
|
||||
console.log("Object added to scene:", mediaItem);
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
{
|
||||
"path": "../../libs/components/close-button"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/tauri-api"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/toaster"
|
||||
},
|
||||
@@ -61,6 +58,9 @@
|
||||
{
|
||||
"path": "../../libs/common"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/tauri-api"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/tab-selector"
|
||||
},
|
||||
@@ -84,9 +84,6 @@
|
||||
},
|
||||
{
|
||||
"path": "../../libs/tauri-utils"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/build-env"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useSignals } from "@preact/signals-react/runtime";
|
||||
import {
|
||||
galleryModalVisibleDuringDrag,
|
||||
galleryReopenAfterDragSignal,
|
||||
galleryModalVisibleViewMode,
|
||||
} from "./galleryModalSignals";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
@@ -46,8 +47,7 @@ interface GroupedItems {
|
||||
type ModalMode = "select" | "view";
|
||||
|
||||
interface GalleryModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onClose?: () => void;
|
||||
mode: ModalMode;
|
||||
selectedItemIds?: string[];
|
||||
onSelectItem?: (id: string) => void;
|
||||
@@ -58,11 +58,11 @@ interface GalleryModalProps {
|
||||
url: string,
|
||||
media_id: string | undefined
|
||||
) => Promise<void>;
|
||||
isOpen?: boolean;
|
||||
}
|
||||
|
||||
export const GalleryModal = React.memo(
|
||||
({
|
||||
isOpen,
|
||||
onClose,
|
||||
mode = "view",
|
||||
selectedItemIds = [],
|
||||
@@ -71,6 +71,7 @@ export const GalleryModal = React.memo(
|
||||
onUseSelected,
|
||||
onDownloadClicked,
|
||||
onAddToSceneClicked,
|
||||
isOpen,
|
||||
}: GalleryModalProps) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [lightboxImage, setLightboxImage] = useState<GalleryItem | null>(
|
||||
@@ -145,10 +146,10 @@ export const GalleryModal = React.memo(
|
||||
setUsername(session.data.user.username);
|
||||
}
|
||||
};
|
||||
if (isOpen) {
|
||||
if (isOpen || (mode === "view" && galleryModalVisibleViewMode.value)) {
|
||||
getUsername();
|
||||
}
|
||||
}, [usersApi, isOpen]);
|
||||
}, [usersApi, mode, galleryModalVisibleViewMode.value, isOpen]);
|
||||
|
||||
// filter state
|
||||
const FILTERS = [
|
||||
@@ -286,7 +287,12 @@ export const GalleryModal = React.memo(
|
||||
|
||||
// Soft refresh on open: fetch first page and prepend new items
|
||||
useEffect(() => {
|
||||
if (isOpen && allItems.length > 0 && username) {
|
||||
if (
|
||||
mode === "view" &&
|
||||
galleryModalVisibleViewMode.value &&
|
||||
allItems.length > 0 &&
|
||||
username
|
||||
) {
|
||||
const fetchLatest = async () => {
|
||||
const filterMediaClasses = getFilterMediaClass(activeFilter);
|
||||
const response = await api.listUserMediaFiles({
|
||||
@@ -327,17 +333,26 @@ export const GalleryModal = React.memo(
|
||||
fetchLatest();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isOpen]);
|
||||
}, [mode, galleryModalVisibleViewMode.value]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
isOpen={
|
||||
mode === "view"
|
||||
? isOpen && galleryModalVisibleDuringDrag.value
|
||||
: isOpen
|
||||
? galleryModalVisibleViewMode.value &&
|
||||
galleryModalVisibleDuringDrag.value
|
||||
: typeof isOpen === "boolean"
|
||||
? isOpen
|
||||
: true
|
||||
}
|
||||
onClose={onClose}
|
||||
onClose={() => {
|
||||
if (mode === "view") {
|
||||
onClose?.() || (galleryModalVisibleViewMode.value = false);
|
||||
} else {
|
||||
onClose?.();
|
||||
}
|
||||
}}
|
||||
className={twMerge(
|
||||
"h-[620px] max-w-4xl",
|
||||
mode === "view" && "h-[640px] max-w-4xl"
|
||||
@@ -440,7 +455,10 @@ export const GalleryModal = React.memo(
|
||||
showIconsInList={true}
|
||||
/>
|
||||
{mode === "view" && <Modal.ExpandButton />}
|
||||
<CloseButton onClick={onClose} className="relative z-[51]" />
|
||||
<CloseButton
|
||||
onClick={() => (galleryModalVisibleViewMode.value = false)}
|
||||
className="relative z-[51]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -541,7 +559,11 @@ export const GalleryModal = React.memo(
|
||||
<LightboxModal
|
||||
isOpen={isLightboxVisible}
|
||||
onClose={handleCloseLightbox}
|
||||
onCloseGallery={onClose}
|
||||
onCloseGallery={() =>
|
||||
mode === "view"
|
||||
? (galleryModalVisibleViewMode.value = false)
|
||||
: onClose?.()
|
||||
}
|
||||
imageUrl={imageUrl}
|
||||
imageAlt={lightboxImage?.label || ""}
|
||||
onImageError={() => imageUrl && handleImageError(imageUrl)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { signal } from "@preact/signals-react";
|
||||
|
||||
export const galleryModalVisibleDuringDrag = signal(false);
|
||||
export const galleryModalVisibleDuringDrag = signal(true);
|
||||
export const galleryReopenAfterDragSignal = signal(false);
|
||||
export const galleryModalVisibleViewMode = signal(false);
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../slider-v2"
|
||||
},
|
||||
{
|
||||
"path": "../popover"
|
||||
},
|
||||
{
|
||||
"path": "../../api"
|
||||
},
|
||||
@@ -14,15 +20,15 @@
|
||||
{
|
||||
"path": "../button"
|
||||
},
|
||||
{
|
||||
"path": "../tab-selector"
|
||||
},
|
||||
{
|
||||
"path": "../lightbox-modal"
|
||||
},
|
||||
{
|
||||
"path": "../modal"
|
||||
},
|
||||
{
|
||||
"path": "../tooltip"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../slider-v2/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../popover/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../api/tsconfig.lib.json"
|
||||
},
|
||||
@@ -55,14 +61,14 @@
|
||||
{
|
||||
"path": "../button/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../tab-selector/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../lightbox-modal/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../modal/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../tooltip/tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../tauri-api"
|
||||
},
|
||||
{
|
||||
"path": "../button"
|
||||
},
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../tauri-api/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../button/tsconfig.lib.json"
|
||||
},
|
||||
|
||||
@@ -82,7 +82,6 @@ export const PromptBox2D = ({
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [isEnqueueing, setIsEnqueueing] = useState(false);
|
||||
const [useSystemPrompt, setUseSystemPrompt] = useState(true);
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
const [selectedGalleryImages, setSelectedGalleryImages] = useState<string[]>(
|
||||
[]
|
||||
);
|
||||
@@ -111,6 +110,8 @@ export const PromptBox2D = ({
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) {
|
||||
textareaRef.current.style.height = "auto";
|
||||
@@ -185,9 +186,7 @@ export const PromptBox2D = ({
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleGallerySelect = () => {
|
||||
setIsGalleryModalOpen(true);
|
||||
};
|
||||
const handleGallerySelect = () => setIsGalleryModalOpen(true);
|
||||
|
||||
const handleGalleryClose = () => {
|
||||
setIsGalleryModalOpen(false);
|
||||
@@ -638,7 +637,7 @@ export const PromptBox2D = ({
|
||||
</div>
|
||||
</div>
|
||||
<GalleryModal
|
||||
isOpen={isGalleryModalOpen}
|
||||
isOpen={!!isGalleryModalOpen}
|
||||
onClose={handleGalleryClose}
|
||||
mode="select"
|
||||
selectedItemIds={selectedGalleryImages}
|
||||
|
||||
@@ -139,10 +139,10 @@ export const PromptBox3D = ({
|
||||
},
|
||||
]);
|
||||
const [isCameraSettingsOpen, setIsCameraSettingsOpen] = useState(false);
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
const [selectedGalleryImages, setSelectedGalleryImages] = useState<string[]>(
|
||||
[]
|
||||
);
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) {
|
||||
@@ -257,10 +257,7 @@ export const PromptBox3D = ({
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleGallerySelect = () => {
|
||||
setIsGalleryModalOpen(true);
|
||||
};
|
||||
|
||||
const handleGallerySelect = () => setIsGalleryModalOpen(true);
|
||||
const handleGalleryClose = () => {
|
||||
setIsGalleryModalOpen(false);
|
||||
setSelectedGalleryImages([]);
|
||||
@@ -521,7 +518,7 @@ export const PromptBox3D = ({
|
||||
}
|
||||
};
|
||||
|
||||
const getCurrentSoraRemixAspectRatio = () : SoraImageRemixAspectRatio => {
|
||||
const getCurrentSoraRemixAspectRatio = (): SoraImageRemixAspectRatio => {
|
||||
switch (cameraAspectRatio.value) {
|
||||
case CameraAspectRatio.HORIZONTAL_3_2:
|
||||
return SoraImageRemixAspectRatio.Wide;
|
||||
@@ -532,7 +529,7 @@ export const PromptBox3D = ({
|
||||
default:
|
||||
return SoraImageRemixAspectRatio.Square;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveFrame = async () => {
|
||||
if (!snapshotCurrentFrame) {
|
||||
@@ -828,7 +825,7 @@ export const PromptBox3D = ({
|
||||
/>
|
||||
</div>
|
||||
<GalleryModal
|
||||
isOpen={isGalleryModalOpen}
|
||||
isOpen={!!isGalleryModalOpen}
|
||||
onClose={handleGalleryClose}
|
||||
mode="select"
|
||||
selectedItemIds={selectedGalleryImages}
|
||||
|
||||
@@ -73,7 +73,6 @@ export const PromptBoxVideo = ({
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [isEnqueueing, setIsEnqueueing] = useState(false);
|
||||
const [useSystemPrompt, setUseSystemPrompt] = useState(true);
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
const [selectedGalleryImages, setSelectedGalleryImages] = useState<string[]>(
|
||||
[]
|
||||
);
|
||||
@@ -132,10 +131,9 @@ export const PromptBoxVideo = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleGallerySelect = () => {
|
||||
setIsGalleryModalOpen(true);
|
||||
};
|
||||
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
|
||||
|
||||
const handleGallerySelect = () => setIsGalleryModalOpen(true);
|
||||
const handleGalleryClose = () => {
|
||||
setIsGalleryModalOpen(false);
|
||||
setSelectedGalleryImages([]);
|
||||
@@ -411,7 +409,7 @@ export const PromptBoxVideo = ({
|
||||
</div>
|
||||
</div>
|
||||
<GalleryModal
|
||||
isOpen={isGalleryModalOpen}
|
||||
isOpen={!!isGalleryModalOpen}
|
||||
onClose={handleGalleryClose}
|
||||
mode="select"
|
||||
selectedItemIds={selectedGalleryImages}
|
||||
|
||||
Reference in New Issue
Block a user