From c5f44536b78469f416bd44c40535232e4ef4f81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otgaar?= Date: Sun, 4 Jan 2026 15:18:07 +0100 Subject: [PATCH] feat: seperation of concerns for gesture value editor, adjusting output of nodes, integration testing, css file changes, and probably much more. ref: N25B-412 --- src/index.css | 13 + src/pages/VisProgPage/VisProg.module.css | 14 +- .../visualProgrammingUI/VisProgStores.tsx | 26 +- .../components/DragDropSidebar.tsx | 16 +- .../components/GestureValueEditor.module.css | 164 +++++ .../components/GestureValueEditor.tsx | 579 ++++++++++++++++++ .../components/PlanEditor.tsx | 71 +-- .../visualProgrammingUI/nodes/NormNode.tsx | 2 +- 8 files changed, 809 insertions(+), 76 deletions(-) create mode 100644 src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.module.css create mode 100644 src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.tsx diff --git a/src/index.css b/src/index.css index 6e28fe5..f4e6ffe 100644 --- a/src/index.css +++ b/src/index.css @@ -59,8 +59,21 @@ button:focus-visible { background-color: #ffffff; --accent-color: #00AAAA; + --select-color: rgba(gray); + + --dropdown-menu-background-color: rgb(247, 247, 247); + --dropdown-menu-border: rgba(207, 207, 207, 0.986); } button { background-color: #f9f9f9; } } + +@media (prefers-color-scheme: dark) { + :root { + color: #ffffff; + --select-color: rgba(gray); + --dropdown-menu-background-color: rgba(39, 39, 39, 0.986); + --dropdown-menu-border: rgba(65, 65, 65, 0.986); + } +} \ No newline at end of file diff --git a/src/pages/VisProgPage/VisProg.module.css b/src/pages/VisProgPage/VisProg.module.css index 7731e42..e15db1f 100644 --- a/src/pages/VisProgPage/VisProg.module.css +++ b/src/pages/VisProgPage/VisProg.module.css @@ -141,13 +141,13 @@ } .planDialog { - width: 80vw; - max-width: 900px; - padding: 1rem; - border: none; - border-radius: 8px; + overflow:visible; + width: 80vw; + max-width: 900px; + transition: width 0.25s ease; } + .planDialog::backdrop { background: rgba(0, 0, 0, 0.4); } @@ -160,6 +160,7 @@ } .planEditorLeft { + position: relative; display: flex; flex-direction: column; gap: 0.75rem; @@ -212,4 +213,5 @@ opacity: 0.5; font-style: italic; text-decoration: line-through; -} \ No newline at end of file +} + diff --git a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx index 1decf8e..676019a 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx @@ -40,21 +40,21 @@ function createNode(id: string, type: string, position: XYPosition, data: Record ...data, }, } - } +} -//* Initial nodes, created by using createNode. */ -const initialNodes : Node[] = [ - createNode('start', 'start', {x: 100, y: 100}, {label: "Start"}, false), - createNode('end', 'end', {x: 500, y: 100}, {label: "End"}, false), - createNode('phase-1', 'phase', {x:200, y:100}, {label: "Phase 1", children : []}), - createNode('norms-1', 'norm', {x:-200, y:100}, {label: "Initial Norms", normList: ["Be a robot", "get good"], critical:false}), -]; + //* Initial nodes, created by using createNode. */ + // Start and End don't need to apply the UUID, since they are technically never compiled into a program. + const startNode = createNode('start', 'start', {x: 100, y: 100}, {label: "Start"}, false) + const endNode = createNode('end', 'end', {x: 500, y: 100}, {label: "End"}, false) + const initialPhaseNode = createNode(crypto.randomUUID(), 'phase', {x:200, y:100}, {label: "Phase 1", children : []}) -// * Initial edges * / -const initialEdges: Edge[] = [ - { id: 'start-phase-1', source: 'start', target: 'phase-1' }, - { id: 'phase-1-end', source: 'phase-1', target: 'end' }, -]; + const initialNodes : Node[] = [startNode, endNode, initialPhaseNode,]; + + // * Initial edges * / + const initialEdges: Edge[] = [ + { id: 'start-phase-1', source: startNode.id, target: initialPhaseNode.id }, + { id: 'phase-1-end', source: initialPhaseNode.id, target: endNode.id }, + ]; /** diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/DragDropSidebar.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/DragDropSidebar.tsx index 0401da9..01e222e 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/DragDropSidebar.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/DragDropSidebar.tsx @@ -69,23 +69,11 @@ function DraggableNode({ className, children, nodeType, onDrop }: DraggableNodeP * @param position - The XY position in the flow canvas where the node will appear. */ function addNodeToFlow(nodeType: keyof typeof NodeTypes, position: XYPosition) { - const { nodes, addNode } = useFlowStore.getState(); + const { addNode } = useFlowStore.getState(); // Load any predefined data for this node type. const defaultData = NodeDefaults[nodeType] ?? {} - - // Currently, we find out what the Id is by checking the last node and adding one. - const sameTypeNodes = nodes.filter((node) => node.type === nodeType); - const nextNumber = - sameTypeNodes.length > 0 - ? (() => { - const lastNode = sameTypeNodes[sameTypeNodes.length - 1]; - const parts = lastNode.id.split('-'); - const lastNum = Number(parts[1]); - return Number.isNaN(lastNum) ? sameTypeNodes.length + 1 : lastNum + 1; - })() - : 1; - const id = `${nodeType}-${nextNumber}`; + const id = crypto.randomUUID(); // Create new node const newNode = { diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.module.css b/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.module.css new file mode 100644 index 0000000..9d0f3e6 --- /dev/null +++ b/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.module.css @@ -0,0 +1,164 @@ + +.gestureEditor { + display: flex; + flex-direction: column; + gap: 12px; + width: 100%; +} + +.modeSelector { + display: flex; + align-items: center; + gap: 12px; +} + +.modeLabel { + font-size: 14px; + font-weight: 500; + color: var(--text-secondary); + white-space: nowrap; +} + +.toggleContainer { + display: flex; + background: rgba(78, 78, 78, 0.411); + border-radius: 6px; + padding: 2px; + border: 1px solid var(--border-color); +} + +.toggleButton { + padding: 6px 12px; + background: none; + border: none; + border-radius: 4px; + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + color: var(--text-secondary); +} + +.toggleButton:hover { + background: none; +} + +.toggleButton.active { + box-shadow: 0 0 1px 0 rgba(9, 255, 0, 0.733); +} + +.valueEditor { + width: 100%; +} + +.textInput { + width: 100%; + padding: 8px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 14px; + transition: border-color 0.2s ease; +} + +.textInput:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.1); +} + +.tagSelector { + display: flex; + flex-direction: column; + gap: 8px; +} + +.tagSelect { + width: 100%; + padding: 8px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 14px; + background-color: rgba(135, 135, 135, 0.296); + cursor: pointer; +} + +.tagSelect:focus { + outline: none; + border-color: rgb(0, 149, 25); +} + +.tagList { + display: flex; + flex-wrap: wrap; + gap: 6px; + max-height: 120px; + overflow-y: auto; + padding: 4px; + border: 1px solid rgba(var(--primary-rgb), 0.1); + border-radius: 4px; + background: var(--primary-color); +} + +.tagButton { + padding: 4px 8px; + border: 1px solid gray; + border-radius: 4px; + background: var(--primary-rgb); + font-size: 12px; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.tagButton:hover { + background: gray; + border-color: gray; +} + +.tagButton.selected { + background: rgba(var(--primary-rgb), 0.5); + color: var(--primary-rgb); + border-color: rgb(27, 223, 60); +} + +.suggestionsDropdownLeft { + position: absolute; + left: -220px; + top: 120px; + + width: 200px; + max-height: 20vh; + overflow-y: auto; + + background: var(--dropdown-menu-background-color); + border-radius: 12px; + box-shadow: 0 8px 24px var(--dropdown-menu-border); +} + +.suggestionsDropdownLeft::before { + content: "Gesture Suggestions"; + display: block; + padding: 8px 12px; + font-weight: 600; + border-bottom: 1px solid var(--border-light); +} + +.suggestionItem { + padding: 8px 12px; + cursor: pointer; + transition: background-color 0.2s ease; + font-size: 14px; + border-bottom: 1px solid var(--border-light); +} + +.suggestionItem:last-child { + border-bottom: none; +} + +.suggestionItem:hover { + background-color: var(--background-hover); +} + +.suggestionItem:active { + background-color: var(--primary-color-light); +} \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.tsx new file mode 100644 index 0000000..5cb76a4 --- /dev/null +++ b/src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor.tsx @@ -0,0 +1,579 @@ +import { useState, useEffect, useRef } from "react"; +import styles from './GestureValueEditor.module.css' + +type GestureValueEditorProps = { + value: string; + setValue: (value: string) => void; + placeholder?: string; +}; + +// Define your gesture tags here +const GESTURE_TAGS = ["above", "affirmative", "afford", "agitated", "all", "allright", "alright", "any", + "assuage", "attemper", "back", "bashful", "beg", "beseech", "blank", + "body language", "bored", "bow", "but", "call", "calm", "choose", "choice", "cloud", + "cogitate", "cool", "crazy", "disappointed", "down", "earth", "empty", "embarrassed", + "enthusiastic", "entire", "estimate", "except", "exalted", "excited", "explain", "far", + "field", "floor", "forlorn", "friendly", "front", "frustrated", "gentle", "gift", + "give", "ground", "happy", "hello", "her", "here", "hey", "hi", "him", "hopeless", + "hysterical", "I", "implore", "indicate", "joyful", "me", "meditate", "modest", + "negative", "nervous", "no", "not know", "nothing", "offer", "ok", "once upon a time", + "oppose", "or", "pacify", "pick", "placate", "please", "present", "proffer", "quiet", + "reason", "refute", "reject", "rousing", "sad", "select", "shamefaced", "show", + "show sky", "sky", "soothe", "sun", "supplicate", "tablet", "tall", "them", "there", + "think", "timid", "top", "unless", "up", "upstairs", "void", "warm", "winner", "yeah", + "yes", "yoo-hoo", "you", "your", "zero", "zestful"]; + +const GESTURE_SINGLES = [ + "animations/Stand/BodyTalk/Listening/Listening_1", + "animations/Stand/BodyTalk/Listening/Listening_2", + "animations/Stand/BodyTalk/Listening/Listening_3", + "animations/Stand/BodyTalk/Listening/Listening_4", + "animations/Stand/BodyTalk/Listening/Listening_5", + "animations/Stand/BodyTalk/Listening/Listening_6", + "animations/Stand/BodyTalk/Listening/Listening_7", + "animations/Stand/BodyTalk/Speaking/BodyTalk_1", + "animations/Stand/BodyTalk/Speaking/BodyTalk_10", + "animations/Stand/BodyTalk/Speaking/BodyTalk_11", + "animations/Stand/BodyTalk/Speaking/BodyTalk_12", + "animations/Stand/BodyTalk/Speaking/BodyTalk_13", + "animations/Stand/BodyTalk/Speaking/BodyTalk_14", + "animations/Stand/BodyTalk/Speaking/BodyTalk_15", + "animations/Stand/BodyTalk/Speaking/BodyTalk_16", + "animations/Stand/BodyTalk/Speaking/BodyTalk_2", + "animations/Stand/BodyTalk/Speaking/BodyTalk_3", + "animations/Stand/BodyTalk/Speaking/BodyTalk_4", + "animations/Stand/BodyTalk/Speaking/BodyTalk_5", + "animations/Stand/BodyTalk/Speaking/BodyTalk_6", + "animations/Stand/BodyTalk/Speaking/BodyTalk_7", + "animations/Stand/BodyTalk/Speaking/BodyTalk_8", + "animations/Stand/BodyTalk/Speaking/BodyTalk_9", + "animations/Stand/BodyTalk/Thinking/Remember_1", + "animations/Stand/BodyTalk/Thinking/Remember_2", + "animations/Stand/BodyTalk/Thinking/Remember_3", + "animations/Stand/BodyTalk/Thinking/ThinkingLoop_1", + "animations/Stand/BodyTalk/Thinking/ThinkingLoop_2", + "animations/Stand/Emotions/Negative/Angry_1", + "animations/Stand/Emotions/Negative/Angry_2", + "animations/Stand/Emotions/Negative/Angry_3", + "animations/Stand/Emotions/Negative/Angry_4", + "animations/Stand/Emotions/Negative/Anxious_1", + "animations/Stand/Emotions/Negative/Bored_1", + "animations/Stand/Emotions/Negative/Bored_2", + "animations/Stand/Emotions/Negative/Disappointed_1", + "animations/Stand/Emotions/Negative/Exhausted_1", + "animations/Stand/Emotions/Negative/Exhausted_2", + "animations/Stand/Emotions/Negative/Fear_1", + "animations/Stand/Emotions/Negative/Fear_2", + "animations/Stand/Emotions/Negative/Fearful_1", + "animations/Stand/Emotions/Negative/Frustrated_1", + "animations/Stand/Emotions/Negative/Humiliated_1", + "animations/Stand/Emotions/Negative/Hurt_1", + "animations/Stand/Emotions/Negative/Hurt_2", + "animations/Stand/Emotions/Negative/Late_1", + "animations/Stand/Emotions/Negative/Sad_1", + "animations/Stand/Emotions/Negative/Sad_2", + "animations/Stand/Emotions/Negative/Shocked_1", + "animations/Stand/Emotions/Negative/Sorry_1", + "animations/Stand/Emotions/Negative/Surprise_1", + "animations/Stand/Emotions/Negative/Surprise_2", + "animations/Stand/Emotions/Negative/Surprise_3", + "animations/Stand/Emotions/Neutral/Alienated_1", + "animations/Stand/Emotions/Neutral/AskForAttention_1", + "animations/Stand/Emotions/Neutral/AskForAttention_2", + "animations/Stand/Emotions/Neutral/AskForAttention_3", + "animations/Stand/Emotions/Neutral/Cautious_1", + "animations/Stand/Emotions/Neutral/Confused_1", + "animations/Stand/Emotions/Neutral/Determined_1", + "animations/Stand/Emotions/Neutral/Embarrassed_1", + "animations/Stand/Emotions/Neutral/Hesitation_1", + "animations/Stand/Emotions/Neutral/Innocent_1", + "animations/Stand/Emotions/Neutral/Lonely_1", + "animations/Stand/Emotions/Neutral/Mischievous_1", + "animations/Stand/Emotions/Neutral/Puzzled_1", + "animations/Stand/Emotions/Neutral/Sneeze", + "animations/Stand/Emotions/Neutral/Stubborn_1", + "animations/Stand/Emotions/Neutral/Suspicious_1", + "animations/Stand/Emotions/Positive/Amused_1", + "animations/Stand/Emotions/Positive/Confident_1", + "animations/Stand/Emotions/Positive/Ecstatic_1", + "animations/Stand/Emotions/Positive/Enthusiastic_1", + "animations/Stand/Emotions/Positive/Excited_1", + "animations/Stand/Emotions/Positive/Excited_2", + "animations/Stand/Emotions/Positive/Excited_3", + "animations/Stand/Emotions/Positive/Happy_1", + "animations/Stand/Emotions/Positive/Happy_2", + "animations/Stand/Emotions/Positive/Happy_3", + "animations/Stand/Emotions/Positive/Happy_4", + "animations/Stand/Emotions/Positive/Hungry_1", + "animations/Stand/Emotions/Positive/Hysterical_1", + "animations/Stand/Emotions/Positive/Interested_1", + "animations/Stand/Emotions/Positive/Interested_2", + "animations/Stand/Emotions/Positive/Laugh_1", + "animations/Stand/Emotions/Positive/Laugh_2", + "animations/Stand/Emotions/Positive/Laugh_3", + "animations/Stand/Emotions/Positive/Mocker_1", + "animations/Stand/Emotions/Positive/Optimistic_1", + "animations/Stand/Emotions/Positive/Peaceful_1", + "animations/Stand/Emotions/Positive/Proud_1", + "animations/Stand/Emotions/Positive/Proud_2", + "animations/Stand/Emotions/Positive/Proud_3", + "animations/Stand/Emotions/Positive/Relieved_1", + "animations/Stand/Emotions/Positive/Shy_1", + "animations/Stand/Emotions/Positive/Shy_2", + "animations/Stand/Emotions/Positive/Sure_1", + "animations/Stand/Emotions/Positive/Winner_1", + "animations/Stand/Emotions/Positive/Winner_2", + "animations/Stand/Gestures/Angry_1", + "animations/Stand/Gestures/Angry_2", + "animations/Stand/Gestures/Angry_3", + "animations/Stand/Gestures/BowShort_1", + "animations/Stand/Gestures/BowShort_2", + "animations/Stand/Gestures/BowShort_3", + "animations/Stand/Gestures/But_1", + "animations/Stand/Gestures/CalmDown_1", + "animations/Stand/Gestures/CalmDown_2", + "animations/Stand/Gestures/CalmDown_3", + "animations/Stand/Gestures/CalmDown_4", + "animations/Stand/Gestures/CalmDown_5", + "animations/Stand/Gestures/CalmDown_6", + "animations/Stand/Gestures/Choice_1", + "animations/Stand/Gestures/ComeOn_1", + "animations/Stand/Gestures/Confused_1", + "animations/Stand/Gestures/Confused_2", + "animations/Stand/Gestures/CountFive_1", + "animations/Stand/Gestures/CountFour_1", + "animations/Stand/Gestures/CountMore_1", + "animations/Stand/Gestures/CountOne_1", + "animations/Stand/Gestures/CountThree_1", + "animations/Stand/Gestures/CountTwo_1", + "animations/Stand/Gestures/Desperate_1", + "animations/Stand/Gestures/Desperate_2", + "animations/Stand/Gestures/Desperate_3", + "animations/Stand/Gestures/Desperate_4", + "animations/Stand/Gestures/Desperate_5", + "animations/Stand/Gestures/DontUnderstand_1", + "animations/Stand/Gestures/Enthusiastic_3", + "animations/Stand/Gestures/Enthusiastic_4", + "animations/Stand/Gestures/Enthusiastic_5", + "animations/Stand/Gestures/Everything_1", + "animations/Stand/Gestures/Everything_2", + "animations/Stand/Gestures/Everything_3", + "animations/Stand/Gestures/Everything_4", + "animations/Stand/Gestures/Everything_6", + "animations/Stand/Gestures/Excited_1", + "animations/Stand/Gestures/Explain_1", + "animations/Stand/Gestures/Explain_10", + "animations/Stand/Gestures/Explain_11", + "animations/Stand/Gestures/Explain_2", + "animations/Stand/Gestures/Explain_3", + "animations/Stand/Gestures/Explain_4", + "animations/Stand/Gestures/Explain_5", + "animations/Stand/Gestures/Explain_6", + "animations/Stand/Gestures/Explain_7", + "animations/Stand/Gestures/Explain_8", + "animations/Stand/Gestures/Far_1", + "animations/Stand/Gestures/Far_2", + "animations/Stand/Gestures/Far_3", + "animations/Stand/Gestures/Follow_1", + "animations/Stand/Gestures/Give_1", + "animations/Stand/Gestures/Give_2", + "animations/Stand/Gestures/Give_3", + "animations/Stand/Gestures/Give_4", + "animations/Stand/Gestures/Give_5", + "animations/Stand/Gestures/Give_6", + "animations/Stand/Gestures/Great_1", + "animations/Stand/Gestures/HeSays_1", + "animations/Stand/Gestures/HeSays_2", + "animations/Stand/Gestures/HeSays_3", + "animations/Stand/Gestures/Hey_1", + "animations/Stand/Gestures/Hey_10", + "animations/Stand/Gestures/Hey_2", + "animations/Stand/Gestures/Hey_3", + "animations/Stand/Gestures/Hey_4", + "animations/Stand/Gestures/Hey_6", + "animations/Stand/Gestures/Hey_7", + "animations/Stand/Gestures/Hey_8", + "animations/Stand/Gestures/Hey_9", + "animations/Stand/Gestures/Hide_1", + "animations/Stand/Gestures/Hot_1", + "animations/Stand/Gestures/Hot_2", + "animations/Stand/Gestures/IDontKnow_1", + "animations/Stand/Gestures/IDontKnow_2", + "animations/Stand/Gestures/IDontKnow_3", + "animations/Stand/Gestures/IDontKnow_4", + "animations/Stand/Gestures/IDontKnow_5", + "animations/Stand/Gestures/IDontKnow_6", + "animations/Stand/Gestures/Joy_1", + "animations/Stand/Gestures/Kisses_1", + "animations/Stand/Gestures/Look_1", + "animations/Stand/Gestures/Look_2", + "animations/Stand/Gestures/Maybe_1", + "animations/Stand/Gestures/Me_1", + "animations/Stand/Gestures/Me_2", + "animations/Stand/Gestures/Me_4", + "animations/Stand/Gestures/Me_7", + "animations/Stand/Gestures/Me_8", + "animations/Stand/Gestures/Mime_1", + "animations/Stand/Gestures/Mime_2", + "animations/Stand/Gestures/Next_1", + "animations/Stand/Gestures/No_1", + "animations/Stand/Gestures/No_2", + "animations/Stand/Gestures/No_3", + "animations/Stand/Gestures/No_4", + "animations/Stand/Gestures/No_5", + "animations/Stand/Gestures/No_6", + "animations/Stand/Gestures/No_7", + "animations/Stand/Gestures/No_8", + "animations/Stand/Gestures/No_9", + "animations/Stand/Gestures/Nothing_1", + "animations/Stand/Gestures/Nothing_2", + "animations/Stand/Gestures/OnTheEvening_1", + "animations/Stand/Gestures/OnTheEvening_2", + "animations/Stand/Gestures/OnTheEvening_3", + "animations/Stand/Gestures/OnTheEvening_4", + "animations/Stand/Gestures/OnTheEvening_5", + "animations/Stand/Gestures/Please_1", + "animations/Stand/Gestures/Please_2", + "animations/Stand/Gestures/Please_3", + "animations/Stand/Gestures/Reject_1", + "animations/Stand/Gestures/Reject_2", + "animations/Stand/Gestures/Reject_3", + "animations/Stand/Gestures/Reject_4", + "animations/Stand/Gestures/Reject_5", + "animations/Stand/Gestures/Reject_6", + "animations/Stand/Gestures/Salute_1", + "animations/Stand/Gestures/Salute_2", + "animations/Stand/Gestures/Salute_3", + "animations/Stand/Gestures/ShowFloor_1", + "animations/Stand/Gestures/ShowFloor_2", + "animations/Stand/Gestures/ShowFloor_3", + "animations/Stand/Gestures/ShowFloor_4", + "animations/Stand/Gestures/ShowFloor_5", + "animations/Stand/Gestures/ShowSky_1", + "animations/Stand/Gestures/ShowSky_10", + "animations/Stand/Gestures/ShowSky_11", + "animations/Stand/Gestures/ShowSky_12", + "animations/Stand/Gestures/ShowSky_2", + "animations/Stand/Gestures/ShowSky_3", + "animations/Stand/Gestures/ShowSky_4", + "animations/Stand/Gestures/ShowSky_5", + "animations/Stand/Gestures/ShowSky_6", + "animations/Stand/Gestures/ShowSky_7", + "animations/Stand/Gestures/ShowSky_8", + "animations/Stand/Gestures/ShowSky_9", + "animations/Stand/Gestures/ShowTablet_1", + "animations/Stand/Gestures/ShowTablet_2", + "animations/Stand/Gestures/ShowTablet_3", + "animations/Stand/Gestures/Shy_1", + "animations/Stand/Gestures/Stretch_1", + "animations/Stand/Gestures/Stretch_2", + "animations/Stand/Gestures/Surprised_1", + "animations/Stand/Gestures/TakePlace_1", + "animations/Stand/Gestures/TakePlace_2", + "animations/Stand/Gestures/Take_1", + "animations/Stand/Gestures/Thinking_1", + "animations/Stand/Gestures/Thinking_2", + "animations/Stand/Gestures/Thinking_3", + "animations/Stand/Gestures/Thinking_4", + "animations/Stand/Gestures/Thinking_5", + "animations/Stand/Gestures/Thinking_6", + "animations/Stand/Gestures/Thinking_7", + "animations/Stand/Gestures/Thinking_8", + "animations/Stand/Gestures/This_1", + "animations/Stand/Gestures/This_10", + "animations/Stand/Gestures/This_11", + "animations/Stand/Gestures/This_12", + "animations/Stand/Gestures/This_13", + "animations/Stand/Gestures/This_14", + "animations/Stand/Gestures/This_15", + "animations/Stand/Gestures/This_2", + "animations/Stand/Gestures/This_3", + "animations/Stand/Gestures/This_4", + "animations/Stand/Gestures/This_5", + "animations/Stand/Gestures/This_6", + "animations/Stand/Gestures/This_7", + "animations/Stand/Gestures/This_8", + "animations/Stand/Gestures/This_9", + "animations/Stand/Gestures/WhatSThis_1", + "animations/Stand/Gestures/WhatSThis_10", + "animations/Stand/Gestures/WhatSThis_11", + "animations/Stand/Gestures/WhatSThis_12", + "animations/Stand/Gestures/WhatSThis_13", + "animations/Stand/Gestures/WhatSThis_14", + "animations/Stand/Gestures/WhatSThis_15", + "animations/Stand/Gestures/WhatSThis_16", + "animations/Stand/Gestures/WhatSThis_2", + "animations/Stand/Gestures/WhatSThis_3", + "animations/Stand/Gestures/WhatSThis_4", + "animations/Stand/Gestures/WhatSThis_5", + "animations/Stand/Gestures/WhatSThis_6", + "animations/Stand/Gestures/WhatSThis_7", + "animations/Stand/Gestures/WhatSThis_8", + "animations/Stand/Gestures/WhatSThis_9", + "animations/Stand/Gestures/Whisper_1", + "animations/Stand/Gestures/Wings_1", + "animations/Stand/Gestures/Wings_2", + "animations/Stand/Gestures/Wings_3", + "animations/Stand/Gestures/Wings_4", + "animations/Stand/Gestures/Wings_5", + "animations/Stand/Gestures/Yes_1", + "animations/Stand/Gestures/Yes_2", + "animations/Stand/Gestures/Yes_3", + "animations/Stand/Gestures/YouKnowWhat_1", + "animations/Stand/Gestures/YouKnowWhat_2", + "animations/Stand/Gestures/YouKnowWhat_3", + "animations/Stand/Gestures/YouKnowWhat_4", + "animations/Stand/Gestures/YouKnowWhat_5", + "animations/Stand/Gestures/YouKnowWhat_6", + "animations/Stand/Gestures/You_1", + "animations/Stand/Gestures/You_2", + "animations/Stand/Gestures/You_3", + "animations/Stand/Gestures/You_4", + "animations/Stand/Gestures/You_5", + "animations/Stand/Gestures/Yum_1", + "animations/Stand/Reactions/EthernetOff_1", + "animations/Stand/Reactions/EthernetOn_1", + "animations/Stand/Reactions/Heat_1", + "animations/Stand/Reactions/Heat_2", + "animations/Stand/Reactions/LightShine_1", + "animations/Stand/Reactions/LightShine_2", + "animations/Stand/Reactions/LightShine_3", + "animations/Stand/Reactions/LightShine_4", + "animations/Stand/Reactions/SeeColor_1", + "animations/Stand/Reactions/SeeColor_2", + "animations/Stand/Reactions/SeeColor_3", + "animations/Stand/Reactions/SeeSomething_1", + "animations/Stand/Reactions/SeeSomething_3", + "animations/Stand/Reactions/SeeSomething_4", + "animations/Stand/Reactions/SeeSomething_5", + "animations/Stand/Reactions/SeeSomething_6", + "animations/Stand/Reactions/SeeSomething_7", + "animations/Stand/Reactions/SeeSomething_8", + "animations/Stand/Reactions/ShakeBody_1", + "animations/Stand/Reactions/ShakeBody_2", + "animations/Stand/Reactions/ShakeBody_3", + "animations/Stand/Reactions/TouchHead_1", + "animations/Stand/Reactions/TouchHead_2", + "animations/Stand/Reactions/TouchHead_3", + "animations/Stand/Reactions/TouchHead_4", + "animations/Stand/Waiting/AirGuitar_1", + "animations/Stand/Waiting/BackRubs_1", + "animations/Stand/Waiting/Bandmaster_1", + "animations/Stand/Waiting/Binoculars_1", + "animations/Stand/Waiting/BreathLoop_1", + "animations/Stand/Waiting/BreathLoop_2", + "animations/Stand/Waiting/BreathLoop_3", + "animations/Stand/Waiting/CallSomeone_1", + "animations/Stand/Waiting/Drink_1", + "animations/Stand/Waiting/DriveCar_1", + "animations/Stand/Waiting/Fitness_1", + "animations/Stand/Waiting/Fitness_2", + "animations/Stand/Waiting/Fitness_3", + "animations/Stand/Waiting/FunnyDancer_1", + "animations/Stand/Waiting/HappyBirthday_1", + "animations/Stand/Waiting/Helicopter_1", + "animations/Stand/Waiting/HideEyes_1", + "animations/Stand/Waiting/HideHands_1", + "animations/Stand/Waiting/Innocent_1", + "animations/Stand/Waiting/Knight_1", + "animations/Stand/Waiting/KnockEye_1", + "animations/Stand/Waiting/KungFu_1", + "animations/Stand/Waiting/LookHand_1", + "animations/Stand/Waiting/LookHand_2", + "animations/Stand/Waiting/LoveYou_1", + "animations/Stand/Waiting/Monster_1", + "animations/Stand/Waiting/MysticalPower_1", + "animations/Stand/Waiting/PlayHands_1", + "animations/Stand/Waiting/PlayHands_2", + "animations/Stand/Waiting/PlayHands_3", + "animations/Stand/Waiting/Relaxation_1", + "animations/Stand/Waiting/Relaxation_2", + "animations/Stand/Waiting/Relaxation_3", + "animations/Stand/Waiting/Relaxation_4", + "animations/Stand/Waiting/Rest_1", + "animations/Stand/Waiting/Robot_1", + "animations/Stand/Waiting/ScratchBack_1", + "animations/Stand/Waiting/ScratchBottom_1", + "animations/Stand/Waiting/ScratchEye_1", + "animations/Stand/Waiting/ScratchHand_1", + "animations/Stand/Waiting/ScratchHead_1", + "animations/Stand/Waiting/ScratchLeg_1", + "animations/Stand/Waiting/ScratchTorso_1", + "animations/Stand/Waiting/ShowMuscles_1", + "animations/Stand/Waiting/ShowMuscles_2", + "animations/Stand/Waiting/ShowMuscles_3", + "animations/Stand/Waiting/ShowMuscles_4", + "animations/Stand/Waiting/ShowMuscles_5", + "animations/Stand/Waiting/ShowSky_1", + "animations/Stand/Waiting/ShowSky_2", + "animations/Stand/Waiting/SpaceShuttle_1", + "animations/Stand/Waiting/Stretch_1", + "animations/Stand/Waiting/Stretch_2", + "animations/Stand/Waiting/TakePicture_1", + "animations/Stand/Waiting/Taxi_1", + "animations/Stand/Waiting/Think_1", + "animations/Stand/Waiting/Think_2", + "animations/Stand/Waiting/Think_3", + "animations/Stand/Waiting/Think_4", + "animations/Stand/Waiting/Waddle_1", + "animations/Stand/Waiting/Waddle_2", + "animations/Stand/Waiting/WakeUp_1", + "animations/Stand/Waiting/Zombie_1"] + + +export default function GestureValueEditor({ + value, + setValue, + placeholder = "Gesture name", +}: GestureValueEditorProps) { + const [mode, setMode] = useState<"single" | "tag">("tag"); + const [customValue, setCustomValue] = useState(""); + const [showSuggestions, setShowSuggestions] = useState(true); + const [filteredSuggestions, setFilteredSuggestions] = useState([]); + const containerRef = useRef(null); + + const handleModeChange = (newMode: "single" | "tag") => { + setMode(newMode); + if (newMode === "single") { + // When switching to single, use custom value or existing value + setValue(customValue || value); + setFilteredSuggestions(GESTURE_SINGLES); + setShowSuggestions(true); + } else { + // When switching to tag, clear value if not a valid tag + const isCurrentValueTag = GESTURE_TAGS.some(tag => + tag.toLowerCase() === value.toLowerCase() + ); + if (!isCurrentValueTag) { + setValue(""); + } + setShowSuggestions(false); + } + }; + + const handleTagSelect = (tag: string) => { + setValue(tag); + }; + + const handleCustomChange = (newValue: string) => { + setCustomValue(newValue); + setValue(newValue); + + // Filter suggestions based on input + if (newValue.trim() === "") { + setShowSuggestions(true) + setFilteredSuggestions(GESTURE_SINGLES); + } else { + const filtered = GESTURE_SINGLES.filter(single => + single.toLowerCase().includes(newValue.toLowerCase()) + ); + setFilteredSuggestions(filtered); + setShowSuggestions(filtered.length > 0); + } + }; + + const handleSuggestionSelect = (suggestion: string) => { + setCustomValue(suggestion); + setValue(suggestion); + setShowSuggestions(false); + }; + + const handleInputFocus = () => { + if (customValue.trim() !== "") { + const filtered = GESTURE_SINGLES.filter(tag => + tag.toLowerCase().includes(customValue.toLowerCase()) + ); + setFilteredSuggestions(filtered); + setShowSuggestions(filtered.length > 0); + } + }; + + const handleInputBlur = (_e: React.FocusEvent) => { + // Delay hiding suggestions to allow clicking on them + + }; + + return ( +
+ {/* Mode selector */} +
+ +
+ + +
+
+ + {/* Value editor based on mode */} +
+ {mode === "single" ? ( +
+ {showSuggestions && ( +
+ {filteredSuggestions.map((suggestion) => ( +
handleSuggestionSelect(suggestion)} + onMouseDown={(e) => e.preventDefault()} + > + {suggestion} +
+ ))} +
+ )} + handleCustomChange(e.target.value)} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + placeholder={placeholder} + className={`${styles.textInput} ${showSuggestions ? styles.textInputWithSuggestions : ''}`} + autoComplete="off" + /> +
+ ) : ( +
+ +
+ {GESTURE_TAGS.map((tag) => ( + + ))} +
+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx index af05310..7092a95 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx @@ -3,6 +3,7 @@ import styles from '../../VisProg.module.css'; import { GetActionValue, type Action, type ActionTypes, type Plan } from "../components/Plan"; import { defaultPlan } from "../components/Plan.default"; import { TextField } from "../../../../components/TextField"; +import GestureValueEditor from "./GestureValueEditor"; // Add this import type PlanEditorDialogProps = { plan?: Plan; @@ -10,25 +11,6 @@ type PlanEditorDialogProps = { description? : string; }; -/** - * Adds an element to a React.JSX.Element that allows for the creation and editing of plans. - * Renders a dialog in the current screen with buttons and text fields for names, actions and other configurability. - * @param param0: Takes in a current plan, which can be undefined and a function which is called on saving with the potential plan. - * @returns: JSX.Element - * @example - * ``` - * // Within a Node's default JSX Element function - * { - * updateNodeData(props.id, { - * ...data, - * plan, - * }); - * }} - * /> - * ``` - */ export default function PlanEditorDialog({ plan, onSave, @@ -53,8 +35,6 @@ export default function PlanEditorDialog({ dialogRef.current?.showModal(); } - - const openEdit = () => { if (!plan) return; setDraftPlan(structuredClone(plan)); @@ -93,9 +73,9 @@ export default function PlanEditorDialog({ {/* Start of dialog (plan editor) */} e.preventDefault()} + ref={dialogRef} + className={`${styles.planDialog}`} + onWheel={(e) => e.stopPropagation()} >

{draftPlan?.id === plan?.id ? "Edit Plan" : "Create Plan"}

@@ -124,26 +104,34 @@ export default function PlanEditorDialog({ {/* Type selection */} - {/* Action value editor */} - + {/* Action value editor - UPDATED SECTION */} + {newActionType === "gesture" ? ( + + ) : ( + + )} {/* Adding steps */}
); -} +} \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx index ef65215..fb7a251 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx @@ -102,7 +102,7 @@ export function NormReduce(node: Node, nodes: Node[]) { const conditionNode = nodes.find((node) => node.id === data.condition); // In case something went wrong, and our condition doesn't actually exist; if (conditionNode == undefined) return result; - result["belief"] = reducer(conditionNode, nodes) + result["condition"] = reducer(conditionNode, nodes) } return result