Frame buttons: Show preview and add deletion function

This commit is contained in:
Tanish Manku committed 2025-01-09 21:13:14 -08:00
1 parent cc51b45e0d
commit daebc158f6
5 files changed
+99 -23

No files matched your search

@@ -11,7 +11,7 @@ import { UploadImageMedia } from "./UploadImageMedia";
interface Props {
onClose: () => void;
onSuccess: (data?: unknown) => void;
onSuccess: (data?: string) => void;
isOpen: boolean;
title: string;
fileTypes: string[];
+1 -1
View File
@@ -3,7 +3,7 @@ import { UploaderStates } from "~/enums";
export interface UploaderState {
status: UploaderStates;
errorMessage?: string;
data?: unknown;
data?: string;
}
export const initialUploaderState = {
@@ -1,11 +1,18 @@
import { faImage } from "@fortawesome/pro-solid-svg-icons";
import { faImage, faTrashCan } from "@fortawesome/pro-solid-svg-icons";
import { ButtonIconStack } from "~/components/reusable/ButtonIconStack";
import { frameTrackButtonWidthPx } from "../../signals";
import { useCallback, useContext, useState } from "react";
import { useCallback, useContext, useRef, useState } from "react";
import { EngineContext } from "../../contexts/EngineContext";
import { CHARACTER_FRAME_FILE_TYPE } from "~/enums";
import { UploadModalMedia } from "~/components/reusable/UploadModalMedia";
import { UploadImageMediaModal } from "~/components/reusable/UploadModalMedia/UploadImageMediaModal";
import { MediaFilesApi } from "~/Classes/ApiManager";
import { MediaFile } from "../../models";
import { ApiResponse } from "~/Classes/ApiManager/ApiManager";
import { get_media_url } from "~/Classes/ApiHelpers";
import { twMerge } from "tailwind-merge";
import { ButtonIcon } from "~/components";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export enum CharacterFrameTarget {
Start,
@@ -31,25 +38,93 @@ export default function CharacterFrameButton(
}: CharacterFrameButtonProps
) {
const clickable = useRef(true);
const editorEngine = useContext(EngineContext);
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
const [mediaFile, setMediaFile] = useState<string | undefined>(undefined);
const handleFrameClick = useCallback(() => {
if (!clickable.current) {
return;
}
})
// Make button unresponsive to clicks until modal is closed
clickable.current = false;
setIsUploadModalOpen(true);
}, [])
return (
<>
<div className={className} style={{ minWidth: frameTrackButtonWidthPx, width: frameTrackButtonWidthPx }}>
<ButtonIconStack icon={faImage} additionalStyle="bg-character-frame" text={CharacterFrameStrings[target]} onClick={() => setIsUploadModalOpen(true)} />
</div>
<UploadImageMediaModal
isOpen={isUploadModalOpen}
onClose={() => setIsUploadModalOpen(false)}
onSuccess={(data) => { console.log(data); setIsUploadModalOpen(false) }}
title={"Upload Character Frame Image"}
fileTypes={Object.values(CHARACTER_FRAME_FILE_TYPE)}
/>
</>
)
const unlockButton = useCallback(() => {
clickable.current = true;
setIsUploadModalOpen(false);
}, [setIsUploadModalOpen]);
const handleFrameSet = useCallback((token?: string) => {
if (!token) {
return;
}
// TODO: Fetch the image and pass the token to the character engine
// Fetch the image and set as button bg
get_media_url(token)
.then((url) => {
setMediaFile(url);
})
.catch((error) => {
console.error("Error fetching media file", error);
})
.finally(() => {
unlockButton();
})
}, [unlockButton, setMediaFile]);
const handleDeleteFrame = useCallback(() => {
setMediaFile(undefined);
unlockButton();
}, [unlockButton, setMediaFile]);
if (!mediaFile) {
return (
<>
<div className={className} style={{ minWidth: frameTrackButtonWidthPx, width: frameTrackButtonWidthPx }}>
<ButtonIconStack icon={faImage} additionalStyle="bg-character-frame" text={CharacterFrameStrings[target]} onClick={handleFrameClick} />
</div>
<UploadImageMediaModal
isOpen={isUploadModalOpen}
onClose={unlockButton}
onSuccess={handleFrameSet}
title={"Upload Character Frame Image"}
fileTypes={Object.values(CHARACTER_FRAME_FILE_TYPE)}
/>
</>
)
} else {
const classes = twMerge([
className,
"bg-character-unselected overflow-hidden"
]);
const buttonClasses = twMerge([
"absolute flex box-content top-1 right-1 w-6 h-6 rounded-md invisible group-hover:visible items-center justify-center",
"bg-gray-800 hover:bg-red text-gray-500 hover:text-gray-100 border-2 border-transparent hover:border-white",
"transition-all duration-150",
])
return (
<>
<div className={classes} style={{ minWidth: frameTrackButtonWidthPx, width: frameTrackButtonWidthPx }}>
<div className={"rounded-md w-full h-full relative group border-2 border-gray-400"}>
<img crossOrigin="anonymous" src={mediaFile} alt={CharacterFrameStrings[target]} className={"rounded-md object-cover w-full h-full"} />
<button className={buttonClasses} onClick={handleDeleteFrame}>
<FontAwesomeIcon icon={faTrashCan} size={"xs"} className={""} />
</button>
</div>
</div>
</>
)
}
}
@@ -3,6 +3,7 @@ import { useState } from "react";
import {
canDrop,
dragItem,
frameTrackButtonWidthPx,
scale,
selectedItem,
} from "~/pages/PageEnigma/signals";
@@ -54,7 +55,7 @@ export const TrackClip = ({ clip, min, max, group, updateClip }: Props) => {
: "",
].join(" ")}
style={{
left: offset * 4 * scale.value,
left: offset * 4 * scale.value + frameTrackButtonWidthPx,
}}
onPointerDown={(event) => onPointerDown(event, "left")}
onPointerMove={() => {
@@ -83,7 +84,7 @@ export const TrackClip = ({ clip, min, max, group, updateClip }: Props) => {
].join(" ")}
style={{
width: length * 4 * scale.value - 30,
left: offset * 4 * scale.value + 15,
left: offset * 4 * scale.value + 15 + frameTrackButtonWidthPx,
cursor: "move",
}}
onPointerDown={(event) => onPointerDown(event, "drag")}
@@ -116,7 +117,7 @@ export const TrackClip = ({ clip, min, max, group, updateClip }: Props) => {
: "",
].join(" ")}
style={{
left: offset * 4 * scale.value + length * 4 * scale.value - 15,
left: offset * 4 * scale.value + length * 4 * scale.value - 15 + frameTrackButtonWidthPx,
}}
onPointerDown={(event) => onPointerDown(event, "right")}
onPointerMove={() => {
@@ -95,7 +95,7 @@ export const TrackClips = ({ id, clips, updateClip, group, type }: Props) => {
<div
id={`track-${trackType}-${id}`}
className={[
"relative mb-1 flex h-[60px] w-fit rounded-md overflow-clip",
"relative mb-1 flex h-[60px] w-fit rounded-md overflow-hidden",
].join(" ")}
style={{ marginLeft: (group === ClipGroup.CHARACTER ? 0 : frameTrackButtonWidthPx) }}
>