@@ -5,29 +5,28 @@ import { useRoute, useRouter } from '#app/composables/router'
5
5
import { clearUndefined , toArray } from ' @antfu/utils'
6
6
import { computedWithControl , debouncedWatch } from ' @vueuse/core'
7
7
import Fuse from ' fuse.js'
8
- import { computed , reactive } from ' vue'
8
+ import { computed , ref } from ' vue'
9
9
import { settings } from ' ~/state/settings'
10
10
import { parseReadablePath } from ' ~/utils/filepath'
11
- import { getFileTypeFromModuleId , getFileTypeFromName } from ' ~/utils/icon'
11
+ import { getFileTypeFromModuleId , ModuleTypeRules } from ' ~/utils/icon'
12
12
13
13
const props = defineProps <{
14
14
session: SessionContext
15
15
}>()
16
16
17
- interface Filters {
18
- search: string
19
- file_types: string [] | null
20
- node_modules: string [] | null
21
- }
22
-
23
17
const route = useRoute ()
24
18
const router = useRouter ()
25
19
26
- const filters = reactive <Filters >({
20
+ const searchValue = ref <{
21
+ search: string
22
+ selected: string [] | null
23
+ [key : string ]: any
24
+ }>({
27
25
search: (route .query .search || ' ' ) as string ,
28
- file_types : (route .query .file_types ? toArray (route .query .file_types ) : null ) as string [] | null ,
26
+ selected : (route .query .file_types ? toArray (route .query .file_types ) : null ) as string [] | null ,
29
27
node_modules: (route .query .node_modules ? toArray (route .query .node_modules ) : null ) as string [] | null ,
30
28
})
29
+
31
30
const moduleViewTypes = [
32
31
{
33
32
label: ' List' ,
@@ -47,12 +46,12 @@ const moduleViewTypes = [
47
46
] as const
48
47
49
48
debouncedWatch (
50
- filters ,
49
+ searchValue . value ,
51
50
(f ) => {
52
51
const query: any = {
53
52
... route .query ,
54
53
search: f .search || undefined ,
55
- file_types: f .file_types || undefined ,
54
+ file_types: f .selected || undefined ,
56
55
node_modules: f .node_modules || undefined ,
57
56
}
58
57
router .replace ({
@@ -72,6 +71,12 @@ const parsedPaths = computed(() => props.session.modulesList.map((mod) => {
72
71
}
73
72
}))
74
73
74
+ const searchFilterTypes = computed (() => {
75
+ return ModuleTypeRules .filter ((rule ) => {
76
+ return parsedPaths .value .some (mod => rule .match .test (mod .mod .id ))
77
+ })
78
+ })
79
+
75
80
// const allNodeModules = computed(() => {
76
81
// const nodeModules = new Set<string>()
77
82
// for (const mod of parsedPaths.value) {
@@ -81,45 +86,20 @@ const parsedPaths = computed(() => props.session.modulesList.map((mod) => {
81
86
// return nodeModules
82
87
// })
83
88
84
- const allFileTypes = computed (() => {
85
- const fileTypes = new Set <string >()
86
- for (const mod of parsedPaths .value ) {
87
- fileTypes .add (mod .type .name )
88
- }
89
- return fileTypes
90
- })
91
-
92
89
const filtered = computed (() => {
93
90
let modules = parsedPaths .value
94
- if (filters .file_types ) {
95
- modules = modules .filter (mod => filters .file_types ! .includes (mod .type .name ))
91
+ if (searchValue .value .selected ) {
92
+ modules = modules .filter ((mod ) => {
93
+ const type = getFileTypeFromModuleId (mod .mod .id )
94
+ return searchValue .value .selected ! .includes (type .name )
95
+ })
96
96
}
97
- if (filters .node_modules ) {
98
- modules = modules .filter (mod => mod .path .moduleName && filters .node_modules ! .includes (mod .path .moduleName ))
97
+ if (searchValue . value .node_modules ) {
98
+ modules = modules .filter (mod => mod .path .moduleName && searchValue . value .node_modules ! .includes (mod .path .moduleName ))
99
99
}
100
100
return modules .map (mod => ({ ... mod .mod , path: mod .path .path }))
101
101
})
102
102
103
- function isFileTypeSelected(type : string ) {
104
- return filters .file_types == null || filters .file_types .includes (type )
105
- }
106
-
107
- function toggleFileType(type : string ) {
108
- if (filters .file_types == null ) {
109
- filters .file_types = Array .from (allFileTypes .value )
110
- }
111
-
112
- if (filters .file_types .includes (type )) {
113
- filters .file_types = filters .file_types .filter (t => t !== type )
114
- }
115
- else {
116
- filters .file_types .push (type )
117
- }
118
- if (filters .file_types .length === allFileTypes .value .size ) {
119
- filters .file_types = null
120
- }
121
- }
122
-
123
103
const fuse = computedWithControl (
124
104
() => filtered .value ,
125
105
() => new Fuse (filtered .value , {
@@ -131,11 +111,11 @@ const fuse = computedWithControl(
131
111
)
132
112
133
113
const searched = computed (() => {
134
- if (filters . search === ' ' ) {
114
+ if (! searchValue . value . search ) {
135
115
return filtered .value
136
116
}
137
117
return fuse .value
138
- .search (filters .search )
118
+ .search (searchValue . value .search )
139
119
.map (r => r .item )
140
120
})
141
121
@@ -149,51 +129,25 @@ function toggleDisplay(type: ClientSettings['moduleGraphViewType']) {
149
129
150
130
<template >
151
131
<div relative max-h-screen of-hidden >
152
- <div flex =" col gap-2" absolute left-4 top-4 max-w-90vw border =" ~ base rounded-xl" bg-glass z-panel-nav >
153
- <div border =" b base" >
154
- <input
155
- v-model =" filters.search"
156
- p2 px4 w-full
157
- style =" outline : none "
158
- placeholder =" Search"
159
- >
160
- </div >
161
- <div flex =" ~ gap-2 wrap" p2 >
162
- <label
163
- v-for =" type of allFileTypes"
164
- :key =" type"
165
- border =" ~ base rounded-md" px2 py1
166
- flex =" ~ items-center gap-1"
167
- select-none
168
- :title =" type"
169
- :class =" isFileTypeSelected(type) ? 'bg-active' : 'grayscale op50'"
170
- >
171
- <input
172
- type =" checkbox"
173
- :checked =" isFileTypeSelected(type)"
174
- mr1
175
- @change =" toggleFileType(type)"
132
+ <div absolute left-4 top-4 z-panel-nav >
133
+ <DataSearchPanel v-model =" searchValue" :rules =" searchFilterTypes" >
134
+ <div flex =" ~ gap-2 items-center" p2 border =" t base" >
135
+ <span op50 pl2 text-sm >View as</span >
136
+ <button
137
+ v-for =" viewType of moduleViewTypes"
138
+ :key =" viewType.value"
139
+ btn-action
140
+ :class =" settings.moduleGraphViewType === viewType.value ? 'bg-active' : 'grayscale op50'"
141
+ @click =" toggleDisplay(viewType.value)"
176
142
>
177
- <div :class =" getFileTypeFromName(type).icon" icon-catppuccin />
178
- <div text-sm >{{ getFileTypeFromName(type).description }}</div >
179
- </label >
180
- </div >
181
- <div flex =" ~ gap-2 items-center" p2 border =" t base" >
182
- <span op50 pl2 text-sm >View as</span >
183
- <button
184
- v-for =" viewType of moduleViewTypes"
185
- :key =" viewType.value"
186
- btn-action
187
- :class =" settings.moduleGraphViewType === viewType.value ? 'bg-active' : 'grayscale op50'"
188
- @click =" toggleDisplay(viewType.value)"
189
- >
190
- <div :class =" viewType.icon" />
191
- {{ viewType.label }}
192
- </button >
193
- </div >
194
- <!-- TODO: should we add filters for node_modules? -->
195
- <!-- {{ allNodeModules }} -->
143
+ <div :class =" viewType.icon" />
144
+ {{ viewType.label }}
145
+ </button >
146
+ </div >
147
+ </DataSearchPanel >
196
148
</div >
149
+ <!-- TODO: should we add filters for node_modules? -->
150
+ <!-- {{ allNodeModules }} -->
197
151
<template v-if =" settings .moduleGraphViewType === ' list' " >
198
152
<div of-auto h-screen pt-45 >
199
153
<ModulesFlatList
0 commit comments