diff --git a/app/src/components/footer/shortcutHelper.tsx b/app/src/components/footer/shortcutHelper.tsx index afbaa0e..230dff2 100644 --- a/app/src/components/footer/shortcutHelper.tsx +++ b/app/src/components/footer/shortcutHelper.tsx @@ -55,6 +55,7 @@ interface ShortcutHelperProps { const ShortcutHelper: React.FC = ({ setShowShortcuts, }) => { + const shortcuts: ShortcutGroup[] = [ // Essential { @@ -310,6 +311,7 @@ const ShortcutHelper: React.FC = ({ > +
{shortcuts.map((group) => ( @@ -326,9 +328,8 @@ const ShortcutHelper: React.FC = ({
{activeShortcuts.map((item) => (
} - {(commentPositionState !== null || selectedComment !== null) && } + + { + (commentPositionState !== null || selectedComment !== null) && + + } ); diff --git a/app/src/components/ui/collaboration/Messages.tsx b/app/src/components/ui/collaboration/Messages.tsx index b3f37e1..11e87b2 100644 --- a/app/src/components/ui/collaboration/Messages.tsx +++ b/app/src/components/ui/collaboration/Messages.tsx @@ -231,7 +231,10 @@ const Messages: React.FC = ({ val, i, setMessages, mode, setIsEdit
{isEditableThread ? getRelativeTime(val.createdAt) : val.createdAt}
{(val as Reply).creatorId === userId && ( -
+
setOpenOptions(false)} + > + {openOptions && (
- {!(isEditableThread) && } + + {!isEditableThread && ( + + )}
)}
)} +
{"comment" in val ? val.comment : val.threadTitle}
+
)} diff --git a/app/src/components/ui/collaboration/ThreadChat.tsx b/app/src/components/ui/collaboration/ThreadChat.tsx index 8e4b24b..5370689 100644 --- a/app/src/components/ui/collaboration/ThreadChat.tsx +++ b/app/src/components/ui/collaboration/ThreadChat.tsx @@ -131,9 +131,10 @@ const ThreadChat: React.FC = () => { if (dragging) updatePosition(e, true); }; - useEffect(() => { - updatePosition({ clientX: position.x, clientY: position.y }, true); - }, [selectedComment]); + // Commented this useEffect to prevent offset after user saved the comment + // useEffect(() => { + // updatePosition({ clientX: position.x, clientY: position.y }, true); + // }, [selectedComment]); const handlePointerUp = (event: React.PointerEvent) => { @@ -144,6 +145,10 @@ const ThreadChat: React.FC = () => { }; const handleCreateComments = async (e: any) => { + // Continue send or create message only there is only value avalibale + // To prevent empty value + + if (!value) return; e.preventDefault(); try { // const createComments = await addCommentsApi(projectId, value, selectedComment?.threadId, selectedVersion?.versionId || "")/ @@ -163,6 +168,7 @@ const ThreadChat: React.FC = () => { // } + if (threadSocket && mode === "create") { const addComment = { versionId: selectedVersion?.versionId || "", @@ -190,7 +196,7 @@ const ThreadChat: React.FC = () => { // removeComment(selectedComment?.threadId) // setSelectedComment([]) // } - console.log('threadSocket:threadChat ', threadSocket); + if (threadSocket) { // projectId, userId, organization, threadId const deleteThread = { @@ -258,7 +264,7 @@ const ThreadChat: React.FC = () => { }; if (threadSocket) { - console.log('createThread: ', createThread); + setInputActive(false); threadSocket.emit("v1:thread:create", createThread); diff --git a/app/src/hooks/useCameraShortcuts.ts b/app/src/hooks/useCameraShortcuts.ts new file mode 100644 index 0000000..e4b897a --- /dev/null +++ b/app/src/hooks/useCameraShortcuts.ts @@ -0,0 +1,47 @@ +import { useEffect } from "react"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import type { CameraControls } from "@react-three/drei"; + +export const useCameraShortcuts = (controlsRef: React.RefObject) => { + const { camera } = useThree(); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (!controlsRef.current) return; + + // get current distance from camera to target + const target = new THREE.Vector3(); + controlsRef.current.getTarget(target); + + const distance = camera.position.distanceTo(target); + let pos: THREE.Vector3 | null = null; + + switch (e.key) { + case "1": // Front + pos = new THREE.Vector3(0, 0, distance).add(target); + break; + case "3": // Right + pos = new THREE.Vector3(distance, 0, 0).add(target); + break; + case "7": // Top + pos = new THREE.Vector3(0, distance, 0).add(target); + break; + case "9": // Back + pos = new THREE.Vector3(0, 0, -distance).add(target); + break; + } + + if (pos) { + controlsRef.current.setLookAt( + pos.x, pos.y, pos.z, // camera position + target.x, target.y, target.z, // keep same target + true // smooth transition + ); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [controlsRef, camera]); +}; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index ab9434b..ef310fc 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -57,6 +57,7 @@ export default function Builder() { const { setHoveredPoint, setHoveredLine } = useBuilderStore(); const { userId, organization } = getUserData(); + useEffect(() => { if (!toggleView) { setHoveredLine(null); diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index c41a4bd..d63f0ac 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -18,6 +18,7 @@ import ContextControls from "./contextControls/contextControls"; import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D"; import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls"; import UndoRedo3DControls from "./undoRedoControls/undoRedo3D/undoRedo3DControls"; +import { useCameraShortcuts } from "../../../hooks/useCameraShortcuts"; export default function Controls() { const controlsRef = useRef(null); @@ -116,6 +117,7 @@ export default function Controls() { stopInterval(); }; }, [toggleView, state, socket]); + useCameraShortcuts(controlsRef); return ( <> diff --git a/app/src/modules/visualization/zone/DisplayZone.tsx b/app/src/modules/visualization/zone/DisplayZone.tsx index 42fe4c4..b8d117a 100644 --- a/app/src/modules/visualization/zone/DisplayZone.tsx +++ b/app/src/modules/visualization/zone/DisplayZone.tsx @@ -241,21 +241,18 @@ const DisplayZone: React.FC = ({ {Object.keys(zonesData).length !== 0 ? ( <> {Object.values(zonesData).map((zone, index) => ( - <> - { } -
{ +
{ - handleSelect2dZoneData(zonesData[zone.zoneUuid]?.zoneUuid, zone.zoneName) - } - } - > - {zone.zoneName} -
- + handleSelect2dZoneData(zonesData[zone.zoneUuid]?.zoneUuid, zone.zoneName) + } + } + > + {zone.zoneName} +
))} ) : ( diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 063c87c..aa8e84e 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -516,6 +516,7 @@ width: 50px; border-radius: 100px; cursor: pointer; + &:hover { outline: 1px solid var(--accent-color); } @@ -586,6 +587,7 @@ align-items: center; justify-content: center; border-radius: 8px; + &:hover { background: var(--background-color); outline: 1px solid #aaaaaa29; @@ -600,6 +602,7 @@ .kebab-icon { display: flex; + svg { transform: rotate(90deg) scale(0.8); } @@ -1434,6 +1437,11 @@ padding: 12px; border-radius: #{$border-radius-large}; + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + background: var(--background-color); + .compare-simulations-header { font-weight: var(--font-weight-medium); } @@ -1598,12 +1606,13 @@ .animations-lists { max-height: 210px; overflow: auto; - .no-animation{ + .no-animation { padding: 6px 8px; line-height: 20px; } .animations-list-wrapper { padding: 0 4px; + .animations-list { margin: 2px 0; padding: 4px 12px; @@ -1793,7 +1802,8 @@ padding: 14px; padding-bottom: 0; margin-bottom: 8px; - .input-toggle-container{ + + .input-toggle-container { padding: 4px 0; margin-bottom: 8px; } diff --git a/app/src/styles/scene/comments.scss b/app/src/styles/scene/comments.scss index 480594a..ed4a1be 100644 --- a/app/src/styles/scene/comments.scss +++ b/app/src/styles/scene/comments.scss @@ -171,8 +171,8 @@ .messages-wrapper { padding: 12px; padding-top: 0; - max-height: 50vh; - overflow-y: auto; + max-height: 36vh; + overflow: auto; .edit-container { .input-container { textarea { diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 507e31b..6a03563 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -221,8 +221,12 @@ const KeyPressListener: React.FC = () => { // Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added handleSidebarShortcuts(keyCombination); + + // Active module selection (builder, simulation, etc.) - handleModuleSwitch(keyCombination); + if (event.location === 0) { // Location 0 = standard keyboard (not numpad) + handleModuleSwitch(keyCombination); + } // Common editing tools: cursor | delete | free-hand handlePrimaryTools(keyCombination); // Shortcuts specific to the builder module (e.g., drawing and measurement tools)