diff --git a/src/_colors.scss b/src/_colors.scss index 741f7dba56a94c26e076b856600916c867b250dd..9d378ae4ed958d97f5a693b9dced32566c646888 100644 --- a/src/_colors.scss +++ b/src/_colors.scss @@ -23,6 +23,9 @@ $editor-shadow-outer: #ADBCD5; $editor-grayblue: #7789A6; $editor-blue: #00B3E9; $node-active: #E1F4FA; +$editor-red: #E63312; + +$editor-node-ghost: #D6E2F0; [color-scheme="light"] { --background: #{$editor-light}; @@ -37,6 +40,7 @@ $node-active: #E1F4FA; --button-blue: #{$editor-lightblue}; --node: #{$inria-light}; --node-active: #{$node-active}; + --node-ghost: #{$editor-node-ghost}; } // Dark theme not implemented yet @@ -52,4 +56,5 @@ $node-active: #E1F4FA; --editor-grayblue: #{$editor-grayblue}; --editor-blue: #{$editor-blue}; --editor-blue-shadow: rgba(0, 179, 233, 0.3); + --editor-red: #{$editor-red}; } \ No newline at end of file diff --git a/src/features/ePocFlow/ePocFlow.vue b/src/features/ePocFlow/ePocFlow.vue index b8c4ce5efa310ae7f1947295328a9b45b7de34d7..e591c37772ea82a81cb84c73ac94e910258b6211 100644 --- a/src/features/ePocFlow/ePocFlow.vue +++ b/src/features/ePocFlow/ePocFlow.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { VueFlow, useVueFlow, Panel, PanelPosition, MarkerType } from '@vue-flow/core'; +import { VueFlow, useVueFlow, Panel, PanelPosition, MarkerType, ConnectionMode } from '@vue-flow/core'; import { markRaw, nextTick, watch } from 'vue'; import ScreenNode from './nodes/ScreenNode.vue'; import CustomConnectContent from './edges/CustomConnectContent.vue'; @@ -198,7 +198,10 @@ function openForm(id: string, form: Form) { :max-zoom="1.5" :min-zoom=".7" :node-extent="[[0, 0], [1300, 1300]]" + :translate-extent="[[-500, -500], [1800, 1800]]" :node-types="nodeTypes" + :connection-mode="ConnectionMode.Strict" + :edge-updater-radius="30" @drop="onDrop" @dragover.prevent @dragenter.prevent diff --git a/src/features/ePocFlow/nodes/ScreenNode.vue b/src/features/ePocFlow/nodes/ScreenNode.vue index 1010d540f1556eaf76cb76459e7854f220d1c402..e2f598fa7bea6ba69621792a81ae0ef686060550 100644 --- a/src/features/ePocFlow/nodes/ScreenNode.vue +++ b/src/features/ePocFlow/nodes/ScreenNode.vue @@ -61,7 +61,7 @@ function dragEnter(event) { const { nodes } = useVueFlow(); function openForm(element: NodeElement) { - editorStore.openFormPanel(element.id, element.form); + editorStore.openFormPanel(element.id, element.form, element.parentId); } diff --git a/src/features/forms/components/FormButton.vue b/src/features/forms/components/FormButton.vue index 90eded577b344bfb5eb907e79e31d8176ff45191..389255485f67aa661fd6b963dcbd467975e511b2 100644 --- a/src/features/forms/components/FormButton.vue +++ b/src/features/forms/components/FormButton.vue @@ -12,8 +12,15 @@ const emit = defineEmits<{ </script> <template> - <button class="btn btn-form" @click="emit('click')"> + <button class="btn btn-form" :class="{ 'btn-delete' : label === 'Supprimer' }" @click="emit('click')"> <i :class="icon"></i> {{ label }} </button> -</template> \ No newline at end of file +</template> + +<style scoped lang="scss"> +.btn-delete:hover { + transition: color .2s ease-in-out; + color: var(--editor-red); +} +</style> \ No newline at end of file diff --git a/src/features/forms/components/inputs/card/CardGroup.vue b/src/features/forms/components/inputs/card/CardGroup.vue index 54f15368e1b4f913e89fcbdcdde3b1999ecad9c6..52defc6f75f156629b9e22a9f180fc1489dd2006 100644 --- a/src/features/forms/components/inputs/card/CardGroup.vue +++ b/src/features/forms/components/inputs/card/CardGroup.vue @@ -3,6 +3,7 @@ import { Card } from '@/src/shared/interfaces'; import AddCard from './AddCard.vue'; import CardInput from './CardInput.vue'; import draggable from 'vuedraggable'; +import { ref } from 'vue'; defineProps<{ type: string; @@ -19,34 +20,61 @@ const emit = defineEmits<{ (e: 'swapCard', event): void; }>(); +const drag = ref(false); + +const dragOptions = ref({ + animation: 200, + group: 'cards', + disabled: false, + ghostClass: 'ghost', +}); </script> <template> <h3 v-if="fieldName" class="field-title"><span v-if="fieldIndex" class="field-index">{{ fieldIndex }}. </span>{{ fieldName }}</h3> <hr v-if="fieldName" class="separator"> - <draggable - :model-value="cards" - item-key="index" - handle=".card-header" - ghost-class="ghost" - @change="emit('swapCard', $event)" - > - <template #item="{element, index}"> - <CardInput - :pos="index + 1" - :card="element" - :is-last="index === cards.length - 1" - @input="element.value = $event" - @delete-card="emit('deleteCard', index)" - @move-up-card="emit('moveUpCard', index)" - @move-down-card="emit('moveDownCard', index)" - /> - </template> - </draggable> + <transition-group> + <draggable + key="draggable" + :model-value="cards" + item-key="index" + handle=".card-header" + ghost-class="ghost" + v-bind="dragOptions" + @change="emit('swapCard', $event)" + @start="drag = true" + @end="drag = false" + > + <template #item="{element, index}"> + <CardInput + :key="index" + class="list-group-item" + :pos="index + 1" + :card="element" + :is-last="index === cards.length - 1" + @input="element.value = $event" + @delete-card="emit('deleteCard', index)" + @move-up-card="emit('moveUpCard', index)" + @move-down-card="emit('moveDownCard', index)" + /> + </template> + </draggable> + </transition-group> <AddCard :placeholder="'Ajouter'" class="add-card" @click="emit('addCard')" /> -</template> \ No newline at end of file +</template> + +<style lang="scss"> + +.flip-list-move { + transition: transform 0.5s; +} +.no-move { + transition: transform 0s; +} + +</style> \ No newline at end of file diff --git a/src/features/forms/components/inputs/card/CardInput.vue b/src/features/forms/components/inputs/card/CardInput.vue index c180b60a695933b98f6a9802a3bbe84a85e60f91..c00490e089b806239ec33c64b166f05de49c132c 100644 --- a/src/features/forms/components/inputs/card/CardInput.vue +++ b/src/features/forms/components/inputs/card/CardInput.vue @@ -28,7 +28,7 @@ const emit = defineEmits<{ <div class="card-header"> <h3>{{ card.label }} {{ pos }}</h3> <div class="card-header-icon"> - <i class="icon-supprimer" @click="emit('deleteCard')"></i> + <i class="icon-supprimer delete" @click="emit('deleteCard')"></i> <hr v-if="!(isLast && pos === 1)" class="vertical-separator"> <i v-if="!isLast" class="icon-bas" @click="emit('moveDownCard')"></i> <i v-if="pos !== 1" class="icon-haut" @click="emit('moveUpCard')"></i> @@ -90,6 +90,10 @@ const emit = defineEmits<{ &:not(:last-child) { margin-right: .5rem; } + + &.delete:hover { + color: var(--editor-red); + } } } } diff --git a/src/features/sideBar/components/SideActionButtonV0.vue b/src/features/sideBar/components/SideActionButtonV0.vue index e1d12f17629c90576ed894021857fb15ee52ed0a..83ef18e5f0150ff435dcdd5ddbbf1618f8fa2eae 100644 --- a/src/features/sideBar/components/SideActionButtonV0.vue +++ b/src/features/sideBar/components/SideActionButtonV0.vue @@ -15,6 +15,7 @@ function dragStart(event, sideAction) { event.dataTransfer.dropEffect= 'move'; event.dataTransfer.effectAllowed= 'move'; event.dataTransfer.setData('sideAction', JSON.stringify(sideAction)); + dragging.value = true; } </script> @@ -37,6 +38,7 @@ function dragStart(event, sideAction) { .dragging { transition: opacity .1s ease-in-out; opacity: .5; + box-shadow: none; } .question { diff --git a/src/features/topBar/TopActionButton.vue b/src/features/topBar/TopActionButton.vue index 47562c3a943afb93255328fb977ea70697aa465c..ea32ae33112e585a5d31dfed37cafa72a8ea41c8 100644 --- a/src/features/topBar/TopActionButton.vue +++ b/src/features/topBar/TopActionButton.vue @@ -18,35 +18,6 @@ defineProps<{ </template> <style scoped lang="scss"> -.btn-top-bar { - padding: .7rem 1rem; - margin-right: 1rem; - background-color: var(--button-blue); - border-radius: 8px; - border: 1px solid var(--border); - transition: box-shadow .2s ease-in-out; - i { - margin: auto; - font-size: 1rem; - } - .text-top-bar { - margin-left: .5rem; - } - .icon-chevron { - font-size: .5rem; - } - .zoom-span { - margin-right: .5rem; - margin-left: 0; - } - &:hover { - background-color: var(--content); - box-shadow: 0 1px 8px 0 var(--shadow); - } - &:active { - opacity: .7; - } -} .btn-squared { padding: .7rem; } diff --git a/src/features/topBar/TopBar.vue b/src/features/topBar/TopBar.vue index dc8eea1db22ed72c8b1d8258aa6070ea0eb138dc..d3b4009434c1ff7ca93c452fc432a8a98c8ab4dc 100644 --- a/src/features/topBar/TopBar.vue +++ b/src/features/topBar/TopBar.vue @@ -60,5 +60,17 @@ import TopActionButton from './TopActionButton.vue'; small { color: var(--text-secondary); } + + &-select { + outline: none; + padding-left: .2rem; + appearance: none; + width: 5rem; + + background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgd2lkdGg9IjExcHgiIGhlaWdodD0iN3B4IiB2aWV3Qm94PSIwIDAgMTEuMCA3LjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxjbGlwUGF0aCBpZD0iaTAiPjxwYXRoIGQ9Ik0yNDE4LDAgTDI0MTgsMjQyNiBMMCwyNDI2IEwwLDAgTDI0MTgsMCBaIj48L3BhdGg+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9ImkxIj48cGF0aCBkPSJNOS4yMDE3MjIyNywwIEM5LjYxNjUwNDA2LDAgOS45OTA4OTcyMSwwLjI3MzU1MDk4NyAxMC4xNDk4ODU5LDAuNjk0MzM1OTM3IEMxMC4zMDg4NzQ2LDEuMTE1MTIwODkgMTAuMjQ5ODk0OSwxLjU5OTYwOTM3IDkuOTU0OTk2NjMsMS45MTk1MzE0NiBMNS44ODA5MDQ1NSw2LjQxOTUzMTQ2IEM1LjY1MzMxOTM0LDYuNjQxMDE1NDEgNS4zOTA0NzQ3Niw2Ljc1IDUuMTI3NjMwMTksNi43NSBDNC44NjQ3ODU2Miw2Ljc1IDQuNjAyNTgxNzgsNi42NDAxMzY3MiA0LjQwMjI0Mjg2LDYuNDIwNDEwMTYgTDAuMzI4MTUwMjkxLDEuOTIwNDEwMTYgQzAuMDA2MTQ2NTU1MTksMS41OTk2MDkzNyAtMC4wODE2OTQ5MjIzLDEuMTE0NDUzMDIgMC4wNzcxMDE1NTQ3LDAuNjk2MDkzODU3IEMwLjIzNTg5ODAzMiwwLjI3NzczNDY5NyAwLjYxMDIyNzEwNiwwIDEuMDI0Njg4NTMsMCBMOS4yMDE3MjIyNywwIFoiPjwvcGF0aD48L2NsaXBQYXRoPjwvZGVmcz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTMwNC4wIC0xMDYyLjApIj48ZyBjbGlwLXBhdGg9InVybCgjaTApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg5ODAuMCA5MC4wKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAuMCA3MjkuMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMCA1MS4wKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTUuMCAxNTAuMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMCAyNC4wKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjg5LjM3MjM2OTgwNjgwMSAxOC4wKSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2kxKSI+PHBvbHlnb24gcG9pbnRzPSItMS4xMTAyMjMwMmUtMTYsMCAxMC4yMzYwMTA0LDAgMTAuMjM2MDEwNCw2Ljc1IC0xLjExMDIyMzAyZS0xNiw2Ljc1IC0xLjExMDIyMzAyZS0xNiwwIiBzdHJva2U9Im5vbmUiIGZpbGw9IiMzNTQyNTgiPjwvcG9seWdvbj48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4="); + background-repeat: no-repeat; + background-position: right 0.7rem top 50%; + background-size: .8rem auto; + } } </style> \ No newline at end of file diff --git a/src/global.scss b/src/global.scss index 65129ff76519c90c5fde6ed1ff159a0d656b54b1..05bfcc67c1b7d8e19332df8e1d6bc4c30a5c6bfe 100644 --- a/src/global.scss +++ b/src/global.scss @@ -90,7 +90,7 @@ body, &:hover { box-shadow: 0 2px 5px 0 var(--shadow-outer); } - &:active, &.active { + &.active { color: var(--editor-blue); border: 1px solid var(--editor-blue); box-shadow: 0 1px 8px 0 var(--editor-blue-shadow); @@ -322,4 +322,46 @@ textarea { // &.connected { // background: var(--text); // } -// } \ No newline at end of file +// } + +.btn-top-bar { + padding: .7rem 1rem; + margin-right: 1rem; + background-color: var(--button-blue); + border-radius: 8px; + border: 1px solid var(--border); + transition: box-shadow .2s ease-in-out; + i { + margin: auto; + font-size: 1rem; + } + .text-top-bar { + margin-left: .5rem; + } + .icon-chevron { + font-size: .5rem; + } + .zoom-span { + margin-right: .5rem; + margin-left: 0; + } + &:hover { + background-color: var(--content); + box-shadow: 0 1px 8px 0 var(--shadow); + } + &:active { + opacity: .7; + } +} + +.node-ghost { + * { + opacity: 0; + } + background-color: var(--node-ghost); + + background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgd2lkdGg9IjE2cHgiIGhlaWdodD0iMTZweCIgdmlld0JveD0iMCAwIDE2LjAgMTYuMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PGNsaXBQYXRoIGlkPSJpMCI+PHBhdGggZD0iTTUyMDAsMCBMNTIwMCwxODU2IEwwLDE4NTYgTDAsMCBMNTIwMCwwIFoiPjwvcGF0aD48L2NsaXBQYXRoPjxjbGlwUGF0aCBpZD0iaTEiPjxwYXRoIGQ9Ik03LjMxMjUsMCBDNy42MjM0MjE2NywwIDcuODc1LDAuMjUxMzY2OTczIDcuODc1LDAuNTYyMTQ4MDk0IEw3Ljg3NSw2Ljc0OTY0ODA5IEwxNC4wNjI1LDYuNzQ5NjQ4MDkgQzE0LjM3MTg3NDYsNi43NDk2NDgwOSAxNC42MjUsNy4wMDI3NzI5OSAxNC42MjUsNy4zMTIxNDgwOSBDMTQuNjI1LDcuNjIxNTIyNjcgMTQuMzcxODc0Niw3Ljg3NDY0ODA5IDE0LjA2MjUsNy44NzQ2NDgwOSBMNy44NzUsNy44NzQ2NDgwOSBMNy44NzUsMTQuMDYyMTQ4MSBDNy44NzUsMTQuMzczMDY5OCA3LjYyMzQyMTY3LDE0LjYyNSA3LjMxMjUsMTQuNjI1IEM3LjAwMTU3ODMzLDE0LjYyNSA2Ljc1LDE0LjM3MTUyMjcgNi43NSwxNC4wNjIxNDgxIEw2Ljc1LDcuODc0NjQ4MDkgTDAuNTYyNSw3Ljg3NDY0ODA5IEMwLjI1MTU3ODMzMSw3Ljg3NDY0ODA5IDAsNy42MjMyODExMiAwLDcuMzEyNSBDMCw3LjAwMjc3Mjk5IDAuMjUxNzE4ODc5LDYuNzQ5NjQ4MDkgMC41NjI1LDYuNzQ5NjQ4MDkgTDYuNzUsNi43NDk2NDgwOSBMNi43NSwwLjU2MjE0ODA5NCBDNi43NSwwLjI1MTIyNjQyNSA3LjAwMTU3ODMzLDAgNy4zMTI1LDAgWiI+PC9wYXRoPjwvY2xpcFBhdGg+PC9kZWZzPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNjEyLjAgLTEzMzguMCkiPjxnIGNsaXAtcGF0aD0idXJsKCNpMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDk3OS4wIDExMDMuMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU2MS4wIDc2LjApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzNS4wIDAuMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMCAyMi4wKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAuMCA3NS4wKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNC42ODc1IDUuMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMCA0NC45Mzc4NTE5MDU4MjI5OCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEzLjAgMTMuMCkiPjxnIGNsaXAtcGF0aD0idXJsKCNpMSkiPjxwb2x5Z29uIHBvaW50cz0iMCwwIDE0LjYyNSwwIDE0LjYyNSwxNC42MjUgMCwxNC42MjUgMCwwIiBzdHJva2U9Im5vbmUiIGZpbGw9IiM4Q0ExQ0EiPjwvcG9seWdvbj48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPg=="); + background-repeat: no-repeat; + background-position: right 50% top 50%; + background-size: 1.5rem auto; +} \ No newline at end of file diff --git a/src/shared/data/form.data.ts b/src/shared/data/form.data.ts index 288111437948d2e871b92b83eb544152840bc1b6..ec595e5892f589166204ff733dd6fd73374d0682 100644 --- a/src/shared/data/form.data.ts +++ b/src/shared/data/form.data.ts @@ -206,11 +206,6 @@ const epocForm: Form = { ], buttons: [ - { - label: 'Supprimer', - icon: 'icon-supprimer', - action: 'delete' - }, { label: 'Copier le lien', icon: 'icon-copie', diff --git a/src/shared/stores/editorStore.ts b/src/shared/stores/editorStore.ts index 2a4fdbc30bdba6d2996e7211039f046a262017e3..43d39c4ed17fab1aff55b84fd8f9d64c7279ca90 100644 --- a/src/shared/stores/editorStore.ts +++ b/src/shared/stores/editorStore.ts @@ -2,9 +2,12 @@ import { defineStore } from 'pinia'; import { fetchRecentProjects } from '@/src/shared/services'; import { SideAction, Screen, ePocProject, NodeElement, Form, Card } from '@/src/shared/interfaces'; import { toRaw } from 'vue'; +import { useVueFlow } from '@vue-flow/core'; import { formsModel } from '@/src/shared/data/form.data'; +const { findNode } = useVueFlow(); + type uid = string; interface EditorState { @@ -16,6 +19,7 @@ interface EditorState { form: Form; }; openedNodeId: uid | null; + openedParentId: uid | null; sideActions: SideAction[]; questions: SideAction[]; standardScreens: Screen[]; @@ -32,6 +36,7 @@ export const useEditorStore = defineStore('editor', { form: null, }, openedNodeId: null, + openedParentId: null, sideActions: actionItems, questions: questions, standardScreens: standardScreen, @@ -63,10 +68,11 @@ export const useEditorStore = defineStore('editor', { this.floatingMenu = false; this.modelMenu = false; }, - openFormPanel(id: string, form: Form): void { + openFormPanel(id: string, form: Form, parentId?: string): void { this.formPanel.isOpen = true; this.formPanel.form = form; this.openedNodeId = id; + this.openedParentId = parentId; }, closeFormPanel(): void { this.formPanel.isOpen = false; @@ -97,7 +103,10 @@ export const useEditorStore = defineStore('editor', { // type: 'remove', // } // ]); - console.log(this.openedNodeId); + console.log('deleteCurrentElement', this.openedParentId); + const node = findNode(this.openedParentId); + console.log('node', node); + this.closeFormPanel(); }, addCard(type: string, fieldIndex: number):void { const newCard: Card = this.getCard(type);