|
1 | 1 | <script lang="ts"> |
| 2 | + import { debounce } from "lodash"; |
2 | 3 | import { Menu, type App } from "obsidian"; |
3 | 4 | import { deleteFile } from "src/utils/delete-file"; |
4 | 5 | import { findDuplicateUrls } from "src/utils/find-duplicate-urls"; |
|
11 | 12 |
|
12 | 13 | const { obsidianApp }: AppProps = $props(); |
13 | 14 |
|
14 | | - let duplicateUrls: Map<string, string[]> = $state(new Map()); |
| 15 | + let duplicateUrlMap: Map<string, string[]> = $state(new Map()); |
| 16 | + let searchValue = $state(""); |
| 17 | +
|
| 18 | + let filteredDuplicateUrlMap = $derived( |
| 19 | + new Map( |
| 20 | + Array.from(duplicateUrlMap.entries()).filter(([_, files]) => |
| 21 | + files.some((file) => |
| 22 | + file.toLowerCase().includes(searchValue.toLowerCase()), |
| 23 | + ), |
| 24 | + ), |
| 25 | + ), |
| 26 | + ); |
| 27 | +
|
| 28 | + let duplicateUrlCount = $derived( |
| 29 | + Array.from(filteredDuplicateUrlMap.entries()).filter( |
| 30 | + ([_, files]) => files.length > 1, |
| 31 | + ).length, |
| 32 | + ); |
| 33 | +
|
| 34 | + const handleInputChange = debounce((event: Event) => { |
| 35 | + searchValue = (event.target as HTMLInputElement).value; |
| 36 | + }, 100); |
15 | 37 |
|
16 | 38 | function handleItemClick(filePath: string) { |
17 | 39 | openInNewTab(obsidianApp, filePath, true); |
|
33 | 55 | item.setTitle("Delete file"); |
34 | 56 | item.onClick(async () => { |
35 | 57 | await deleteFile(obsidianApp, filePath); |
36 | | - duplicateUrls = await findDuplicateUrls(obsidianApp); |
| 58 | + duplicateUrlMap = await findDuplicateUrls(obsidianApp); |
37 | 59 | }); |
38 | 60 | }); |
39 | 61 | menu.showAtMouseEvent(event); |
40 | 62 | } |
41 | 63 |
|
42 | 64 | onMount(async () => { |
43 | | - duplicateUrls = await findDuplicateUrls(obsidianApp); |
| 65 | + duplicateUrlMap = await findDuplicateUrls(obsidianApp); |
44 | 66 | }); |
45 | | -
|
46 | | - let duplicateUrlCount = $derived( |
47 | | - Array.from(duplicateUrls.entries()).filter( |
48 | | - ([_, files]) => files.length > 1, |
49 | | - ).length, |
50 | | - ); |
51 | 67 | </script> |
52 | 68 |
|
53 | 69 | <div> |
54 | 70 | <h1>Duplicate Finder</h1> |
55 | 71 | <p>Duplicate URLs: {duplicateUrlCount}</p> |
| 72 | + <input |
| 73 | + type="search" |
| 74 | + placeholder="Filter by file name..." |
| 75 | + value={searchValue} |
| 76 | + oninput={handleInputChange} |
| 77 | + /> |
| 78 | + <hr /> |
56 | 79 | <div class="accordion-list-container"> |
57 | | - {#each Array.from(duplicateUrls.entries()) as [url, files]} |
| 80 | + {#each Array.from(filteredDuplicateUrlMap.entries()) as [url, files]} |
58 | 81 | {#if files.length > 1} |
59 | 82 | <div class="accordion"> |
60 | 83 | <details> |
|
88 | 111 | font-size: 2rem; |
89 | 112 | } |
90 | 113 |
|
| 114 | + hr { |
| 115 | + margin: 1.1rem 0; |
| 116 | + } |
| 117 | +
|
91 | 118 | .accordion-item { |
92 | 119 | padding: 8px 16px; |
93 | 120 | border-bottom: 1px solid #e0e0e0; |
|
0 commit comments