<script setup lang="ts">
import { ref, markRaw, type Component, computed, watch, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import type { Node, Edge } from '@vue-flow/core';
import { Panel, VueFlow, useVueFlow } from '@vue-flow/core';
import { Background, BackgroundVariant, MiniMap } from '@vue-flow/additional-components';

import SpecialNode from './components/SpecialNode.vue';
import SpecialEdge from './components/SpecialEdge.vue';
import NodeTypeItem from './components/NodeType.vue';
import ImageNode from './components/ImageNode.vue';
import TextNode from './components/TextNode.vue';
import VideoNode from './components/VideoNode.vue';
import AudioNode from './components/AudioNode.vue';
import Editor from './components/Editor.vue';
import SvgIcon from '@/components/SvgIcon/SvgIcon.vue';
import SelectIcon from '@/components/SvgIcon/SelectIcon.vue';
import RoomDialog from './components/RoomDialog.vue';
import VideoPreviewDialog from './components/VideoPreviewDialog.vue';
import {
  cropSignal,
  cropActive,
  cropConfirmSignal,
  cropCancelSignal,
  cropProportionValue,
  proportionOptions,
} from './composables/useCropSignal';
import {
  doodleSignal,
  doodleActive,
  doodleConfirmSignal,
  doodleCancelSignal,
  doodleUndoSignal,
  doodleClearSignal,
  doodlePenColor,
  doodlePenSize,
} from './composables/useDoodleSignal';
import { useNodeOperations } from './composables/useNodeOperations';
import { usePanelState } from './composables/usePanelState';
import { useFlowPersistence } from './composables/useFlowPersistence';

import { ElButton, ElTooltip } from 'element-plus';

const { addNodes, viewport, setViewport, zoomIn, zoomOut, fitView, findNode } = useVueFlow();
const route = useRoute();
const visible = ref(false);
const nodes = ref<Node[]>([]);
const list = [
  { title: '文本', type: 'text', desc: '剧本、分镜、提示词', icon: 'text' },
  { title: '图片', type: 'image', desc: '角色形象、分镜头', icon: 'image' },
  { title: '视频', type: 'video', desc: '动画、电影、样片', icon: 'video' },
  { title: '音频', type: 'audio', desc: '配音、音效、音乐', icon: 'audio' },
];
const edges = ref<Edge[]>([]);

// 当前选中节点 id
const selectedNodeId = ref<string | null>(null);

// 注册自定义节点类型
interface NodeTypes {
  [key: string]: Component | (() => Promise<Component>);
}
const nodeTypes: NodeTypes = {
  image: markRaw(ImageNode),
  text: markRaw(TextNode),
  video: markRaw(VideoNode),
  audio: markRaw(AudioNode),
};

// 响应式获取当前选中节点
const selectedNode = computed<any>(() => (selectedNodeId.value ? (findNode(selectedNodeId.value) ?? null) : null));

// ============ Composable: 面板状态 ============
const { panelType, topPanelIndex, showTopBar, panelForm, floatingPanelStyleTop, floatingPanelStyleBottom } = usePanelState(
  selectedNode,
  selectedNodeId
);

// ============ Composable: 节点操作 ============
const { mirror, onCropConfirm, onDoodleConfirm, delNodeBottomFile } = useNodeOperations(selectedNode, selectedNodeId, panelForm);

// ============ Composable: 持久化 ============
const DEMO_PROJECT_KEY = 'vue_flow_demo_project_id';
const resolveProjectId = (): string => {
  const param = route.params.projectId;
  if (param && !Array.isArray(param) && param.trim()) return param.trim();
  let demo = localStorage.getItem(DEMO_PROJECT_KEY);
  if (!demo) {
    demo = `flow_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    localStorage.setItem(DEMO_PROJECT_KEY, demo);
  }
  return demo;
};
const projectId = resolveProjectId();
const { restoreFlow, buildSnapshot } = useFlowPersistence(projectId, nodes, edges);

// ============ 上方面板按钮 ============
const showMap = ref(false);
const roomDialogRef: any = ref(null);
const showPreview = ref(false);
const srcList: any = ref([]);
const videoPreviewDialogRef:any = ref(false)
const handleTopBarBtns = (index: number) => {
  if (index === 1) {
    // 触发涂鸦信号，ImageNode 收到后进入涂鸦模式；切换上方面板为涂鸦工具条
    doodleSignal.value++;
    topPanelIndex.value = 1;
  }
  if (index === 3) {
    // 触发裁剪信号，ImageNode 收到后进入裁剪模式；切换上方面板为裁剪工具条
    cropSignal.value++;
    topPanelIndex.value = 3;
  }
  if (index === 4) {
    roomDialogRef.value?.open(selectedNode.value);
  }
  if (index === 6) {
    if(selectedNode.value.type === 'video') {
      videoPreviewDialogRef.value?.open(selectedNode.value)
    } else {
      srcList.value = [selectedNode.value.data?.url];
      showPreview.value = true;
    }
  }
};

// 裁剪工具条：确认 / 取消（通过共享信号通知 ImageNode）
const onCropConfirmBtn = () => {
  cropConfirmSignal.value++;
};
const onCropCancelBtn = () => {
  cropCancelSignal.value++;
};

// 裁剪结束后（cropActive 变 false）恢复上方面板为常规按钮
watch(cropActive, (active) => {
  if (!active && topPanelIndex.value === 3) {
    topPanelIndex.value = 0;
  }
});

// 涂鸦工具条：确认 / 取消 / 撤销 / 清空（通过共享信号通知 ImageNode）
const onDoodleConfirmBtn = () => {
  doodleConfirmSignal.value++;
};
const onDoodleCancelBtn = () => {
  doodleCancelSignal.value++;
};
const onDoodleUndoBtn = () => {
  doodleUndoSignal.value++;
};
const onDoodleClearBtn = () => {
  doodleClearSignal.value++;
};

// 涂鸦结束后（doodleActive 变 false）恢复上方面板为常规按钮 + 清空涂鸦提交面板内容
const doodleEditorContent = ref('');
const doodleSelectValue = ref('');
watch(doodleActive, (active) => {
  if (!active && topPanelIndex.value === 1) {
    topPanelIndex.value = 0;
  }
  // 面板消失即清空，不保存内容
  if (!active) {
    doodleEditorContent.value = '';
    doodleSelectValue.value = '';
  }
});

// 涂鸦提交：收集编辑器内容 + 下拉值
const doodleSubmit = () => {
  const payload = {
    content: doodleEditorContent.value,
    selectValue: doodleSelectValue.value,
  };
  console.log('涂鸦提交内容', payload);
};

// ============ 画布缩放控制 ============
const zoomPercent = computed(() => Math.round(viewport.value.zoom * 100) + '%');
const onZoomTo = (percent: number) => {
  setViewport({ ...viewport.value, zoom: percent / 100 }, { duration: 300 });
};
const onFitView = () => fitView({ duration: 300, padding: 0.2 });
const onZoomCommand = (cmd: string) => {
  if (cmd === 'fit') onFitView();
  else onZoomTo(Number(cmd));
};

// ============ 节点交互 ============
const onNodeClick = ({ node }: any) => {
  selectedNodeId.value = node.id;
};
const onDrag = () => {
  selectedNodeId.value = null;
};
const onDragStop = ({ node }: any) => {
  selectedNodeId.value = node.id;
};
const onPaneClick = () => {
  selectedNodeId.value = null;
  topPanelIndex.value = 0;
};
function generateRandomNode(item: any) {
  return {
    id: Math.random().toString(),
    type: item.type,
    position: { x: 740, y: 250 },
    label: 'Random Node',
    connectable: true,
    data: { hello: 'world', label: item.title, title: item.title },
  };
}
function onAddNode(item: any) {
  visible.value = false;
  addNodes(generateRandomNode(item));
}
const onNodeAdded = (nodeId: string) => {
  selectedNodeId.value = nodeId;
};
const onUploadSuccess = () => {
  panelType.value = null;
};

onMounted(restoreFlow);

const getData = () => {
  console.log(11111, buildSnapshot());
};
</script>

<template>
  <div class="flow-wrapper w-full h-full">
    <VueFlow
      :nodes="nodes"
      :edges="edges"
      :max-zoom="8"
      :zoomActivationKeyCode="'Control'"
      :zoomOnScroll="false"
      :panOnScroll="true"
      :node-types="nodeTypes"
      @node-click="onNodeClick"
      @pane-click="onPaneClick"
      @node-drag="onDrag"
      @node-drag-stop="onDragStop"
      class="bg-000"
    >
      <Background :variant="BackgroundVariant.Dots" :gap="24" :size="0.8" />
      <template #node-special="specialNodeProps">
        <SpecialNode v-bind="specialNodeProps" />
      </template>

      <template #edge-special="specialEdgeProps">
        <SpecialEdge v-bind="specialEdgeProps" />
      </template>

      <template #node-text="textNodeProps">
        <TextNode v-bind="textNodeProps" @node-added="onNodeAdded" @upload-success="onUploadSuccess" />
      </template>

      <template #node-image="imageNodeProps">
        <ImageNode
          v-bind="imageNodeProps"
          @node-added="onNodeAdded"
          @upload-success="onUploadSuccess"
          @crop-confirm="onCropConfirm"
          @doodle-confirm="onDoodleConfirm"
        />
      </template>

      <template #node-video="videoNodeProps">
        <VideoNode v-bind="videoNodeProps" @node-added="onNodeAdded" @upload-success="onUploadSuccess" />
      </template>

      <template #node-audio="audioNodeProps">
        <AudioNode v-bind="audioNodeProps" @node-added="onNodeAdded" @upload-success="onUploadSuccess" />
      </template>

      <Panel position="top-left" class="left-center-panel">
        <div class="bg-333 p-8 round-6 flex-center flex-col gap-14">
          <ElTooltip v-model:visible="visible" :show-arrow="false" placement="right" :hide-after="0">
            <template #content>
              <div class="mb-10 color-999">添加节点</div>
              <div class="flex flex-col gap-10 pb-10">
                <NodeTypeItem v-for="(item, index) in list" :key="index" :item="item" class="pointer" @click.stop="onAddNode(item)" />
              </div>
            </template>
            <div class="color-fff w-36 h-36 bg-fff round-6 fs-20 flex-center pointer add-btn" :class="{ 'is-active': visible }">
              <i class="icon-wrapper color-000 lh-10"><SvgIcon name="add" color="#333" :size="14" /></i>
            </div>
          </ElTooltip>
          <div class="w-20 bg-666" style="height: 1px"></div>
          <ElTooltip :show-arrow="false" placement="right" :hide-after="0">
            <template #content>
              <span>我的空间</span>
            </template>
            <div class="color-fff w-36 h-36 round-6 fs-20 flex-center pointer mt-6 room-btn">
              <SvgIcon name="room" color="#aaa" :size="24" />
            </div>
          </ElTooltip>
        </div>
      </Panel>

      <!-- 上方面板：多按钮组件（选中 + 已有文件时显示，屏幕空间不缩放） -->
      <Panel v-if="showTopBar" position="top-left" class="color-fff fixed" :style="floatingPanelStyleTop">
        <section v-if="selectedNode.type === 'image'">
          <section v-if="topPanelIndex === 0" class="top-bar flex items-center gap-6 round-6 p-4">
            <div class="analog-btn flex-center gap-4 px-10 py-6 pointer w-120" @click="handleTopBarBtns(1)">
              <SvgIcon name="redraw" :size="24" />
              <span>局部重绘</span>
            </div>
            <div class="analog-btn flex-center gap-4 px-10 py-6 pointer w-80" @click="handleTopBarBtns(2)">
              <SvgIcon name="HD" :size="24" /> 高清
            </div>
            <div class="analog-btn flex-center gap-4 px-10 py-6 pointer w-80" @click="handleTopBarBtns(3)">
              <SvgIcon name="caijian" :size="24" /> 裁剪
            </div>
            <el-dropdown placement="bottom" trigger="click" effect="dark" :show-arrow="false">
              <div class="analog-btn flex-center gap-4 px-10 py-6 pointer color-fff w-120">
                <SvgIcon name="mirror" :size="24" />
                <span class="mr-20">镜像</span>
                <SelectIcon color="#fff" />
              </div>
              <template #dropdown>
                <el-dropdown-menu style="background: #222" class="p-6">
                  <el-dropdown-item @click="mirror('vertical')">垂直镜像</el-dropdown-item>
                  <el-dropdown-item @click="mirror('horizontal')">水平镜像</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            <span class="color-666 lh-10">|</span>
            <div class="analog-btn flex-center px-8 py-6 pointer" @click="handleTopBarBtns(4)" title="添加到空间">
              <SvgIcon name="room" :size="28" />
            </div>
            <div class="analog-btn flex-center px-8 py-6 pointer" @click="handleTopBarBtns(5)" title="下载">
              <SvgIcon name="download" :size="26" />
            </div>
            <div class="analog-btn flex-center px-8 py-6 pointer" @click="handleTopBarBtns(6)" title="全屏">
              <SvgIcon name="fullScreen" :size="24" />
            </div>
          </section>
          <!-- 涂鸦工具条：颜色 / 粗细 / 取消 / 撤销 / 清空 / 确定（屏幕空间，不随画布缩放） -->
          <section v-else-if="topPanelIndex === 1" class="top-bar flex items-center gap-6 round-6 p-4">
            <input type="color" v-model="doodlePenColor" title="画笔颜色" class="doodle-color" />
            <SvgIcon name="fineness" :size="22" color="#fff" />
            <input type="range" v-model="doodlePenSize" min="2" max="30" title="画笔粗细" class="doodle-range" />
            <span class="color-999 fs-12">{{ doodlePenSize }}px</span>
            <span class="color-666 lh-10">|</span>
            <div class="analog-btn flex-center px-10 py-8 pointer" @click="onDoodleUndoBtn" title="撤销">
              <SvgIcon name="undo" :size="22" color="#fff" />
            </div>
            <div class="analog-btn flex-center px-10 py-8 pointer" @click="onDoodleClearBtn" title="清空涂鸦">
              <SvgIcon name="clear" :size="22" color="#fff" />
            </div>
            <span class="color-666 lh-10">|</span>
            <div class="analog-btn flex-center px-10 py-8 pointer" @click="onDoodleCancelBtn" title="取消">
              <SvgIcon name="close" :size="22" color="#fff" />
            </div>
            <div class="analog-btn flex-center px-10 py-8 pointer color-fff bg-333 round-6 w-60" @click="onDoodleConfirmBtn">确定</div>
          </section>
          <!-- 裁剪工具条：取消 / 比例选择 / 确定（屏幕空间，不随画布缩放） -->
          <section v-else-if="topPanelIndex === 3" class="top-bar flex items-center gap-6 round-6 p-4">
            <div class="analog-btn flex-center px-10 py-8 pointer" @click="onCropCancelBtn">
              <SvgIcon name="close" :size="22" color="#fff" />
            </div>
            <el-select v-model="cropProportionValue" effect="dark" class="w-110" :suffix-icon="SelectIcon">
              <el-option v-for="item in proportionOptions" :key="item.value" :label="item.label" :value="item.value" class="elOption" />
            </el-select>
            <div class="analog-btn flex-center px-10 py-8 pointer color-fff bg-333 round-6 w-60" @click="onCropConfirmBtn">确定</div>
          </section>
        </section>
        <section v-if="selectedNode.type === 'video'">
          <section v-if="topPanelIndex === 0" class="top-bar flex items-center gap-6 round-6 p-4">
            <el-dropdown placement="bottom" trigger="click" effect="dark" :show-arrow="false">
              <div class="analog-btn flex-center gap-4 px-10 py-6 pointer color-fff w-120">
                <SvgIcon name="mirror" :size="24" />
                <span class="mr-20">抽帧</span>
                <SelectIcon color="#fff" />
              </div>
              <template #dropdown>
                <el-dropdown-menu style="background: #222" class="p-6">
                  <el-dropdown-item>抽取视频</el-dropdown-item>
                  <el-dropdown-item>抽取图片</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            <div class="analog-btn flex-center gap-4 px-10 py-6 pointer w-120">
              <SvgIcon name="redraw" :size="24" />
              <span>去字幕</span>
            </div>
            <div class="analog-btn flex-center gap-4 px-10 py-6 pointer w-80"><SvgIcon name="HD" :size="24" /> 高清</div>
            <span class="color-666 lh-10">|</span>
            <div class="analog-btn flex-center px-8 py-6 pointer" @click="handleTopBarBtns(5)" title="下载">
              <SvgIcon name="download" :size="26" />
            </div>
            <div class="analog-btn flex-center px-8 py-6 pointer" @click="handleTopBarBtns(6)" title="全屏">
              <SvgIcon name="fullScreen" :size="24" />
            </div>
          </section>
        </section>
      </Panel>

      <!-- 下方面板：Panel1 / Panel2（屏幕空间不缩放） -->
      <Panel v-if="panelType || doodleActive" position="top-left" class="color-fff fixed" :style="floatingPanelStyleBottom">
        <!-- Panel1：未上传时的编辑面板 -->
        <section v-if="panelType === 'editor'" class="bg-111 round-6 p-10 flex flex-col gap-10">
          <div class="flex gap-10">
            <div class="w-60 h-60 bg-333 round-6"></div>
            <div v-if="panelForm.imgUrl || panelForm.videoUrl" class="relative">
              <span
                class="absolute w-14 h-14 bg-666 round-20 flex-center text-fff z-1 pointer lh-14 close-x"
                style="top: -5px; right: -5px"
                @click="delNodeBottomFile"
                >×</span
              >
              <div class="w-60 h-60 bg-333 round-6 hidden relative">
                <img :src="panelForm.imgUrl" class="w-full h-full" style="object-fit: cover" />
                <video :src="panelForm.videoUrl" class="w-full h-full" />
              </div>
            </div>
          </div>
          <Editor v-model="panelForm.content" />
          <div>
            <el-select v-model="panelForm.selectValue" class="w-200">
              <el-option label="灌灌灌灌灌" value="1"></el-option>
              <el-option label="发发发发发" value="2"></el-option>
            </el-select>
          </div>
        </section>
        <!-- Panel2：已有文件时的面板（内容待定） -->
        <section v-else-if="panelType === 'panel2'" class="bg-111 round-6 p-10">
          <div>Panel2 内容（待编辑）</div>
        </section>

        <!-- 涂鸦提交面板：仅涂鸦时出现，与上方面板涂鸦工具条同时显隐；不保存内容 -->
        <section v-if="doodleActive" class="bg-111 round-6 p-10 flex flex-col gap-10">
          <Editor v-model="doodleEditorContent" placeholder="请描述要如何调整画面" />
          <div>
            <el-select v-model="doodleSelectValue" class="w-200">
              <el-option label="灌灌灌灌灌" value="1"></el-option>
              <el-option label="发发发发发" value="2"></el-option>
            </el-select>
          </div>
          <div class="analog-btn flex-center px-10 py-6 pointer color-fff bg-333 round-6 w-fit" @click="doodleSubmit">涂鸦提交</div>
        </section>
      </Panel>

      <Panel position="bottom-left" class="control">
        <div class="flex gap-10">
          <div
            class="w-34 h-34 round-6 flex-center fs-20 lh-20 pointer color-fff control-btn"
            title="画布小地图"
            @click="showMap = !showMap"
          >
            <SvgIcon name="map" :size="20" color="#fff" />
          </div>
          <div class="w-34 h-34 round-6 flex-center fs-20 lh-20 pointer color-fff control-btn" title="缩小" @click="() => zoomOut()">
            <SvgIcon name="reduce" :size="12" color="#fff" />
          </div>
          <el-dropdown placement="bottom" trigger="click" effect="dark" :show-arrow="false" @command="onZoomCommand">
            <div class="w-34 h-34 round-6 flex-center fs-12 color-fff pointer control-btn" title="缩放选项">{{ zoomPercent }}</div>
            <template #dropdown>
              <el-dropdown-menu style="background: #222" class="p-6">
                <el-dropdown-item command="fit">适应屏幕</el-dropdown-item>
                <el-dropdown-item command="50">缩放至 50%</el-dropdown-item>
                <el-dropdown-item command="100">缩放至 100%</el-dropdown-item>
                <el-dropdown-item command="200">缩放至 200%</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <div class="w-34 h-34 round-6 flex-center fs-20 lh-20 color-fff pointer control-btn" title="放大" @click="() => zoomIn()">
            <SvgIcon name="add" :size="12" color="#fff" />
          </div>
        </div>
      </Panel>
      <MiniMap v-if="showMap" pannable zoomable style="bottom: 70px; left: 30px; right: auto" />
    </VueFlow>
    <!-- 添加到空间 -->
    <RoomDialog ref="roomDialogRef" />
    <!-- 图片预览 -->
    <el-image-viewer
      v-if="showPreview"
      :url-list="srcList"
      show-progress
      :min-scale="0.3"
      hide-on-click-modal
      :max-scale="5"
      @close="showPreview = false"
    />
    <!-- 视频预览 -->
     <VideoPreviewDialog ref="videoPreviewDialogRef" />
  </div>
</template>

<style>
/* import the necessary styles for Vue Flow to work */
@import '@vue-flow/core/dist/style.css';
/* import the default theme, this is optional but generally recommended */
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style scoped lang="scss">
:deep(.vue-flow__background circle) {
  fill: #444 !important;
}

.left-center-panel {
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  margin: 0 !important;
}

.control-btn {
  &:hover {
    background: #555;
    // color: #333;
  }
}

.add-btn {
  transition: all 0.3s;
   &:hover,
  &.is-active {
    background: #555;
    
    .icon-wrapper {
      transform: rotate(135deg);
      transition: transform 0.3s;
    }
  }
  
  .icon-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transform: rotate(0deg);
    transition: transform 0.3s;
  }
}
.room-btn {
  &:hover {
    background: #555;
  }
}

.control {
  left: 40px;
  bottom: 20px;
  background-color: #1a1a1a;
  box-shadow: 0 0 0 2px #333;
  padding: 4px;
  border-radius: 5px;
}

/* 上方多按钮组件 */
.top-bar {
  background: #1a1a1a;
  border: 1px solid #333;

  .analog-btn {
    &:hover {
      background: #333;
      border-radius: 5px;
    }
  }
}

.close-x {
  &:hover {
    background: #444;
  }
}

// 选中节点的样式
:deep(.vue-flow__node) {
  &.selected {
    border-radius: 6px;
    box-shadow: 0px 0px 1px 1px #888;
  }
}

:deep(.vue-flow__panel) {
  margin: 0;
}

:deep(.el-dropdown-menu__item) {
  color: #fff;

  &:hover {
    background: #333;
    color: #fff;
    border-radius: 5px;
  }

  &:focus {
    background: #333;
    color: #fff;
    border-radius: 5px;
  }
}

:deep(.vue-flow__handle) {
  border: none;
  // box-shadow: 0px 0px 0px 1px #fff;
  width: 20px;
  height: 50px;
  // line-height: 100px;
  font-size: 8px;
  color: #fff;
  border-radius: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: none;
}

:deep(.vue-flow__handle-right) {
  right: -10px;
}

:deep(.vue-flow__handle-left) {
  left: -10px;
}

:deep(.vue-flow__node) {
  &.selected {
    box-shadow: none;

    .image-row,
    .audio-row,
    .video-row,
    .text-row {
      box-shadow: 0px 0px 1px 1px #888;
      border-radius: 6px;
    }
  }
}

// 下拉框
:deep(.el-select__wrapper) {
  background: #1a1a1a;
  border: none;
  box-shadow: none;

  &:hover {
    box-shadow: none;
    background: #333;
  }

  .el-select__placeholder {
    color: #fff !important;
  }
}

// 裁剪比例下拉项
.elOption {
  background: #333;
  border-radius: 5px;
  color: #fff;
  &:hover {
    background: #555;
  }
}

// 涂鸦工具条：颜色 / 粗细控件
.doodle-color {
  width: 34px;
  height: 34px;
  padding: 2px;
  border: 1px solid #444;
  border-radius: 6px;
  cursor: pointer;
  background: #1a1a1a;
}
.doodle-range {
  width: 100px;
  cursor: pointer;
}

// 画布小地图
:deep(.vue-flow__minimap) {
  border-radius: 5px;
  // border: 1px solid #333 !important;
  background-color: #1a1a1a;
  overflow: hidden;
  svg {
    background: #333;
  }
}
:deep(.vue-flow__minimap-mask) {
  fill: #1a1a1a !important;
}
</style>
