Skip to content

Commit 5912947

Browse files
committed
refactor: module graph
1 parent 473f8ae commit 5912947

4 files changed

Lines changed: 866 additions & 8 deletions

File tree

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<script setup lang="ts" generic="T extends { id: string, imports: unknown[] }, I">
2+
import type { SessionContext } from '~~/shared/types'
3+
import { onMounted, unref, watch } from 'vue'
4+
import { generateLink, getModuleGraphLinkColor, useGraphDraggingScroll, useGraphZoom, useModuleGraph, useToggleGraphNodeExpanded } from '~/composables/moduleGraph'
5+
6+
const props = defineProps<{
7+
modules: T[]
8+
session: SessionContext
9+
}>()
10+
11+
const { isFirstCalculateGraph, childToParentMap, collapsedNodes, calculateGraph, container, width, height, scale, nodes, links, spacing, nodesRefMap } = useModuleGraph()
12+
const { isGrabbing, init: initGraphDraggingScroll } = useGraphDraggingScroll()
13+
const { zoomIn, zoomOut, ZOOM_MIN, ZOOM_MAX } = useGraphZoom()
14+
const { isGraphNodeToggling, toggleNode, expandAll, collapseAll } = useToggleGraphNodeExpanded({
15+
modules: props.modules,
16+
})
17+
18+
onMounted(() => {
19+
initGraphDraggingScroll()
20+
21+
watch(
22+
() => props.modules,
23+
() => {
24+
isFirstCalculateGraph.value = true
25+
collapsedNodes.clear()
26+
childToParentMap.clear()
27+
calculateGraph()
28+
},
29+
{ immediate: true },
30+
)
31+
})
32+
</script>
33+
34+
<template>
35+
<div
36+
ref="container"
37+
w-full h-screen of-scroll relative select-none
38+
:class="isGrabbing ? 'cursor-grabbing' : ''"
39+
>
40+
<div
41+
:style="{
42+
width: `${width * scale}px`,
43+
height: `${height * scale}px`,
44+
}"
45+
>
46+
<div
47+
flex="~ items-center justify-center"
48+
:style="{ transform: `scale(${scale})`, transformOrigin: '0 0' }"
49+
>
50+
<div
51+
absolute left-0 top-0
52+
:style="{
53+
width: `${width}px`,
54+
height: `${height}px`,
55+
}"
56+
class="bg-dots"
57+
/>
58+
<svg pointer-events-none absolute left-0 top-0 z-graph-link :width="width" :height="height">
59+
<g>
60+
<template v-for="link of links" :key="link.id">
61+
<slot name="link" :link="link" :d="generateLink<T, I>(link, spacing)!" :link-class="getModuleGraphLinkColor<T, I>(link)">
62+
<path
63+
:key="link.id"
64+
:d="generateLink<T, I>(link, spacing)!"
65+
:class="getModuleGraphLinkColor<T, I>(link)"
66+
fill="none"
67+
/>
68+
</slot>
69+
</template>
70+
</g>
71+
</svg>
72+
<template
73+
v-for="node of nodes"
74+
:key="node.data.module.id"
75+
>
76+
<template v-if="node.data.module.id !== '~root'">
77+
<div
78+
absolute
79+
class="group z-graph-node flex gap-1 items-center"
80+
:style="{
81+
left: `${node.x}px`,
82+
top: `${node.y}px`,
83+
transform: 'translate(-50%, -50%)',
84+
}"
85+
>
86+
<div
87+
flex="~ items-center gap-1"
88+
bg-glass
89+
border="~ base rounded"
90+
class="group-hover:bg-active block px2 p1"
91+
:style="{
92+
minWidth: `${unref(spacing.width)}px`,
93+
maxWidth: `${unref(spacing.width)}px`,
94+
maxHeight: `${unref(spacing.height)}px`,
95+
overflow: 'hidden',
96+
transition: 'all 0.3s ease',
97+
}"
98+
>
99+
<slot :node="node" :nodes-ref-map="nodesRefMap" />
100+
</div>
101+
102+
<!-- Expand/Collapse Button -->
103+
<div class="w-4">
104+
<button
105+
v-if="node.data.hasChildren"
106+
w-4
107+
h-4
108+
rounded-full
109+
flex="items-center justify-center"
110+
text-xs
111+
border="~ active"
112+
class="flex cursor-pointer z-graph-node-active bg-base"
113+
:disabled="isGraphNodeToggling"
114+
:class="{ 'cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
115+
:title="node.data.expanded ? 'Collapse' : 'Expand'"
116+
@click.stop="toggleNode(node.data.module.id)"
117+
>
118+
<div
119+
class="text-primary h-4"
120+
:class="[
121+
node.data.expanded ? 'i-ph-minus' : 'i-ph-plus',
122+
]"
123+
transition="transform duration-200"
124+
/>
125+
</button>
126+
</div>
127+
</div>
128+
</template>
129+
</template>
130+
</div>
131+
</div>
132+
<div
133+
fixed right-6 bottom-6 z-panel-nav flex="~ col gap-2 items-center"
134+
>
135+
<div w-10 flex="~ items-center justify-center">
136+
<DisplayTimeoutView :content="`${Math.round(scale * 100)}%`" class="text-sm" />
137+
</div>
138+
139+
<div bg-glass rounded-full border border-base shadow flex="~ col gap-1 p1">
140+
<button
141+
v-tooltip.left="'Expand All'"
142+
w-10 h-10 rounded-full hover:bg-active op-fade
143+
hover:op100 flex="~ items-center justify-center"
144+
:disabled="isGraphNodeToggling"
145+
:class="{ 'op50 cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
146+
title="Expand All"
147+
@click="expandAll()"
148+
>
149+
<div class="i-carbon:expand-categories" />
150+
</button>
151+
<button
152+
v-tooltip.left="'Collapse All'"
153+
w-10 h-10 rounded-full hover:bg-active op-fade
154+
hover:op100 flex="~ items-center justify-center"
155+
:disabled="isGraphNodeToggling"
156+
:class="{ 'op50 cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
157+
title="Collapse All"
158+
@click="collapseAll()"
159+
>
160+
<div class="i-carbon:collapse-categories" />
161+
</button>
162+
163+
<div border="t base" my1 />
164+
165+
<button
166+
v-tooltip.left="'Zoom In (Ctrl + =)'"
167+
:disabled="scale >= ZOOM_MAX"
168+
w-10 h-10 rounded-full hover:bg-active op-fade
169+
hover:op100 disabled:op20 disabled:bg-none
170+
disabled:cursor-not-allowed
171+
flex="~ items-center justify-center"
172+
title="Zoom In (Ctrl + =)"
173+
@click="zoomIn()"
174+
>
175+
<div i-ph-magnifying-glass-plus-duotone />
176+
</button>
177+
<button
178+
v-tooltip.left="'Zoom Out (Ctrl + -)'"
179+
:disabled="scale <= ZOOM_MIN"
180+
w-10 h-10 rounded-full hover:bg-active op-fade hover:op100
181+
disabled:op20 disabled:bg-none disabled:cursor-not-allowed
182+
flex="~ items-center justify-center"
183+
title="Zoom Out (Ctrl + -)"
184+
@click="zoomOut()"
185+
>
186+
<div i-ph-magnifying-glass-minus-duotone />
187+
</button>
188+
</div>
189+
</div>
190+
</div>
191+
</template>

0 commit comments

Comments
 (0)