@@ -39,9 +39,18 @@ const sectionList = computed(() => {
3939 .sort ((a , b ) => a .order - b .order )
4040})
4141
42+ const fileSearch = ref (' ' )
43+
4244const filteredChanges = computed (() => {
43- if (fileFilter .value === ' all' ) return props .allChanges
44- return props .allChanges .filter (f => f .type === fileFilter .value )
45+ let files = props .allChanges
46+ if (fileFilter .value !== ' all' ) {
47+ files = files .filter (f => f .type === fileFilter .value )
48+ }
49+ if (fileSearch .value .trim ()) {
50+ const query = fileSearch .value .trim ().toLowerCase ()
51+ files = files .filter (f => f .path .toLowerCase ().includes (query ))
52+ }
53+ return files
4554})
4655
4756function getSemverBadgeClass(semverDiff : string | null | undefined ): string {
@@ -185,33 +194,51 @@ function handleFileSelect(file: FileChange) {
185194 />
186195 </summary >
187196
188- <div class =" border-b border-border px-3 py-2 shrink-0 flex items-center justify-end" >
189- <select
190- v-model =" fileFilter"
191- :aria-label =" $t('compare.filter_files_label')"
192- class =" text-[10px] px-2 py-1 bg-bg-subtle border border-border rounded font-mono cursor-pointer hover:border-border-hover transition-colors"
193- >
194- <option value =" all" >
195- {{ $t('compare.file_filter_option.all', { count: allChanges.length }) }}
196- </option >
197- <option value =" added" >
198- {{ $t('compare.file_filter_option.added', { count: compare.stats.filesAdded }) }}
199- </option >
200- <option value =" removed" >
201- {{ $t('compare.file_filter_option.removed', { count: compare.stats.filesRemoved }) }}
202- </option >
203- <option value =" modified" >
204- {{ $t('compare.file_filter_option.modified', { count: compare.stats.filesModified }) }}
205- </option >
206- </select >
197+ <div class =" border-b border-border px-3 py-2 shrink-0 space-y-2" >
198+ <div class =" relative" >
199+ <span
200+ class =" absolute left-2 top-1/2 -translate-y-1/2 i-carbon-search w-3 h-3 text-fg-subtle pointer-events-none"
201+ />
202+ <input
203+ v-model =" fileSearch"
204+ type =" search"
205+ :placeholder =" $t('compare.search_files_placeholder')"
206+ :aria-label =" $t('compare.search_files_placeholder')"
207+ class =" w-full text-[11px] pl-6.5 pr-2 py-1 bg-bg-subtle border border-border rounded font-mono placeholder:text-fg-subtle transition-colors hover:border-border-hover focus:border-accent focus:outline-none"
208+ />
209+ </div >
210+ <div class =" flex items-center justify-end" >
211+ <select
212+ v-model =" fileFilter"
213+ :aria-label =" $t('compare.filter_files_label')"
214+ class =" text-[10px] px-2 py-1 bg-bg-subtle border border-border rounded font-mono cursor-pointer hover:border-border-hover transition-colors"
215+ >
216+ <option value =" all" >
217+ {{ $t('compare.file_filter_option.all', { count: allChanges.length }) }}
218+ </option >
219+ <option value =" added" >
220+ {{ $t('compare.file_filter_option.added', { count: compare.stats.filesAdded }) }}
221+ </option >
222+ <option value =" removed" >
223+ {{ $t('compare.file_filter_option.removed', { count: compare.stats.filesRemoved }) }}
224+ </option >
225+ <option value =" modified" >
226+ {{
227+ $t('compare.file_filter_option.modified', { count: compare.stats.filesModified })
228+ }}
229+ </option >
230+ </select >
231+ </div >
207232 </div >
208233
209234 <div class =" flex-1 overflow-y-auto min-h-0" >
210235 <div v-if =" filteredChanges.length === 0" class =" p-8 text-center text-xs text-fg-muted" >
211236 {{
212- fileFilter === 'all'
213- ? $t('compare.no_files_all')
214- : $t('compare.no_files_filtered', { filter: $t(`compare.filter.${fileFilter}`) })
237+ fileSearch.trim()
238+ ? $t('compare.no_files_search', { query: fileSearch.trim() })
239+ : fileFilter === 'all'
240+ ? $t('compare.no_files_all')
241+ : $t('compare.no_files_filtered', { filter: $t(`compare.filter.${fileFilter}`) })
215242 }}
216243 </div >
217244
0 commit comments