diff --git a/src/features/ePocFlow/ePocFlow.vue b/src/features/ePocFlow/ePocFlow.vue index 9f6e39a92c927d437ae1ec02ce6ebe7e5ae13d9d..b8c4ce5efa310ae7f1947295328a9b45b7de34d7 100644 --- a/src/features/ePocFlow/ePocFlow.vue +++ b/src/features/ePocFlow/ePocFlow.vue @@ -1,17 +1,20 @@ <script setup lang="ts"> -import { VueFlow, useVueFlow, Panel, PanelPosition } from '@vue-flow/core'; +import { VueFlow, useVueFlow, Panel, PanelPosition, MarkerType } from '@vue-flow/core'; import { markRaw, nextTick, watch } from 'vue'; import ScreenNode from './nodes/ScreenNode.vue'; import CustomConnectContent from './edges/CustomConnectContent.vue'; -import { SideAction, NodeElement, Form } from '../../shared/interfaces'; -import { useEditorStore } from '../../shared/stores'; +import { SideAction, NodeElement, Form } from '@/src/shared/interfaces'; +import { useEditorStore } from '@/src/shared/stores'; import ChapterNode from './nodes/ChapterNode.vue'; import ePocNode from './nodes/ePocNode.vue'; import AddChapterNode from './nodes/AddChapterNode.vue'; const { nodes, addNodes, addEdges, onConnect, vueFlowRef, project, findNode, setNodes, setEdges } = useVueFlow(); -onConnect((params) => addEdges([{...params, updatable: true, style: { stroke: '#384257', strokeWidth: 2.5 }}])); +//TODO: find a way to ignore the onConnect here and only use the snap to handle one +onConnect((params) => { + addEdges([{...params, updatable: true, style: { stroke: '#384257', strokeWidth: 2.5 }, markerEnd: { type: MarkerType.ArrowClosed, color: '#384257'} }]); +}); const editorStore = useEditorStore(); @@ -51,7 +54,7 @@ const mainEdge = { const elements = [epoc, add, mainEdge]; -//? Use this to detect interesctions(for creating screen); +//? Use this to detect intersections(for creating screen); // onNodeDrag(({ intersections }) => { // const intersectionIds = intersections.map((intersection) => intersection.id); @@ -182,7 +185,6 @@ function addChapter() { } function openForm(id: string, form: Form) { - console.log('open screen Form'); editorStore.openFormPanel(id, form); } diff --git a/src/features/ePocFlow/edges/CustomConnectContent.vue b/src/features/ePocFlow/edges/CustomConnectContent.vue index 516687c7c9017ffb1336e3e7851355ae1634dbc0..63f2957e8378b0bad2b9709d551d2cd47a71057c 100644 --- a/src/features/ePocFlow/edges/CustomConnectContent.vue +++ b/src/features/ePocFlow/edges/CustomConnectContent.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { Position, connectionExists, getSimpleBezierPath, useVueFlow } from '@vue-flow/core'; +import { MarkerType, Position, connectionExists, getSimpleBezierPath, useVueFlow } from '@vue-flow/core'; import { computed, reactive, ref, watch } from 'vue'; const props = defineProps({ @@ -125,9 +125,14 @@ onConnectEnd(() => { target: closest.node.id, targetHandle: closest.handle.id, updatable: true, - style: { stroke: '#384257', strokeWidth: 2.5 } + style: { stroke: '#384257', strokeWidth: 2.5 }, + markerEnd: { type: MarkerType.ArrowClosed, color: '#384257' }, }, ]); + // document.querySelector('.vue-flow__handle-' + closest.handle.id)?.classList.add('connected'); + // document.querySelector('.vue-flow__handle-' + closest.startHandle.handleId)?.classList.add('connected'); + // console.log(closest.startHandle); + // console.log(closest.handle); } } }); diff --git a/src/features/ePocFlow/nodes/ChapterNode.vue b/src/features/ePocFlow/nodes/ChapterNode.vue index 260b8d50548400418cb1f64191448a7ea98c9ca9..46c649f204012ed6858e07478acc64317c3d38e9 100644 --- a/src/features/ePocFlow/nodes/ChapterNode.vue +++ b/src/features/ePocFlow/nodes/ChapterNode.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> -import ContentButton from '../../../components/ContentButton.vue'; -import { NodeElement } from '../../../shared/interfaces'; -import { useEditorStore } from '../../../shared/stores'; +import ContentButton from '@/src/components/ContentButton.vue'; +import { NodeElement } from '@/src/shared/interfaces'; +import { useEditorStore } from '@/src/shared/stores'; import { Handle } from '@vue-flow/core'; import { Position } from '@vue-flow/core'; diff --git a/src/features/ePocFlow/nodes/ScreenNode.vue b/src/features/ePocFlow/nodes/ScreenNode.vue index 411f331150254e28170a10d791e691aac6c86516..1010d540f1556eaf76cb76459e7854f220d1c402 100644 --- a/src/features/ePocFlow/nodes/ScreenNode.vue +++ b/src/features/ePocFlow/nodes/ScreenNode.vue @@ -1,9 +1,9 @@ <script setup lang="ts"> import { Handle, useVueFlow } from '@vue-flow/core'; -import ContentButton from '../../../components/ContentButton.vue'; +import ContentButton from '@/src/components/ContentButton.vue'; import { onMounted } from 'vue'; -import { useEditorStore } from '../../../shared/stores'; -import { NodeElement } from '../../../shared/interfaces'; +import { useEditorStore } from '@/src/shared/stores'; +import { NodeElement } from '@/src/shared/interfaces'; import { Position } from '@vue-flow/core'; const editorStore = useEditorStore(); @@ -64,6 +64,18 @@ function openForm(element: NodeElement) { editorStore.openFormPanel(element.id, element.form); } + +// const node = ref(findNode(props.id)); +// const connectedEdges = ref(getConnectedEdges([node.value], edges.value)); + +// const source = ref(connectedEdges.value.forEach((edge) => { if(edge.source === props.id) return true; })); +// const target = ref(connectedEdges.value.forEach((edge) => { if(edge.target === props.id) return true; })); + +// onConnectEnd(() => { +// console.log('source', source.value); +// console.log('target', target.value); +// }); + </script> <template> diff --git a/src/features/ePocFlow/nodes/ScreenNode.vue~refs/remotes/origin/main b/src/features/ePocFlow/nodes/ScreenNode.vue~refs/remotes/origin/main deleted file mode 100644 index 411f331150254e28170a10d791e691aac6c86516..0000000000000000000000000000000000000000 --- a/src/features/ePocFlow/nodes/ScreenNode.vue~refs/remotes/origin/main +++ /dev/null @@ -1,113 +0,0 @@ -<script setup lang="ts"> -import { Handle, useVueFlow } from '@vue-flow/core'; -import ContentButton from '../../../components/ContentButton.vue'; -import { onMounted } from 'vue'; -import { useEditorStore } from '../../../shared/stores'; -import { NodeElement } from '../../../shared/interfaces'; -import { Position } from '@vue-flow/core'; - -const editorStore = useEditorStore(); - -const props = defineProps<{ - id: string; - data: { - type: object; - required: true; - readyToDrop: boolean; - animated: boolean; - elements: NodeElement[]; - } -}>(); - -// This add an animation when the node is added to the flow -onMounted(() => { - const node = document.querySelector('#node' + props.id); - node.classList.add('node'); - if(props.data.animated) node.classList.add('node-creation-animation'); -}); - -//TODO: Think about refactoring this -let dragOverCount = 0; - -function dragOver(event) { - if(event.dataTransfer.types.length > 1) return; - dragOverCount ++; - if(dragOverCount > 25) { - dragOverCount = 0; - nodes.value.find(element => element.id === props.id).data.readyToDrop = true; - document.querySelector('#node'+props.id).classList.add('node-animate'); - - // To be sure the counter is set to 1 when ready to drop - counter = 1; - } -} - -// This counter is used to avoid triggering dragLeave when not necessary -let counter = 0; - -function dragLeave() { - counter --; - if (counter > 0) return; - nodes.value.find(element => element.id === props.id).data.readyToDrop = false; - document.querySelector('#node'+props.id).classList.remove('node-animate'); - dragOverCount = 0; -} - -function dragEnter(event) { - event.preventDefault(); - counter ++; -} - -const { nodes } = useVueFlow(); - -function openForm(element: NodeElement) { - editorStore.openFormPanel(element.id, element.form); -} - -</script> - -<template> - <p contenteditable="true" class="node-title">Screen</p> - <Handle type="target" :position="Position.Left" /> - <div - :id="'node'+props.id" - :class=" { 'active': editorStore.openedNodeId ? editorStore.openedNodeId === props.id : false }" - class="node" - @dragover="dragOver" - @dragleave="dragLeave" - @dragenter="dragEnter" - > - <ContentButton - v-for="element of props.data.elements" - :key="element.action.icon" - :icon="element.action.icon" - :is-active="editorStore.openedNodeId ? editorStore.openedNodeId === element.id : false" - :is-draggable="false" - :class-list="{ 'btn-content-blue' : false, 'clickable': true, 'btn-content-node': true }" - @click="openForm(element)" - /> - </div> - <Handle type="source" :position="Position.Right" /> -</template> - -<style scoped lang="scss"> - -.vue-flow__handle { - width: 12px; - height: 12px; - &-left { - left: -6px; - } - &-right { - right: -6px; - } -} -.node-title { - margin: .2rem; - padding: .2rem; - &:focus-visible { - outline: 1px solid var(--editor-blue); - border-radius: 4px; - } -} -</style> \ No newline at end of file diff --git a/src/features/ePocFlow/nodes/ePocNode.vue b/src/features/ePocFlow/nodes/ePocNode.vue index 8e0239ae013784bf02649dc5551938b65cf399b8..78d0c34762f9a450ea1640e84d69449dc07a50ea 100644 --- a/src/features/ePocFlow/nodes/ePocNode.vue +++ b/src/features/ePocFlow/nodes/ePocNode.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> -import ContentButton from '../../../components/ContentButton.vue'; -import { NodeElement } from '../../../shared/interfaces'; -import { useEditorStore } from '../../../shared/stores'; +import ContentButton from '@/src/components/ContentButton.vue'; +import { NodeElement } from '@/src/shared/interfaces'; +import { useEditorStore } from '@/src/shared/stores'; const editorStore = useEditorStore(); const props = defineProps<{ diff --git a/src/features/forms/FormPanel.vue b/src/features/forms/FormPanel.vue index 9582aef619c9d28318980f9d2128dcd131de3b7d..c173daf9d4b6ddcd38588690ce1236e24e3f3242 100644 --- a/src/features/forms/FormPanel.vue +++ b/src/features/forms/FormPanel.vue @@ -3,6 +3,8 @@ import { useEditorStore } from '../../shared/stores'; import FormButton from './components/FormButton.vue'; import GenericField from './components/GenericField.vue'; import CardGroup from './components/inputs/card/CardGroup.vue'; +import { Input } from '@/src/shared/interfaces'; +import { Card } from '@/src/shared/interfaces/card.interface'; const editorStore = useEditorStore(); @@ -15,7 +17,7 @@ function actionOnForm(action: string) { } function addCard(type: string, index: number): void { - editorStore.addInput(type, index); + editorStore.addCard(type, index); } function deleteCard(cardIndex: number, fieldIndex: number): void { @@ -71,7 +73,7 @@ function swapCard(event, fieldIndex) { > <CardGroup v-if="field.type === 'cardGroup'" - :inputs="field.inputs" + :cards="(field.inputs as Card[])" :field-name="field.name" :field-index="field.index" :type="field.inputType" @@ -83,7 +85,7 @@ function swapCard(event, fieldIndex) { /> <GenericField v-else - :inputs="field.inputs" + :inputs="(field.inputs as Input[])" :field-name="field.name" :field-index="field.index" /> diff --git a/src/features/forms/components/GenericField.vue b/src/features/forms/components/GenericField.vue index 20bc2f522933620545a43fa84a7ae2e6c96caff5..57b68162508981517b67055d50508ef0fbfe3ab5 100644 --- a/src/features/forms/components/GenericField.vue +++ b/src/features/forms/components/GenericField.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { Input } from '../../../shared/interfaces'; +import { Input } from '@/src/shared/interfaces'; import GenericInput from './inputs/GenericInput.vue'; defineProps<{ diff --git a/src/features/forms/components/inputs/FileInput.vue b/src/features/forms/components/inputs/FileInput.vue index 23bbd428f1bf28e86167d8d8d546b1f2a424a686..893861884f0f4cec0bf9f69d11aab08fe9ce3ea9 100644 --- a/src/features/forms/components/inputs/FileInput.vue +++ b/src/features/forms/components/inputs/FileInput.vue @@ -1,5 +1,5 @@ -<script setup lang="ts">import { ref } from 'vue'; - +<script setup lang="ts"> +import { ref } from 'vue'; defineProps<{ label: string; diff --git a/src/features/forms/components/inputs/GenericInput.vue b/src/features/forms/components/inputs/GenericInput.vue index 7b90cfcd4d51c3e96ec11e60fdcb888b3ab7bbcf..cbc443b60681d06a30544505553f5c1d30232d08 100644 --- a/src/features/forms/components/inputs/GenericInput.vue +++ b/src/features/forms/components/inputs/GenericInput.vue @@ -5,6 +5,10 @@ import FileInput from './FileInput.vue'; import ScoreInput from './ScoreInput.vue'; import QuillEditor from './QuillEditor.vue'; +import CheckBoxInput from './card/components/CheckBoxInput.vue'; +import RadioInput from './card/components/RadioInput.vue'; +import SelectInput from './card/components/SelectInput.vue'; + defineProps<{ type: string; label: string; @@ -12,12 +16,8 @@ defineProps<{ placeholder?: string; accept?: string; icon?: string; - question?: { - isLast?: boolean; - pos: number; - type?: string; - }; - addType?: string; + insideCard?: boolean; + pos?: number; }>(); const emit = defineEmits<{ @@ -35,6 +35,7 @@ const emit = defineEmits<{ :label="label" :placeholder="placeholder" :input-value="inputValue" + :inside-card="insideCard" @input="emit('input', $event)" /> <QuillEditor @@ -49,6 +50,7 @@ const emit = defineEmits<{ :label="label" :placeholder="placeholder" :input-value="inputValue" + :inside-card="insideCard" @input="emit('input', $event)" /> <FileInput @@ -64,4 +66,24 @@ const emit = defineEmits<{ :input-value="inputValue" @input="emit('input', $event)" /> + <CheckBoxInput + v-if="type === 'checkbox'" + :label="label" + :input-value="inputValue" + @change="emit('input', $event)" + /> + <RadioInput + v-if="type === 'radio-group'" + :label="label" + :input-value="inputValue" + :pos="pos" + @change="emit('input', $event)" + /> + <SelectInput + v-if="type === 'select'" + :label="label" + :placeholder="placeholder" + :input-value="inputValue" + @change="emit('input', $event)" + /> </template> \ No newline at end of file diff --git a/src/features/forms/components/inputs/TextAreaInput.vue b/src/features/forms/components/inputs/TextAreaInput.vue index e23676dccb430009fc67867abf129e2ab2e09d8d..8a3a7a0e371b8034318f266ad9e1f35578b08082 100644 --- a/src/features/forms/components/inputs/TextAreaInput.vue +++ b/src/features/forms/components/inputs/TextAreaInput.vue @@ -5,6 +5,7 @@ defineProps<{ placeholder: string; inputValue: string; insideCard?: boolean; + classList?: string; }>(); const emit = defineEmits<{ diff --git a/src/features/forms/components/inputs/TextInput.vue b/src/features/forms/components/inputs/TextInput.vue index 893666929c6d6b65f437cc2f3b5dc094e9337841..a5805642f907bbe19c4d08037a57245407bd7423 100644 --- a/src/features/forms/components/inputs/TextInput.vue +++ b/src/features/forms/components/inputs/TextInput.vue @@ -4,6 +4,7 @@ defineProps<{ label: string; placeholder?: string; inputValue: string; + insideCard?: boolean }>(); const emit = defineEmits<{ @@ -17,6 +18,7 @@ const emit = defineEmits<{ <input :id="label" class="input" + :class="{ 'input-card' : insideCard }" type="text" :placeholder="placeholder" :value="inputValue" diff --git a/src/features/forms/components/inputs/card/CardGroup.vue b/src/features/forms/components/inputs/card/CardGroup.vue index 1ca1dd825ca951289f1fc10db6cd41e7365671f7..54f15368e1b4f913e89fcbdcdde3b1999ecad9c6 100644 --- a/src/features/forms/components/inputs/card/CardGroup.vue +++ b/src/features/forms/components/inputs/card/CardGroup.vue @@ -1,12 +1,12 @@ <script setup lang="ts"> -import { Input } from '../../../../../shared/interfaces'; +import { Card } from '@/src/shared/interfaces'; import AddCard from './AddCard.vue'; import CardInput from './CardInput.vue'; import draggable from 'vuedraggable'; defineProps<{ type: string; - inputs: Input[]; + cards: Card[]; fieldName?: string; fieldIndex?: number; }>(); @@ -19,18 +19,6 @@ const emit = defineEmits<{ (e: 'swapCard', event): void; }>(); -//? Use this to get the text for the differents card -//? This way doesn't seem to be optimal -const cardMap = new Map([ - ['check', 'Réponse'], - ['objective', 'Objectif'], - ['category', 'Catégorie'], - ['dd', 'Réponse'], - ['reorder', 'Réponse position'], - ['swipe', 'Carte'], - ['list-choice', 'Choix'], - ['list', 'Carte'] -]); </script> @@ -38,7 +26,7 @@ const cardMap = new Map([ <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="inputs" + :model-value="cards" item-key="index" handle=".card-header" ghost-class="ghost" @@ -47,11 +35,8 @@ const cardMap = new Map([ <template #item="{element, index}"> <CardInput :pos="index + 1" - :type="type" - :is-last="index === inputs.length - 1" - :input-value="element.value" - :placeholder="'Saisissez...'" - :title="cardMap.get(type)" + :card="element" + :is-last="index === cards.length - 1" @input="element.value = $event" @delete-card="emit('deleteCard', index)" @move-up-card="emit('moveUpCard', index)" diff --git a/src/features/forms/components/inputs/card/CardInput.vue b/src/features/forms/components/inputs/card/CardInput.vue index 9c3bf700c8045dc5531163e0e49e59705800c90c..c180b60a695933b98f6a9802a3bbe84a85e60f91 100644 --- a/src/features/forms/components/inputs/card/CardInput.vue +++ b/src/features/forms/components/inputs/card/CardInput.vue @@ -1,58 +1,55 @@ <script setup lang="ts"> -import TextAreaInput from '../TextAreaInput.vue'; -import CheckBoxInput from './components/CheckBoxInput.vue'; -import SelectInput from './components/SelectInput.vue'; -import RadioInput from './components/RadioInput.vue'; +import { Card } from '@/src/shared/interfaces'; +import GenericInput from '../GenericInput.vue'; defineProps<{ - inputValue: string; pos: number; - type?: string; isLast: boolean; - placeholder: string; - title: string; + card: Card }>(); const emit = defineEmits<{ (e: 'input', value: string): void; + (e: 'deleteCard'): void; (e: 'moveUpCard'): void; (e: 'moveDownCard'): void; + + (e: 'check', value: boolean): void; + (e: 'radioCheck', value: number): void; }>(); </script> <template> <Transition> - <div - class="card draggable-card" - > + <div class="card draggable-card"> <div class="card-header"> - <h3>{{ title }} {{ pos }}</h3> + <h3>{{ card.label }} {{ pos }}</h3> <div class="card-header-icon"> <i class="icon-supprimer" @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> <hr class="vertical-separator"> - <i class="icon-glisser"></i> + <i class="icon-glisser"></i> </div> </div> + <div class="card-content"> - <TextAreaInput - label="" + <GenericInput + v-for="(input, index) in card.inputs" + :key="index" + :type="input.type" :inside-card="true" - :placeholder="placeholder" - :input-value="inputValue" - @input="emit('input', $event)" + :label="input.label" + :placeholder="input.placeholder" + :input-value="input.value" + :pos="pos" + @input="input.value = $event" /> </div> - <CheckBoxInput v-if="type === 'check'" /> - <SelectInput v-if="type === 'dd'" :label="'À quelle catégorie appartient cette réponse ' + pos" /> - <SelectInput v-if="type === 'reorder'" label="Position affiché à l'écran avant réorganisation" /> - <SelectInput v-if="type === 'list'" label="Réponse" /> - <RadioInput v-if="type === 'swipe'" :index="pos" /> </div> </Transition> </template> diff --git a/src/features/forms/components/inputs/card/components/CheckBoxInput.vue b/src/features/forms/components/inputs/card/components/CheckBoxInput.vue index 27626b32c37e2fadabf1f7795335c4ea8afc2e29..c9f64dc228e3fad09a2b8eb35ef98b1e4b10f260 100644 --- a/src/features/forms/components/inputs/card/components/CheckBoxInput.vue +++ b/src/features/forms/components/inputs/card/components/CheckBoxInput.vue @@ -1,11 +1,13 @@ <script setup lang="ts"> -import { ref } from 'vue'; -const inputValue = ref(false); -const label = ref('C\'est une bonne réponse'); +defineProps<{ + inputValue: string; + label: string; +}>(); + const emit = defineEmits<{ - (e: 'input', value: string): void; + (e: 'change', value: string): void; }>(); </script> @@ -16,8 +18,8 @@ const emit = defineEmits<{ :id="label" class="checkbox-input" type="checkbox" - :value="inputValue" - @input="emit('input', ($event.target as HTMLInputElement).value)" + :checked="JSON.parse(inputValue)" + @change="emit('change', String(($event.target as HTMLInputElement).checked))" > <label :for="label">{{ label }}</label> </div> @@ -26,7 +28,7 @@ const emit = defineEmits<{ <style scoped lang="scss"> .checkbox { display: flex; - margin: 0 1rem 1rem 1rem; + margin: 1rem 0 .5rem 0; input[type="checkbox"] { appearance: none; margin: 0; diff --git a/src/features/forms/components/inputs/card/components/RadioInput.vue b/src/features/forms/components/inputs/card/components/RadioInput.vue index 8db062d156df8409d1a4505cd78d557a4be9dac6..6658355b9b857d02531f7fcc71c61382fab7c88d 100644 --- a/src/features/forms/components/inputs/card/components/RadioInput.vue +++ b/src/features/forms/components/inputs/card/components/RadioInput.vue @@ -1,7 +1,13 @@ <script setup lang="ts"> defineProps<{ - index: number; + inputValue: string; + label: string; + pos: number +}>(); + +const emit = defineEmits<{ + (e: 'change', value: string): void; }>(); </script> @@ -13,18 +19,22 @@ defineProps<{ <div class="radio-btn"> <input id="left" - :name="'pos' + index" + :name="'pos' + pos" type="radio" class="radio-input" + :checked="inputValue === '1'" + @change="emit('change', '1')" > <label for="left">Choix gauche</label> </div> <div class="radio-btn"> <input id="right" - :name="'pos' + index" + :name="'pos' + pos" type="radio" class="radio-input" + :checked="inputValue === '2'" + @change="emit('change', '2')" > <label for="right">Choix droite</label> </div> @@ -34,7 +44,7 @@ defineProps<{ <style scoped lang="scss"> .radio { - margin: 0 1rem 1rem 1rem; + margin: 1rem 0 .5rem 0; .radio-group { margin-top: .5rem; diff --git a/src/features/forms/components/inputs/card/components/SelectInput.vue b/src/features/forms/components/inputs/card/components/SelectInput.vue index ae3bd60a26d6755e794b04313ba4fe44f9a1cfe6..f54be706125633e284d5fa917760397beca33752 100644 --- a/src/features/forms/components/inputs/card/components/SelectInput.vue +++ b/src/features/forms/components/inputs/card/components/SelectInput.vue @@ -2,6 +2,12 @@ defineProps<{ label: string; + inputValue: string; + placeholder: string; +}>(); + +const emit = defineEmits<{ + (e: 'change', value: string): void; }>(); </script> @@ -9,11 +15,16 @@ defineProps<{ <template> <div class="select"> <label for="select-box">{{ label }}</label> - <select id="select-box" class="select-box"> + <select + id="select-box" + :value="inputValue" + class="select-box" + @change="emit('change', ($event.target as HTMLInputElement).value)" + > <option value="">Sélectionnez</option> - <option value="1">Position 1</option> - <option value="2">Position 2</option> - <option value="3">Position 3</option> + <option value="1">{{ placeholder }} 1</option> + <option value="2">{{ placeholder }} 2</option> + <option value="3">{{ placeholder }} 3</option> </select> </div> </template> @@ -22,7 +33,7 @@ defineProps<{ .select { display: flex; flex-direction: column; - margin-bottom: 1rem; + margin: 1rem 0 .5rem 0; label { margin-bottom: 0.5rem; } @@ -41,6 +52,5 @@ defineProps<{ background-position: right 0.7rem top 50%; background-size: .8rem auto; } - margin: 0 1rem 1rem 1rem; } </style> \ No newline at end of file diff --git a/src/global.scss b/src/global.scss index 38e3450f334790d1fdad2b4352968bcf164f8619..65129ff76519c90c5fde6ed1ff159a0d656b54b1 100644 --- a/src/global.scss +++ b/src/global.scss @@ -315,4 +315,11 @@ textarea { &-title { margin-bottom: .5rem; } -} \ No newline at end of file +} + +// .vue-flow__handle{ +// background: var(--inria-red); +// &.connected { +// background: var(--text); +// } +// } \ No newline at end of file diff --git a/src/shared/data/form.data.ts b/src/shared/data/form.data.ts index d06b3e940cb617fbe9164feef192d23fc5635636..288111437948d2e871b92b83eb544152840bc1b6 100644 --- a/src/shared/data/form.data.ts +++ b/src/shared/data/form.data.ts @@ -1,4 +1,4 @@ -import { Form } from '../interfaces'; +import { Form } from '@/src/shared/interfaces'; const textForm: Form = { type: 'text', @@ -115,6 +115,12 @@ const chapterForm: Form = { value: '', placeholder: 'Saisissez...' }, + { + type: 'text', + label: 'Label', + value: '', + placeholder: 'Saisissez...' + } ] }, { @@ -151,6 +157,12 @@ const epocForm: Form = { value: '', placeholder: 'Saisissez...' }, + { + type: 'text', + label: 'Label', + value: '', + placeholder: 'Saisissez...' + }, { type: 'file', label: 'Image de couverture', @@ -341,7 +353,7 @@ const qcmForm: Form = { name: 'Réponses', index: 3, type: 'cardGroup', - inputType: 'check', + inputType: 'qcm', inputs: [] }, { diff --git a/src/shared/interfaces/card.interface.ts b/src/shared/interfaces/card.interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..050d6c6d67e391283013880ba5285ae7169f25fb --- /dev/null +++ b/src/shared/interfaces/card.interface.ts @@ -0,0 +1,8 @@ +import { Input } from '.'; + +export interface Card { + type: string; + label: string; + placeholder: string; + inputs: Input[]; +} \ No newline at end of file diff --git a/src/shared/interfaces/class-diagram.md b/src/shared/interfaces/class-diagram.md index 84c5b297137978d93d357fe7aa61c370635bec46..5ce5f7ed3607b722b859789e2edc68b5c18c0b5a 100644 --- a/src/shared/interfaces/class-diagram.md +++ b/src/shared/interfaces/class-diagram.md @@ -16,4 +16,16 @@ classDiagram NodeElement -- Form: 1 NodeElement -- SideAction: 1 Form -- Input: 1..* +``` + +--- + +## Data Structure in the form +```mermaid +classDiagram + Form -- Field: 1..* + Field -- Input: 1..* + Field -- Card: 0..* + Card -- Input: 1..* + ``` \ No newline at end of file diff --git a/src/shared/interfaces/field.interface.ts b/src/shared/interfaces/field.interface.ts index d79d326eb26f365f781cf86cb361f6526dd2c932..a7e5c69d97f728ed5a150f7b7e37b404d0475e7b 100644 --- a/src/shared/interfaces/field.interface.ts +++ b/src/shared/interfaces/field.interface.ts @@ -1,9 +1,9 @@ -import { Input } from './input.interface'; +import { Input, Card } from '.'; export interface Field { name?: string; index?: number; type?: string; inputType?: string; - inputs: Input[]; + inputs: Input[] | Card[]; } \ No newline at end of file diff --git a/src/shared/interfaces/form.interface.ts b/src/shared/interfaces/form.interface.ts index c1b5d4fd26015d574bae3b129ba8b5304ea769d6..43c1136bae5a1fbac6acd524ee4d01682b5a4c8b 100644 --- a/src/shared/interfaces/form.interface.ts +++ b/src/shared/interfaces/form.interface.ts @@ -1,5 +1,5 @@ -import { Field } from './field.interface'; -import { FormButton } from './formButton.interface'; +import { Field, FormButton } from '.'; + export interface Form { type: string; name: string; diff --git a/src/shared/interfaces/index.ts b/src/shared/interfaces/index.ts index 61f7a50c1d05ec8e94e810f889efb80d49aff2de..5377fbdbf7317190abfdca414501784af6b1a87e 100644 --- a/src/shared/interfaces/index.ts +++ b/src/shared/interfaces/index.ts @@ -5,4 +5,5 @@ export * from './input.interface'; export * from './form.interface'; export * from './nodeElement.interface'; export * from './formButton.interface'; -export * from './field.interface'; \ No newline at end of file +export * from './field.interface'; +export * from './card.interface'; \ No newline at end of file diff --git a/src/shared/interfaces/screen.interface.ts b/src/shared/interfaces/screen.interface.ts index 83a5023af68c56d82ebc733a59d29cc6d20ab8d6..5dc91edc06ad66b058a7812af33f95d0655c46c8 100644 --- a/src/shared/interfaces/screen.interface.ts +++ b/src/shared/interfaces/screen.interface.ts @@ -1,4 +1,4 @@ -import { SideAction } from './sideAction.interface'; +import { SideAction } from '.'; export interface Screen { title: string; diff --git a/src/shared/services/editor.service.ts b/src/shared/services/editor.service.ts index 48d1e896c72a263a82526b641fee933b71d55c8c..d53381755cd11fdfafc8becaec0437b9c35b49dd 100644 --- a/src/shared/services/editor.service.ts +++ b/src/shared/services/editor.service.ts @@ -1,4 +1,4 @@ -import { ePocProject } from '../interfaces'; +import { ePocProject } from '@/src/shared/interfaces'; export async function fetchRecentProjects(): Promise<ePocProject[]> { //@ts-ignore diff --git a/src/shared/services/project.service.ts b/src/shared/services/project.service.ts index c65d7a19e82549047752a004d9ded5ef8c39141a..aa541af51a30a01c10c348e1ae43bdb026cf2732 100644 --- a/src/shared/services/project.service.ts +++ b/src/shared/services/project.service.ts @@ -1,4 +1,4 @@ -import { ePocProject } from '../interfaces'; +import { ePocProject } from '@/src/shared/interfaces'; export async function openEPOC(): Promise<ePocProject> { //@ts-ignore diff --git a/src/shared/stores/editorStore.ts b/src/shared/stores/editorStore.ts index 9ef83449ea3e99857c6cbe573594e2e942e047ac..2a4fdbc30bdba6d2996e7211039f046a262017e3 100644 --- a/src/shared/stores/editorStore.ts +++ b/src/shared/stores/editorStore.ts @@ -1,9 +1,9 @@ import { defineStore } from 'pinia'; -import { fetchRecentProjects } from '../services'; -import { SideAction, Screen, ePocProject, NodeElement, Form, Input } from '../interfaces'; +import { fetchRecentProjects } from '@/src/shared/services'; +import { SideAction, Screen, ePocProject, NodeElement, Form, Card } from '@/src/shared/interfaces'; import { toRaw } from 'vue'; -import { formsModel } from '../data/form.data'; +import { formsModel } from '@/src/shared/data/form.data'; type uid = string; @@ -86,6 +86,9 @@ export const useEditorStore = defineStore('editor', { getForm(type: string): Form { return structuredClone(toRaw(formsModel.find(form => form.type === type))); }, + getCard(type: string): Card { + return structuredClone(toRaw(cardsModel.find(card => card.type === type))); + }, deleteCurrentElement(): void { // const { applyNodeChanges } = useVueFlow(); // applyNodeChanges([ @@ -96,18 +99,148 @@ export const useEditorStore = defineStore('editor', { // ]); console.log(this.openedNodeId); }, - addInput(type: string, fieldIndex: number):void { - const newInput: Input = { - type: type, - label: '', - placeholder: '', - value: '' - }; - this.formPanel.form.fields[fieldIndex].inputs.push(newInput); + addCard(type: string, fieldIndex: number):void { + const newCard: Card = this.getCard(type); + this.formPanel.form.fields[fieldIndex].inputs.push(newCard); } } }); +const cardsModel: Card[] = [ + { + type: 'objective', + label: 'Objectif', + placeholder: 'Ajouter un objectif', + inputs: [ + { + type:'textarea', + label: '', + placeholder: 'Saisissez un objectif...', + value: '' + } + ] + }, + { + type: 'qcm', + label: 'Réponse', + placeholder: 'Ajouter une autre réponse', + inputs: [ + { + type:'textarea', + label: '', + placeholder: 'Saisissez une réponse...', + value: '' + }, + { + type: 'checkbox', + label: 'C\'est une bonne réponse', + value: 'false' + } + ] + }, + { + type: 'category', + label: 'Catégorie', + placeholder: 'Ajouter une autre catégorie', + inputs: [ + { + type: 'textarea', + label: '', + placeholder: 'Saisissez un intitulé de catégorie...', + value: '' + }, + ] + }, + { + type: 'dd', + label: 'Réponse', + placeholder: 'Ajouter une autre réponse proposée', + inputs: [ + { + type: 'textarea', + label: '', + placeholder: 'Saisissez une réponse...', + value: '' + }, + { + type: 'select', + label: 'À quelle catégorie appartient cette réponse', + placeholder: 'Catégorie', + value: '', + } + ] + }, + { + type: 'reorder', + label: 'Réponse', + placeholder: 'Ajouter une autre réponse', + inputs: [ + { + type: 'textarea', + label: '', + placeholder: 'Saisissez une réponse...', + value: '' + }, + { + type: 'select', + label: 'Position affichée à l\'écran avant réorganisation', + placeholder: 'Affichée en position', + value: '', + }, + ] + }, + { + type: 'swipe', + label: 'Carte', + placeholder: 'Ajouter une autre carte', + inputs: [ + { + type: 'textarea', + label: '', + placeholder: 'Saisissez une proposition...', + value: '' + }, + { + type: 'radio-group', + label: 'Réponse', + value: '0' + }, + ] + }, + { + type: 'list-choice', + label: 'Choix', + placeholder: 'Ajouter un autre choix', + inputs: [ + { + type: 'text', + label: '', + placeholder: 'Saisissez un choix...', + value: '' + }, + ] + }, + { + type: 'list', + label: 'Carte', + placeholder: 'Ajouter une autre carte', + inputs: [ + { + type: 'textarea', + label: '', + placeholder: 'Saisissez une question...', + value: '' + }, + { + type: 'select', + label: 'Réponse', + placeholder: 'Choix', + value: '', + } + ] + } +]; + const standardScreen: Screen[] = [ { title: 'Ecran texte', diff --git a/src/shared/stores/epocStore.ts b/src/shared/stores/epocStore.ts index 3d8e8c1df71cf8a33844bb37dc57d28738068822..01a0b99e02a2ea148ab1e58b3301a0685b775ad8 100644 --- a/src/shared/stores/epocStore.ts +++ b/src/shared/stores/epocStore.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia'; -import { Screen } from '../interfaces'; +import { Screen } from '@/src/shared/interfaces'; interface EpocState { screensModel: { diff --git a/src/shared/stores/projectStore.ts b/src/shared/stores/projectStore.ts index aeb45fe3df9227c284da699440a31b2c3b6c041c..5f44d24bd79deea9c0ca5f5927d81c5a5d30d0d1 100644 --- a/src/shared/stores/projectStore.ts +++ b/src/shared/stores/projectStore.ts @@ -1,6 +1,6 @@ import { defineStore } from 'pinia'; -import { ePocProject } from '../interfaces'; -import { openEPOC } from '../services'; +import { ePocProject } from '@/src/shared/interfaces'; +import { openEPOC } from '@/src/shared/services'; interface ProjectState { project: ePocProject; diff --git a/src/views/EditorPage.vue b/src/views/EditorPage.vue index 813163db13a921559431fd863950484d2ce6dcac..a365b93027d83ce260eb7ec5b0a245e4f3d009c5 100644 --- a/src/views/EditorPage.vue +++ b/src/views/EditorPage.vue @@ -1,9 +1,9 @@ <script setup lang="ts"> -import TopBar from '../features/topBar/TopBar.vue'; -import ePocFlow from '../features/ePocFlow/ePocFlow.vue'; -import { useEditorStore } from '../shared/stores'; -import SideBarV0 from '../features/sideBar/SideBarV0.vue'; -import FormPanel from '../features/forms/FormPanel.vue'; +import TopBar from '@/src/features/topBar/TopBar.vue'; +import ePocFlow from '@/src/features/ePocFlow/ePocFlow.vue'; +import { useEditorStore } from '@/src/shared/stores'; +import SideBarV0 from '@/src/features/sideBar/SideBarV0.vue'; +import FormPanel from '@/src/features/forms/FormPanel.vue'; const editorStore = useEditorStore(); diff --git a/src/views/LandingPage.vue b/src/views/LandingPage.vue index 20a33958b6921bb98f8ebe5a5745f1d46f97b24f..018c0a97b6cbc8eb2bea9e2c334359449249a03f 100644 --- a/src/views/LandingPage.vue +++ b/src/views/LandingPage.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> import { router } from '../router'; -import { useEditorStore, useProjectStore } from '../shared/stores'; +import { useEditorStore, useProjectStore } from '@/src/shared/stores'; const editorStore = useEditorStore();