Browse Source

feat(editor): add comparison block

Ahmad Kholid 3 years ago
parent
commit
5f0722edfb

+ 13 - 41
src/components/block/BlockBase.vue

@@ -1,5 +1,5 @@
 <template>
-  <div ref="rootRef" class="group relative overflow-x-hiddenx">
+  <div id="block-base" class="group relative">
     <div
       class="
         z-10
@@ -13,19 +13,17 @@
       "
     >
       <span
-        :class="categories[state.blockDetails.category]?.color"
+        :class="block.category.color"
         class="inline-block p-2 mr-2 rounded-lg bg-green-200"
       >
-        <v-remixicon
-          :path="icons[state.blockDetails.icon] || icons.riGlobalLine"
-        />
+        <v-remixicon :path="icons[block.details.icon] || icons.riGlobalLine" />
       </span>
       <div style="max-width: 200px">
         <p class="font-semibold leading-none whitespace-nowrap">
-          {{ state.blockDetails.name }}
+          {{ block.details.name }}
         </p>
         <p class="text-gray-600 text-overflow leading-tight">
-          {{ state.blockData.description }}
+          {{ block.data.description }}
         </p>
         <input
           type="text"
@@ -52,10 +50,7 @@
           <v-remixicon size="20" :path="icons.riPencilLine" />
         </button>
         <hr class="border-r border-gray-600 h-5 mx-3" />
-        <button
-          class="-mr-1"
-          @click="editor.removeNodeId(`node-${state.blockId}`)"
-        >
+        <button class="-mr-1" @click="editor.removeNodeId(`node-${block.id}`)">
           <v-remixicon size="20" :path="icons.riDeleteBin7Line" />
         </button>
       </div>
@@ -63,11 +58,10 @@
   </div>
 </template>
 <script setup>
-import { ref, nextTick, reactive } from 'vue';
 import { VRemixIcon as VRemixicon } from 'v-remixicon';
 import emitter from 'tiny-emitter/instance';
 import { icons } from '@/lib/v-remixicon';
-import { tasks, categories } from '@/utils/shared';
+import { useEditorBlock } from '@/composable/editorBlock';
 
 const props = defineProps({
   editor: {
@@ -76,40 +70,18 @@ const props = defineProps({
   },
 });
 
-const rootRef = ref(null);
-const state = reactive({
-  blockId: '',
-  blockDetails: {},
-  blockData: {},
-});
+const block = useEditorBlock('#block-base', props.editor);
 
 function editBlock() {
   emitter.emit('editor:edit-block', {
-    ...state.blockDetails,
-    data: state.blockData,
-    blockId: state.blockId,
+    ...block.details,
+    data: block.data,
+    blockId: block.id,
   });
 }
 function handleDataChange() {
-  const { data } = props.editor.getNodeFromId(state.blockId);
+  const { data } = props.editor.getNodeFromId(block.id);
 
-  state.blockData = data;
+  block.data = data;
 }
-
-nextTick(() => {
-  if (state.blockId) return;
-
-  state.blockId = rootRef.value?.parentElement.parentElement.id.replace(
-    'node-',
-    ''
-  );
-
-  if (state.blockId) {
-    const { name, data } = props.editor.getNodeFromId(state.blockId);
-    const details = tasks[name];
-
-    state.blockDetails = { id: name, ...details };
-    state.blockData = data || details.data;
-  }
-});
 </script>

+ 119 - 0
src/components/block/BlockComparison.vue

@@ -0,0 +1,119 @@
+<template>
+  <div id="block-comparison" class="p-4">
+    <div class="flex items-center">
+      <div
+        :class="block.category.color"
+        class="inline-block text-sm mr-4 p-2 rounded-lg"
+      >
+        <v-remixicon :path="icons.riAB" size="20" class="inline-block mr-1" />
+        <span>Comparison</span>
+      </div>
+      <div class="flex-grow"></div>
+      <v-remixicon
+        :path="icons.riDeleteBin7Line"
+        class="cursor-pointer"
+        @click="editor.removeNodeId(`node-${block.id}`)"
+      />
+      <button
+        class="bg-accent ml-2 rounded-lg text-white text-center"
+        style="height: 37px; width: 37px"
+        @click="addComparison"
+      >
+        <v-remixicon :path="icons.riAddLine" class="inline-block" />
+      </button>
+    </div>
+    <div
+      v-if="block.data.comparison && block.data.comparison.length !== 0"
+      class="mt-4 space-y-2"
+    >
+      <div
+        v-for="(item, index) in block.data.comparison"
+        :key="item.id"
+        class="flex items-center group justify-end"
+      >
+        <v-remixicon
+          :path="icons.riDeleteBin7Line"
+          class="mr-2 invisible group-hover:visible cursor-pointer"
+          @click="deleteComparison(index)"
+        />
+        <div class="flex items-center transition bg-input rounded-lg">
+          <select
+            v-model="block.data.comparison[index].type"
+            class="
+              bg-transparent
+              font-mono
+              z-10
+              p-2
+              text-center
+              transition
+              rounded-l-lg
+              appearance-none
+            "
+          >
+            <option
+              v-for="(name, type) in conditions"
+              :key="type"
+              :value="type"
+            >
+              {{ type }}
+            </option>
+          </select>
+          <div class="bg-gray-300 w-px" style="height: 30px"></div>
+          <input
+            v-model="block.data.comparison[index].value"
+            type="text"
+            placeholder="value"
+            class="p-2 flex-1 transition rounded-r-lg bg-transparent w-36"
+          />
+        </div>
+      </div>
+      <p
+        v-if="block.data.comparison && block.data.comparison.length !== 0"
+        class="text-right text-gray-600"
+      >
+        <span title="Blabla">&#9432;</span> Fallback
+      </p>
+    </div>
+  </div>
+</template>
+<script setup>
+import { watch, toRaw } from 'vue';
+import { VRemixIcon as VRemixicon } from 'v-remixicon';
+import { nanoid } from 'nanoid';
+import { debounce } from '@/utils/helper';
+import { icons } from '@/lib/v-remixicon';
+import { useEditorBlock } from '@/composable/editorBlock';
+
+const props = defineProps({
+  editor: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+
+const block = useEditorBlock('#block-comparison', props.editor);
+const conditions = {
+  '==': 'Equals',
+  '>': 'Greater than',
+  '>=': 'Greater than or equal',
+  '<': 'Less than',
+  '<=': 'Less than or equal',
+};
+
+function addComparison() {
+  block.data.comparison.push({ id: nanoid(6), type: '==', value: '' });
+}
+function deleteComparison(index) {
+  block.data.comparison.splice(index, 1);
+}
+
+watch(
+  () => block.data.comparison,
+  debounce((newValue) => {
+    props.editor.updateNodeDataFromId(block.id, {
+      comparison: toRaw(newValue),
+    });
+  }, 250),
+  { deep: true }
+);
+</script>

+ 1 - 1
src/components/newtab/workflow/WorkflowBuilder.vue

@@ -63,7 +63,7 @@ export default {
         xPosition,
         yPosition,
         block.id,
-        { id: block.id, name: block.name, data: block.data },
+        block.data,
         block.component,
         'vue'
       );

+ 30 - 0
src/composable/editorBlock.js

@@ -0,0 +1,30 @@
+import { reactive, nextTick } from 'vue';
+import { tasks, categories } from '@/utils/shared';
+
+export function useEditorBlock(selector, editor) {
+  const block = reactive({
+    id: '',
+    data: {},
+    details: {},
+    category: {},
+  });
+
+  nextTick(() => {
+    const element = document.querySelector(selector);
+
+    if (block.id || !element) return;
+
+    block.id = element.parentElement.parentElement.id.replace('node-', '');
+
+    if (block.id) {
+      const { name, data } = editor.getNodeFromId(block.id);
+      const details = tasks[name];
+
+      block.details = { id: name, ...details };
+      block.data = data || details.data;
+      block.category = categories[details.category];
+    }
+  });
+
+  return block;
+}

+ 7 - 0
src/lib/v-remixicon.js

@@ -1,6 +1,8 @@
 import vRemixicon from 'v-remixicon';
 import {
   riHome5Line,
+  riRestartLine,
+  riAB,
   riSaveLine,
   riSubtractLine,
   riPlayLine,
@@ -29,6 +31,7 @@ import {
   riMouseLine,
   riBracketsLine,
   riEqualizerLine,
+  riFocusLine,
   riCursorLine,
   riDownloadLine,
   riParagraph,
@@ -44,6 +47,8 @@ import {
 
 export const icons = {
   riHome5Line,
+  riRestartLine,
+  riAB,
   riSaveLine,
   riSubtractLine,
   riPlayLine,
@@ -72,6 +77,7 @@ export const icons = {
   riMouseLine,
   riBracketsLine,
   riEqualizerLine,
+  riFocusLine,
   riCursorLine,
   riDownloadLine,
   riParagraph,
@@ -83,6 +89,7 @@ export const icons = {
   riTimerLine,
   riLightbulbFlashLine,
   riFlashlightLine,
+  mdiEqual: 'M19,10H5V8H19V10M19,16H5V14H19V16Z',
   mdiDrag:
     'M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z',
 };

+ 2 - 2
src/newtab/pages/workflows/[id].vue

@@ -45,7 +45,7 @@ const workflowId = route.params.id;
 
 const editor = shallowRef(null);
 const state = reactive({
-  isEditBlock: true,
+  isEditBlock: false,
   blockData: {},
 });
 const workflow = computed(() => Workflow.find(workflowId) || {});
@@ -79,7 +79,7 @@ function updateWorkflow(data) {
 }
 function saveWorkflow() {
   const data = editor.value.export();
-
+  console.log(data);
   updateWorkflow({ drawflow: JSON.stringify(data) });
 }
 function editBlock(data) {

+ 42 - 5
src/utils/shared.js

@@ -159,6 +159,18 @@ export const tasks = {
       for: 1,
     },
   },
+  'reload-page': {
+    name: 'Reload page',
+    icon: 'riRestartLine',
+    component: 'BlockBase',
+    category: 'interaction',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: [],
+    maxConnection: 1,
+    disableEdit: true,
+    data: {},
+  },
   'trigger-element-events': {
     name: 'Trigger element events',
     icon: 'riLightbulbFlashLine',
@@ -176,6 +188,32 @@ export const tasks = {
       events: [],
     },
   },
+  comparison: {
+    name: 'Comparison',
+    icon: 'riAB',
+    component: 'BlockComparison',
+    category: 'conditions',
+    inputs: 1,
+    outputs: 0,
+    allowedInputs: [],
+    maxConnection: false,
+    data: {
+      comparison: [],
+    },
+  },
+  'element-exists': {
+    name: 'Element exists',
+    icon: 'riFocus3Line',
+    component: 'BlockElementExists',
+    category: 'conditions',
+    inputs: 1,
+    outputs: 0,
+    allowedInputs: [],
+    maxConnection: false,
+    data: {
+      selector: '',
+    },
+  },
 };
 
 export const categories = {
@@ -187,9 +225,8 @@ export const categories = {
     name: 'General',
     color: 'bg-yellow-200',
   },
-};
-
-export const conditions = {
-  /* has attribute or attribute value/key equel to */
-  attribute: {},
+  conditions: {
+    name: 'Conditions',
+    color: 'bg-blue-200',
+  },
 };