From dedd8340b569152d980d091ba928500beb315040 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Tue, 23 Apr 2024 20:48:17 +0700 Subject: [PATCH 1/3] control panel redesign --- app/components/InputVector.tsx | 108 ++++++++++++++---- .../ControlPanelSceneObject.tsx | 100 +++++++++------- app/styles/base.css | 12 ++ 3 files changed, 155 insertions(+), 65 deletions(-) diff --git a/app/components/InputVector.tsx b/app/components/InputVector.tsx index 9fc8464d44..d25b4c0d37 100644 --- a/app/components/InputVector.tsx +++ b/app/components/InputVector.tsx @@ -1,24 +1,35 @@ import { useRef } from "react"; import { twMerge } from "tailwind-merge"; -import { disableHotkeyInput,enableHotkeyInput,DomLevels } from "~/pages/PageEnigma/store"; +import { + disableHotkeyInput, + enableHotkeyInput, + DomLevels, +} from "~/pages/PageEnigma/store"; interface InputVectorProps { x: number; y: number; z: number; onChange: (v: { x: number; y: number; z: number }) => void; + increment?: number; } -export const InputVector = ({ x, y, z, onChange }: InputVectorProps) => { +export const InputVector = ({ + x, + y, + z, + onChange, + increment = 0.1, +}: InputVectorProps) => { const xRef = useRef(null); const yRef = useRef(null); const zRef = useRef(null); const inputCommonClasses = - "relative w-14 h-7 rounded-r-lg bg-brand-secondary p-3 text-sm text-white transition-all duration-150 ease-in-out outline-none -outline-offset-2"; + "relative h-6 rounded-r-lg bg-brand-secondary p-2 text-sm text-white transition-all duration-100 ease-in-out outline-none -outline-offset-2 text-end w-full hover:cursor-e-resize hover:bg-brand-secondary-900"; const wrapperCommonClasses = - "flex items-center before:inline-block before:w-10 before:h-10 before:bg-brand-primary before:text-white before:rounded-l-lg before:h-7 before:w-5 before:text-center before:justify-center before:items-center before:font-semibold before:flex before:align-middle before:leading-8 text-xs"; + "relative flex items-center before:inline-block before:h-6 before:bg-brand-primary before:text-white before:rounded-l-lg before:w-1.5 before:text-center before:justify-center before:items-center before:font-semibold before:flex before:align-middle before:leading-8 text-xs"; function handleOnChange() { const newVector = { @@ -28,14 +39,67 @@ export const InputVector = ({ x, y, z, onChange }: InputVectorProps) => { }; onChange(newVector); } + + const blurAllInputs = () => { + xRef.current?.blur(); + yRef.current?.blur(); + zRef.current?.blur(); + }; + + // For dragging the input value to increment/decrement + const handleMouseDown = ( + e: React.MouseEvent, + ref: React.RefObject, + ) => { + e.preventDefault(); + blurAllInputs(); + let isDragging = false; + let previousMousePosition = e.clientX; + + const mouseMoveHandler = (e: MouseEvent) => { + isDragging = true; + const currentMousePosition = e.clientX; + const direction = currentMousePosition > previousMousePosition ? 1 : -1; + previousMousePosition = currentMousePosition; + + const currentValue = Number(ref.current?.value) || 0; + const newValue = currentValue + direction * increment; + + if (ref.current) { + ref.current.value = newValue.toFixed(1); + ref.current.blur(); + } + + onChange({ + x: Number(xRef.current?.value) || 0, + y: Number(yRef.current?.value) || 0, + z: Number(zRef.current?.value) || 0, + }); + }; + + const mouseUpHandler = () => { + document.removeEventListener("mousemove", mouseMoveHandler); + document.removeEventListener("mouseup", mouseUpHandler); + if (!isDragging) { + ref.current?.focus(); + ref.current?.select(); + } + }; + + document.addEventListener("mousemove", mouseMoveHandler); + document.addEventListener("mouseup", mouseUpHandler); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + (e.currentTarget as HTMLInputElement).blur(); // Unfocus the input field on pressing Enter + } + }; + return ( -
- +
+ +
X
{ value={x} onFocus={() => disableHotkeyInput(DomLevels.INPUT)} onBlur={() => enableHotkeyInput(DomLevels.INPUT)} + onMouseDown={(e) => handleMouseDown(e, xRef)} + onKeyDown={handleKeyDown} />
- + +
Y
{ value={y} onFocus={() => disableHotkeyInput(DomLevels.INPUT)} onBlur={() => enableHotkeyInput(DomLevels.INPUT)} + onMouseDown={(e) => handleMouseDown(e, yRef)} + onKeyDown={handleKeyDown} />
- + +
Z
{ value={z} onFocus={() => disableHotkeyInput(DomLevels.INPUT)} onBlur={() => enableHotkeyInput(DomLevels.INPUT)} + onMouseDown={(e) => handleMouseDown(e, zRef)} + onKeyDown={handleKeyDown} />
diff --git a/app/pages/PageEnigma/comps/ControlPanelSceneObject/ControlPanelSceneObject.tsx b/app/pages/PageEnigma/comps/ControlPanelSceneObject/ControlPanelSceneObject.tsx index 47d7a976d0..c9535decbb 100644 --- a/app/pages/PageEnigma/comps/ControlPanelSceneObject/ControlPanelSceneObject.tsx +++ b/app/pages/PageEnigma/comps/ControlPanelSceneObject/ControlPanelSceneObject.tsx @@ -1,7 +1,8 @@ -import { useContext, useEffect } from "react"; +import { useContext, useEffect, useState } from "react"; import { Transition } from "@headlessui/react"; import { - faArrowRightArrowLeft, + faChevronDown, + faChevronUp, faCube, faTrash, } from "@fortawesome/pro-solid-svg-icons"; @@ -22,6 +23,11 @@ import { QueueKeyframe } from "~/pages/PageEnigma/models"; export const ControlPanelSceneObject = () => { const editorEngine = useContext(EngineContext); const [appUiState, dispatchAppUiState] = useContext(AppUiContext); + const [isCollapsed, setIsCollapsed] = useState(false); + + const toggleCollapse = () => { + setIsCollapsed(!isCollapsed); + }; const position = appUiState.controlPanel.currentSceneObject?.objectVectors?.position; @@ -169,63 +175,73 @@ export const ControlPanelSceneObject = () => { show={appUiState?.controlPanel.isShowing} className={[ "absolute bottom-0 right-0", - "m-4 flex h-fit w-fit flex-col gap-2", + "m-4 flex h-fit w-56 flex-col gap-2", "rounded-lg", "border border-ui-panel-border", - "bg-ui-panel p-4 text-white", + "bg-ui-panel p-3.5 text-white", ].join(" ")} - enter="transition-opacity duration-100" + enter="transition-opacity duration-150" enterFrom="opacity-0" enterTo="opacity-100" - leave="transition-opacity duration-100" + leave="transition-opacity duration-150" leaveFrom="opacity-100" leaveTo="opacity-0"> -
+

{appUiState.controlPanel.currentSceneObject.object_name}

-
- -

Swap Object

+ +
+ + +
+
Location
+
-
- -
-
Position
- -
+
+
Rotation
+ +
-
-
Rotation
- -
+
+
Scale
+ +
+ -
-
Scale
- -
- - -
+