index.vue 5.59 KB
<script setup lang="ts">
  import { Background, BackgroundVariant } from '@vue-flow/background';
  import { Controls } from '@vue-flow/controls';
  import { Panel, PanelPosition, VueFlow } from '@vue-flow/core';
  import { computed, onMounted, Ref, ref, unref } from 'vue';
  import './style';
  import { BasicConnectionArrow, BasicConnectionLine, BasicEdge, Sidebar } from './src/components';
  import type { FlowElRef } from './types/flow';
  import { useDragCreate } from './hook/useDragCreate';
  import { createFlowContext } from './hook/useFlowContext';
  import { CreateNodeModal } from './src/components/CreateNodeModal';
  import { useRuleFlow } from './hook/useRuleFlow';
  import { CreateEdgeModal } from './src/components/CreateEdgeModal';
  import { useFullScreen } from './hook/useFullScreen';
  import { useSaveAndRedo } from './hook/useSaveAndRedo';
  import { Icon } from '/@/components/Icon';
  import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer';
  import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer';

  const getId = Number(Math.random().toString().substring(2)).toString(16);

  const rootElRef = ref<Nullable<HTMLDivElement>>(null);

  const createNodeModalActionType = ref<Nullable<InstanceType<typeof CreateNodeModal>>>(null);

  const createEdgeModalActionType = ref<Nullable<InstanceType<typeof CreateEdgeModal>>>(null);

  const updateNodeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>(null);

  const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null);

  const flowElRef = ref<Nullable<FlowElRef>>(null);

  const elements = ref([]);

  const {
    changeMarker,
    getCurrentPageMetaData,
    triggerChange,
    handleApplyChange,
    handleRedoChange,
  } = useSaveAndRedo();

  const { flowActionType } = useRuleFlow({
    id: getId,
    createNodeModalActionType,
    createEdgeModalActionType,
    updateEdgeDrawerActionType,
    updateNodeDrawerActionType,
    triggerChange,
  });

  const { handleOnDragOver, handleOnDrop } = useDragCreate({
    el: flowElRef,
    createNodeModalActionType,
    flowActionType,
    triggerChange,
  });

  const { handleFullScreen, getFullScreenIcon } = useFullScreen(
    rootElRef as unknown as Ref<Nullable<HTMLDivElement>>
  );

  const handleGetContainer = () => unref(rootElRef)!;

  const getDeleteDisplayState = computed(() => unref(flowActionType.getSelectedElements).length);

  const handleDeleteSelectionElements = () => {
    flowActionType.removeSelectedElements();
  };

  onMounted(() => {
    getCurrentPageMetaData(flowActionType);
  });

  createFlowContext({
    createEdgeModalActionType,
    createNodeModalActionType,
    updateEdgeDrawerActionType,
    updateNodeDrawerActionType,
    flowActionType,
    triggerChange,
  });
</script>

<template>
  <main ref="rootElRef" class="w-full h-full flex relative" @drop="handleOnDrop">
    <Sidebar />

    <VueFlow
      :id="getId"
      ref="flowElRef"
      v-model="elements"
      class="w-full h-full"
      @dragover="handleOnDragOver"
    >
      <template #connection-line="props">
        <BasicConnectionLine v-bind="props" />
      </template>
      <template #edge-custom="props">
        <BasicEdge v-bind="props" />
      </template>

      <BasicConnectionArrow />

      <Background :variant="BackgroundVariant.Lines" :gap="25" pattern-color="#cfcfcf" />

      <Controls :position="PanelPosition.BottomLeft" />

      <Panel position="bottom-right" class="controls">
        <section class="flex gap-4">
          <button
            :style="{ transform: `translateY(${getDeleteDisplayState ? 0 : '72px'})` }"
            class="button-box-shadow w-14 h-14 flex justify-center items-center bg-orange-600 rounded-full transition-transform transform"
            @click="handleDeleteSelectionElements"
          >
            <Icon class="!text-3xl !text-light-50" icon="mdi:delete" />
          </button>
          <button
            class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full opacity-50"
          >
            <Icon class="!text-3xl !text-light-50" icon="carbon:debug" />
          </button>
          <button
            :class="changeMarker ? '!bg-orange-600 !opacity-100' : 'opacity-50'"
            class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full"
            @click="handleApplyChange(flowActionType)"
          >
            <Icon class="!text-3xl !text-light-50" icon="mdi:tick" />
          </button>
          <button
            :class="changeMarker ? '!bg-orange-600 !opacity-100' : 'opacity-50'"
            class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full"
            @click="handleRedoChange(flowActionType)"
          >
            <Icon class="!text-3xl !text-light-50" icon="ic:baseline-close" />
          </button>
        </section>
      </Panel>

      <Panel position="top-right">
        <button
          class="w-10 h-10 bg-gray-300 flex justify-center items-center rounded-full"
          @click="handleFullScreen"
        >
          <Icon class="!text-2xl" :icon="getFullScreenIcon" />
        </button>
      </Panel>
    </VueFlow>

    <CreateNodeModal ref="createNodeModalActionType" :get-container="handleGetContainer" />
    <CreateEdgeModal ref="createEdgeModalActionType" :get-container="handleGetContainer" />

    <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" />
    <UpdateNodeDrawer ref="updateNodeDrawerActionType" />
  </main>
</template>

<style scoped>
  .button-box-shadow {
    box-shadow: 0 3px 5px -1px #0003, 0 6px 10px 0 #00000024, 0 1px 18px 0 #0000001f;
  }
</style>