Skip to content

Commit e679ab2

Browse files
committed
feat: trck graph
1 parent fe8d2dc commit e679ab2

File tree

18 files changed

+897
-50
lines changed

18 files changed

+897
-50
lines changed

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
package-manager-strict=false
2+
public-hoist-pattern[]=@antv/*

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@
2424
"@antv/g6": "5.0.43",
2525
"@eslint/js": "9.21.0",
2626
"@gkd-kit/api": "0.6.0",
27-
"@gkd-kit/selector": "0.5.13",
27+
"@gkd-kit/selector": "0.5.21",
2828
"@gkd-kit/wasm_matches": "0.0.1",
2929
"@tsconfig/node20": "20.1.4",
3030
"@types/file-saver": "2.0.7",
3131
"@types/fs-extra": "11.0.4",
32+
"@types/lodash-es": "4.17.12",
3233
"@types/node": "22.13.5",
3334
"@vitejs/plugin-legacy": "6.0.1",
3435
"@vitejs/plugin-vue": "5.2.1",
@@ -52,6 +53,7 @@
5253
"jszip": "3.10.1",
5354
"lint-staged": "15.4.3",
5455
"localforage": "1.10.0",
56+
"lodash-es": "4.17.21",
5557
"naive-ui": "2.41.0",
5658
"normalize.css": "8.0.1",
5759
"p-limit": "6.2.0",
@@ -76,9 +78,9 @@
7678
},
7779
"volta": {
7880
"node": "22.10.0",
79-
"pnpm": "10.4.1"
81+
"pnpm": "10.5.2"
8082
},
81-
"packageManager": "pnpm@10.4.1",
83+
"packageManager": "pnpm@10.5.2",
8284
"simple-git-hooks": {
8385
"pre-commit": "pnpm exec lint-staged"
8486
},

pnpm-lock.yaml

Lines changed: 11 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ body {
4949
.gkd_code,
5050
[gkd_code] {
5151
font-family:
52-
v-mono, SFMono-Regular, Menlo, Consolas, Courier, monospace !important;
52+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
53+
'Courier New', monospace !important;
5354
}
5455
5556
[direction-rtl],
@@ -99,7 +100,10 @@ body,
99100
#app {
100101
/* 禁止 iOS/Edge 滚动回弹效果 */
101102
overscroll-behavior: none;
103+
}
102104
105+
html,
106+
body {
103107
font-size: 14px;
104108
line-height: 20px;
105109
}

src/assets/svg/close.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/SelectorText.vue

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@
22
import { AstNode, Selector } from '@gkd-kit/selector';
33
import SelectorText from './SelectorText.vue';
44
import { getAstNodeClassName } from '@/utils/selector';
5+
import type { StyleValue } from 'vue';
56
67
const props = defineProps<{
7-
text: string;
8+
source: string;
89
node: AstNode<any>;
10+
getNodeStyle?: (node: AstNode<any>) => StyleValue;
911
}>();
1012
1113
const isRoot = computed(() => {
1214
return props.node.value instanceof Selector;
1315
});
1416
1517
const subText = computed(() => {
16-
return props.text.substring(props.node.start, props.node.end);
18+
return props.source.substring(props.node.start, props.node.end);
1719
});
1820
1921
interface ExtraNode {
@@ -22,11 +24,11 @@ interface ExtraNode {
2224
}
2325
2426
const getExtraText = (child: ExtraNode) => {
25-
return props.text.substring(child.start, child.end);
27+
return props.source.substring(child.start, child.end);
2628
};
2729
2830
const getExtraName = (child: ExtraNode) => {
29-
const t = props.text.substring(child.start, child.end).trim();
31+
const t = props.source.substring(child.start, child.end).trim();
3032
if (!t) {
3133
return 'Whitespace';
3234
}
@@ -78,23 +80,33 @@ const children = computed(() => {
7880
}
7981
return list;
8082
});
83+
84+
const getDataValue = (str: string) => {
85+
return str.length === 1 ? str : undefined;
86+
};
8187
</script>
8288
<template>
8389
<span
90+
class="SelectorText"
8491
:whitespace-pre-wrap="isRoot ? `` : undefined"
8592
:data-name="getAstNodeClassName(node)"
8693
:data-range="getRange(node)"
87-
:class="{
88-
SelectorText: isRoot,
89-
}"
94+
:data-value="getDataValue(subText)"
95+
:style="getNodeStyle?.(node)"
9096
>
9197
<template v-if="node.outChildren.length">
9298
<template v-for="child in children" :key="child.start">
93-
<SelectorText v-if="isAstNode(child)" :text="text" :node="child" />
99+
<SelectorText
100+
v-if="isAstNode(child)"
101+
:source="source"
102+
:node="child"
103+
:getNodeStyle="getNodeStyle"
104+
/>
94105
<span
95106
v-else
96107
:data-name="getExtraName(child)"
97108
:data-range="getRange(child)"
109+
:data-value="getDataValue(getExtraText(child))"
98110
>
99111
{{ getExtraText(child) }}
100112
</span>

src/components/TrackCard.vue

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<script setup lang="ts">
2+
import SelectorText from '@/components/SelectorText.vue';
3+
import TrackTreeGraph from '@/components/TrackGraph.vue';
4+
import { buildEmptyFn, colorList } from '@/utils/others';
5+
import { type ResolvedSelector } from '@/utils/selector';
6+
import type { RawNode } from '@/utils/types';
7+
import type { AstNode, QueryResult } from '@gkd-kit/selector';
8+
import { UnitSelectorExpression } from '@gkd-kit/selector';
9+
import type { StyleValue } from 'vue';
10+
11+
const props = withDefaults(
12+
defineProps<{
13+
nodes: RawNode[];
14+
queryResult: QueryResult<RawNode>;
15+
selector: ResolvedSelector;
16+
onClose?: () => void;
17+
}>(),
18+
{
19+
onClose: buildEmptyFn,
20+
},
21+
);
22+
23+
const allUnitResults = computed(() => {
24+
if (!props.queryResult) return [];
25+
return props.queryResult.unitResults.asJsReadonlyArrayView().concat();
26+
});
27+
28+
const singleUnitResults = computed(() => {
29+
return allUnitResults.value.filter((v) => !v.context.prev);
30+
});
31+
32+
const showUnitResults = computed(() => {
33+
return allUnitResults.value.filter((v) => v.context.prev);
34+
});
35+
36+
const filterUnitResults = shallowRef<QueryResult.UnitResult<RawNode>[]>([]);
37+
watchEffect(() => {
38+
filterUnitResults.value = showUnitResults.value;
39+
});
40+
const switchUnitResult = (unitResult: QueryResult.UnitResult<RawNode>) => {
41+
if (filterUnitResults.value.includes(unitResult)) {
42+
filterUnitResults.value = filterUnitResults.value.filter(
43+
(v) => v !== unitResult,
44+
);
45+
} else {
46+
filterUnitResults.value = filterUnitResults.value.concat(unitResult);
47+
}
48+
};
49+
50+
const getNodeStyle = (node: AstNode<any>): StyleValue => {
51+
const value = node.value;
52+
if (
53+
value instanceof UnitSelectorExpression &&
54+
allUnitResults.value.some((u) => u.expression === value) &&
55+
!node.outChildren.some((v) => v.value instanceof UnitSelectorExpression)
56+
) {
57+
return {
58+
outline: '1px solid #00F',
59+
};
60+
}
61+
return '';
62+
};
63+
</script>
64+
<template>
65+
<div
66+
class="TrackCard"
67+
flex
68+
flex-col
69+
h-full
70+
p-12px
71+
box-border
72+
gap-8px
73+
overflow-hidden
74+
>
75+
<div flex justify-between items-center>
76+
<div text="20px/28px" font-bold>选择器路径视图</div>
77+
<NButton text @click="onClose">
78+
<SvgIcon name="close" h="20px" />
79+
</NButton>
80+
</div>
81+
<div flex-1 flex gap-12px overflow-hidden>
82+
<div self-stretch flex="[2]">
83+
<TrackTreeGraph
84+
v-if="nodes.length && queryResult"
85+
:nodes="nodes"
86+
:queryResult="queryResult"
87+
:showUnitResults="showUnitResults"
88+
:filterUnitResults="filterUnitResults"
89+
class="h-[calc(100%-2px)] b-1px b-solid"
90+
/>
91+
<div relative pointer-events-none z-1>
92+
<div absolute left-8px bottom-8px text="12px/14px #6C6E71">
93+
*为简化视图已隐藏无关节点
94+
</div>
95+
</div>
96+
</div>
97+
<NScrollbar class="self-stretch flex-1">
98+
<div mb-24px break-all px-4px py-2px leading-20px bg="#eee" gkd_code>
99+
<SelectorText
100+
class="gkd_code"
101+
:source="selector.source"
102+
:node="selector.ast"
103+
:getNodeStyle="getNodeStyle"
104+
/>
105+
</div>
106+
<div flex flex-col gap-12px>
107+
<div v-if="singleUnitResults.length" flex gap-8px>
108+
<div
109+
v-for="(unitResult, i) in singleUnitResults"
110+
:key="i"
111+
break-all
112+
px-4px
113+
py-2px
114+
gkd_code
115+
b-1px
116+
b-solid
117+
b="#ccc"
118+
>
119+
<SelectorText
120+
class="gkd_code"
121+
:source="selector.source"
122+
:node="selector.findAst(unitResult.expression)"
123+
/>
124+
</div>
125+
</div>
126+
<div
127+
v-for="(unitResult, i) in showUnitResults"
128+
:key="i"
129+
cursor-pointer
130+
break-all
131+
px-4px
132+
py-2px
133+
gkd_code
134+
b-1px
135+
b-solid
136+
transition-colors
137+
@click="switchUnitResult(unitResult)"
138+
:style="{
139+
borderColor: colorList[i % colorList.length],
140+
backgroundColor: filterUnitResults.includes(unitResult)
141+
? '#eee'
142+
: undefined,
143+
}"
144+
>
145+
<div
146+
inline-block
147+
align-middle
148+
size-16px
149+
:style="{
150+
backgroundColor: colorList[i % colorList.length],
151+
}"
152+
></div>
153+
<span pl-4px></span>
154+
<SelectorText
155+
class="gkd_code"
156+
:source="selector.source"
157+
:node="selector.findAst(unitResult.expression)"
158+
/>
159+
</div>
160+
</div>
161+
</NScrollbar>
162+
</div>
163+
</div>
164+
</template>

0 commit comments

Comments
 (0)