alpha
Login
or
Join now
flo-bit.dev
/
atmo-tools
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
[READ-ONLY] Mirror of https://github.com/flo-bit/atmo-tools.
atmo.tools
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
fix
author
Florian
date
4 months ago
(Mar 3, 2026, 6:16 AM +0100)
commit
d1447aa2
d1447aa2baab0464fc9fdef272001bb207453200
parent
b9c47708
b9c477085c5d45ea91cd99a977e63da6b5d84bce
+208
-159
1 changed file
Expand all
Collapse all
Unified
Split
src
routes
search
Search.svelte
+208
-159
src/routes/search/Search.svelte
View file
Reviewed
···
85
85
</script>
86
86
87
87
<svelte:window
88
88
-
bind:scrollY={scrollY}
88
88
+
bind:scrollY
89
89
onkeydown={() => {
90
90
const tag = document.activeElement?.tagName;
91
91
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;
···
93
93
}}
94
94
/>
95
95
96
96
-
<a
97
97
-
href="/"
98
98
-
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 fixed top-4 left-4 z-50 inline-flex items-center gap-1 text-sm transition-colors"
99
99
-
>
100
100
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4">
101
101
-
<path fill-rule="evenodd" d="M17 10a.75.75 0 0 1-.75.75H5.612l4.158 3.96a.75.75 0 1 1-1.04 1.08l-5.5-5.25a.75.75 0 0 1 0-1.08l5.5-5.25a.75.75 0 1 1 1.04 1.08L5.612 9.25H16.25A.75.75 0 0 1 17 10Z" clip-rule="evenodd" />
102
102
-
</svg>
103
103
-
Back
104
104
-
</a>
96
96
+
<a
97
97
+
href="/"
98
98
+
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 fixed top-4 left-4 z-50 inline-flex items-center gap-1 text-sm transition-colors"
99
99
+
>
100
100
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4">
101
101
+
<path
102
102
+
fill-rule="evenodd"
103
103
+
d="M17 10a.75.75 0 0 1-.75.75H5.612l4.158 3.96a.75.75 0 1 1-1.04 1.08l-5.5-5.25a.75.75 0 0 1 0-1.08l5.5-5.25a.75.75 0 1 1 1.04 1.08L5.612 9.25H16.25A.75.75 0 0 1 17 10Z"
104
104
+
clip-rule="evenodd"
105
105
+
/>
106
106
+
</svg>
107
107
+
Back
108
108
+
</a>
105
109
106
106
-
<Navbar class="mx-2 py-3 h-auto max-w-xl flex-col items-start sm:mx-auto top-12 md:top-10">
107
107
-
<div class="mb-4 mx-2 flex items-baseline gap-2">
108
108
-
<span class="text-base-600 dark:text-base-400 text-sm font-medium">Search my</span>
109
109
-
<div class="flex gap-1">
110
110
-
{#each ALL_SOURCES as source}
111
111
-
<button
112
112
-
class="cursor-pointer rounded-full px-3 py-1 text-sm font-medium transition-colors {searchState.activeSource ===
113
113
-
source
114
114
-
? 'bg-accent-600 text-white'
115
115
-
: 'text-base-600 dark:text-base-400 hover:bg-base-200 dark:hover:bg-base-800'}"
116
116
-
onclick={() => handleSwitchSource(source)}
117
117
-
>
118
118
-
{SOURCE_LABELS[source]}
119
119
-
</button>
120
120
-
{/each}
121
121
-
</div>
110
110
+
<Navbar class="top-12 mx-2 h-auto max-w-xl flex-col items-start py-3 sm:mx-auto md:top-10">
111
111
+
<div class="mx-2 mb-4 flex items-baseline gap-2">
112
112
+
<div class="flex gap-1">
113
113
+
{#each ALL_SOURCES as source}
114
114
+
<button
115
115
+
class="cursor-pointer rounded-full px-3 py-1 text-sm font-medium transition-colors {searchState.activeSource ===
116
116
+
source
117
117
+
? 'bg-accent-600 text-white'
118
118
+
: 'text-base-600 dark:text-base-400 hover:bg-base-200 dark:hover:bg-base-800'}"
119
119
+
onclick={() => handleSwitchSource(source)}
120
120
+
>
121
121
+
{SOURCE_LABELS[source]}
122
122
+
</button>
123
123
+
{/each}
122
124
</div>
125
125
+
</div>
123
126
124
124
-
<div class="flex w-full items-center gap-2">
125
125
-
<Input
126
126
-
bind:ref={input}
127
127
-
bind:value={search}
128
128
-
class="w-full"
129
129
-
sizeVariant="lg"
130
130
-
placeholder={PLACEHOLDERS[searchState.activeSource]}
131
131
-
/>
132
132
-
<button
133
133
-
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 relative cursor-pointer p-2 transition-colors"
134
134
-
onclick={() => (showFilters = !showFilters)}
135
135
-
aria-label="Toggle filters"
127
127
+
<div class="flex w-full items-center gap-2">
128
128
+
<Input
129
129
+
bind:ref={input}
130
130
+
bind:value={search}
131
131
+
class="w-full"
132
132
+
sizeVariant="lg"
133
133
+
placeholder={PLACEHOLDERS[searchState.activeSource]}
134
134
+
/>
135
135
+
<button
136
136
+
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 relative cursor-pointer p-2 transition-colors"
137
137
+
onclick={() => (showFilters = !showFilters)}
138
138
+
aria-label="Toggle filters"
139
139
+
>
140
140
+
<svg
141
141
+
xmlns="http://www.w3.org/2000/svg"
142
142
+
viewBox="0 0 20 20"
143
143
+
fill="currentColor"
144
144
+
class="size-5"
136
145
>
137
137
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
138
138
-
<path fill-rule="evenodd" d="M2.628 1.601C5.028 1.206 7.49 1 10 1s4.973.206 7.372.601a.75.75 0 0 1 .628.74v2.288a2.25 2.25 0 0 1-.659 1.59l-4.682 4.683a2.25 2.25 0 0 0-.659 1.59v3.037c0 .684-.31 1.33-.844 1.757l-1.937 1.55A.75.75 0 0 1 8 18.25v-5.757a2.25 2.25 0 0 0-.659-1.591L2.659 6.22A2.25 2.25 0 0 1 2 4.629V2.34a.75.75 0 0 1 .628-.74Z" clip-rule="evenodd" />
139
139
-
</svg>
140
140
-
{#if hasActiveFilters}
141
141
-
<span class="bg-accent-600 absolute top-1 right-1 size-2 rounded-full"></span>
142
142
-
{/if}
143
143
-
</button>
144
144
-
</div>
145
145
-
146
146
-
{#if showFilters}
147
147
-
<div class="mt-3 flex w-full flex-col gap-3 px-2">
148
148
-
{#if searchState.activeSource !== 'posts'}
149
149
-
<div class="flex flex-col gap-1.5">
150
150
-
<div class="flex items-center gap-2">
151
151
-
<label class="text-base-500 dark:text-base-400 text-xs w-16 shrink-0">Handle</label>
152
152
-
<AtprotoHandlePopup
153
153
-
bind:value={handleInput}
154
154
-
onselected={(actor) => {
155
155
-
if (!filters.handles.includes(actor.handle)) {
156
156
-
filters.handles = [...filters.handles, actor.handle];
157
157
-
}
158
158
-
handleInput = '';
159
159
-
}}
160
160
-
/>
161
161
-
</div>
162
162
-
{#if filters.handles.length > 0}
163
163
-
<div class="ml-18 flex flex-wrap gap-1">
164
164
-
{#each filters.handles as handle}
165
165
-
<span class="bg-base-200 dark:bg-base-800 text-base-700 dark:text-base-300 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs">
166
166
-
@{handle}
167
167
-
<button
168
168
-
class="text-base-500 hover:text-base-800 dark:hover:text-base-100 cursor-pointer"
169
169
-
onclick={() => (filters.handles = filters.handles.filter((h) => h !== handle))}
170
170
-
aria-label="Remove {handle}"
171
171
-
>
172
172
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-3">
173
173
-
<path d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z" />
174
174
-
</svg>
175
175
-
</button>
176
176
-
</span>
177
177
-
{/each}
178
178
-
</div>
179
179
-
{/if}
180
180
-
</div>
181
181
-
{/if}
146
146
+
<path
147
147
+
fill-rule="evenodd"
148
148
+
d="M2.628 1.601C5.028 1.206 7.49 1 10 1s4.973.206 7.372.601a.75.75 0 0 1 .628.74v2.288a2.25 2.25 0 0 1-.659 1.59l-4.682 4.683a2.25 2.25 0 0 0-.659 1.59v3.037c0 .684-.31 1.33-.844 1.757l-1.937 1.55A.75.75 0 0 1 8 18.25v-5.757a2.25 2.25 0 0 0-.659-1.591L2.659 6.22A2.25 2.25 0 0 1 2 4.629V2.34a.75.75 0 0 1 .628-.74Z"
149
149
+
clip-rule="evenodd"
150
150
+
/>
151
151
+
</svg>
152
152
+
{#if hasActiveFilters}
153
153
+
<span class="bg-accent-600 absolute top-1 right-1 size-2 rounded-full"></span>
154
154
+
{/if}
155
155
+
</button>
156
156
+
</div>
182
157
183
183
-
<div class="flex items-center gap-3">
184
184
-
<div class="flex items-center gap-1">
185
185
-
<label class="text-base-500 dark:text-base-400 text-xs">Min likes</label>
186
186
-
<input
187
187
-
type="number"
188
188
-
bind:value={filters.minLikes}
189
189
-
min="0"
190
190
-
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
158
158
+
{#if showFilters}
159
159
+
<div class="mt-3 flex w-full flex-col gap-3 px-2">
160
160
+
{#if searchState.activeSource !== 'posts'}
161
161
+
<div class="flex flex-col gap-1.5">
162
162
+
<div class="flex items-center gap-2">
163
163
+
<label class="text-base-500 dark:text-base-400 w-16 shrink-0 text-xs">Handle</label>
164
164
+
<AtprotoHandlePopup
165
165
+
bind:value={handleInput}
166
166
+
onselected={(actor) => {
167
167
+
if (!filters.handles.includes(actor.handle)) {
168
168
+
filters.handles = [...filters.handles, actor.handle];
169
169
+
}
170
170
+
handleInput = '';
171
171
+
}}
191
172
/>
192
173
</div>
193
193
-
<div class="flex items-center gap-1">
194
194
-
<label class="text-base-500 dark:text-base-400 text-xs">Reposts</label>
195
195
-
<input
196
196
-
type="number"
197
197
-
bind:value={filters.minReposts}
198
198
-
min="0"
199
199
-
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
200
200
-
/>
201
201
-
</div>
202
202
-
<div class="flex items-center gap-1">
203
203
-
<label class="text-base-500 dark:text-base-400 text-xs">Replies</label>
204
204
-
<input
205
205
-
type="number"
206
206
-
bind:value={filters.minReplies}
207
207
-
min="0"
208
208
-
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
209
209
-
/>
210
210
-
</div>
174
174
+
{#if filters.handles.length > 0}
175
175
+
<div class="ml-18 flex flex-wrap gap-1">
176
176
+
{#each filters.handles as handle}
177
177
+
<span
178
178
+
class="bg-base-200 dark:bg-base-800 text-base-700 dark:text-base-300 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs"
179
179
+
>
180
180
+
@{handle}
181
181
+
<button
182
182
+
class="text-base-500 hover:text-base-800 dark:hover:text-base-100 cursor-pointer"
183
183
+
onclick={() => (filters.handles = filters.handles.filter((h) => h !== handle))}
184
184
+
aria-label="Remove {handle}"
185
185
+
>
186
186
+
<svg
187
187
+
xmlns="http://www.w3.org/2000/svg"
188
188
+
viewBox="0 0 16 16"
189
189
+
fill="currentColor"
190
190
+
class="size-3"
191
191
+
>
192
192
+
<path
193
193
+
d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z"
194
194
+
/>
195
195
+
</svg>
196
196
+
</button>
197
197
+
</span>
198
198
+
{/each}
199
199
+
</div>
200
200
+
{/if}
211
201
</div>
202
202
+
{/if}
212
203
213
213
-
<div class="flex items-center gap-3">
214
214
-
<div class="flex items-center gap-1">
215
215
-
<label class="text-base-500 dark:text-base-400 text-xs">After</label>
216
216
-
<input
217
217
-
type="date"
218
218
-
bind:value={filters.dateAfter}
219
219
-
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 rounded-md border px-2 py-1 text-xs"
220
220
-
/>
221
221
-
</div>
222
222
-
<div class="flex items-center gap-1">
223
223
-
<label class="text-base-500 dark:text-base-400 text-xs">Before</label>
224
224
-
<input
225
225
-
type="date"
226
226
-
bind:value={filters.dateBefore}
227
227
-
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 rounded-md border px-2 py-1 text-xs"
228
228
-
/>
229
229
-
</div>
204
204
+
<div class="flex items-center gap-3">
205
205
+
<div class="flex items-center gap-1">
206
206
+
<label class="text-base-500 dark:text-base-400 text-xs">Min likes</label>
207
207
+
<input
208
208
+
type="number"
209
209
+
bind:value={filters.minLikes}
210
210
+
min="0"
211
211
+
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
212
212
+
/>
213
213
+
</div>
214
214
+
<div class="flex items-center gap-1">
215
215
+
<label class="text-base-500 dark:text-base-400 text-xs">Reposts</label>
216
216
+
<input
217
217
+
type="number"
218
218
+
bind:value={filters.minReposts}
219
219
+
min="0"
220
220
+
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
221
221
+
/>
222
222
+
</div>
223
223
+
<div class="flex items-center gap-1">
224
224
+
<label class="text-base-500 dark:text-base-400 text-xs">Replies</label>
225
225
+
<input
226
226
+
type="number"
227
227
+
bind:value={filters.minReplies}
228
228
+
min="0"
229
229
+
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 w-16 rounded-md border px-2 py-1 text-xs"
230
230
+
/>
230
231
</div>
232
232
+
</div>
231
233
232
232
-
<div class="flex items-center gap-2">
233
233
-
<span class="text-base-500 dark:text-base-400 text-xs">Has:</span>
234
234
-
<button class={pillClass(filters.hasImage)} onclick={() => (filters.hasImage = !filters.hasImage)}>Image</button>
235
235
-
<button class={pillClass(filters.hasLink)} onclick={() => (filters.hasLink = !filters.hasLink)}>Link</button>
236
236
-
<button class={pillClass(filters.hasVideo)} onclick={() => (filters.hasVideo = !filters.hasVideo)}>Video</button>
234
234
+
<div class="flex items-center gap-3">
235
235
+
<div class="flex items-center gap-1">
236
236
+
<label class="text-base-500 dark:text-base-400 text-xs">After</label>
237
237
+
<input
238
238
+
type="date"
239
239
+
bind:value={filters.dateAfter}
240
240
+
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 rounded-md border px-2 py-1 text-xs"
241
241
+
/>
242
242
+
</div>
243
243
+
<div class="flex items-center gap-1">
244
244
+
<label class="text-base-500 dark:text-base-400 text-xs">Before</label>
245
245
+
<input
246
246
+
type="date"
247
247
+
bind:value={filters.dateBefore}
248
248
+
class="bg-base-100 dark:bg-base-900 border-base-300 dark:border-base-700 text-base-800 dark:text-base-200 rounded-md border px-2 py-1 text-xs"
249
249
+
/>
237
250
</div>
251
251
+
</div>
238
252
239
239
-
<div class="flex items-center gap-2">
240
240
-
<button class={pillClass(!filters.showReplies)} onclick={() => (filters.showReplies = !filters.showReplies)}>Hide replies</button>
241
241
-
</div>
253
253
+
<div class="flex items-center gap-2">
254
254
+
<span class="text-base-500 dark:text-base-400 text-xs">Has:</span>
255
255
+
<button
256
256
+
class={pillClass(filters.hasImage)}
257
257
+
onclick={() => (filters.hasImage = !filters.hasImage)}>Image</button
258
258
+
>
259
259
+
<button
260
260
+
class={pillClass(filters.hasLink)}
261
261
+
onclick={() => (filters.hasLink = !filters.hasLink)}>Link</button
262
262
+
>
263
263
+
<button
264
264
+
class={pillClass(filters.hasVideo)}
265
265
+
onclick={() => (filters.hasVideo = !filters.hasVideo)}>Video</button
266
266
+
>
267
267
+
</div>
242
268
243
243
-
{#if hasActiveFilters}
244
244
-
<button
245
245
-
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 cursor-pointer self-start text-xs underline"
246
246
-
onclick={() => (filters = { ...DEFAULT_FILTERS })}
247
247
-
>
248
248
-
Clear filters
249
249
-
</button>
250
250
-
{/if}
269
269
+
<div class="flex items-center gap-2">
270
270
+
<button
271
271
+
class={pillClass(!filters.showReplies)}
272
272
+
onclick={() => (filters.showReplies = !filters.showReplies)}>Hide replies</button
273
273
+
>
251
274
</div>
252
252
-
{/if}
253
275
254
254
-
{@const src = searchState.sources[searchState.activeSource]}
255
255
-
<span class="text-base-600 dark:text-base-400 mt-2 mx-4 text-xs">
256
256
-
{#if src.phase === 'idle'}
257
257
-
loading...
258
258
-
{:else if src.phase === 'fetching'}
259
259
-
fetching {SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count + src.pendingUris.length} found)
260
260
-
{:else if src.phase === 'hydrating'}
261
261
-
indexing {src.indexed}/{src.totalToIndex} {SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count} searchable)
262
262
-
{:else}
263
263
-
{SOURCE_LABELS[searchState.activeSource].toLowerCase()}: {src.count}{#if results.length > 0}, {results.length} results{/if}
276
276
+
{#if hasActiveFilters}
277
277
+
<button
278
278
+
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 cursor-pointer self-start text-xs underline"
279
279
+
onclick={() => (filters = { ...DEFAULT_FILTERS })}
280
280
+
>
281
281
+
Clear filters
282
282
+
</button>
264
283
{/if}
265
265
-
</span>
266
266
-
</Navbar>
284
284
+
</div>
285
285
+
{/if}
286
286
+
287
287
+
{@const src = searchState.sources[searchState.activeSource]}
288
288
+
<span class="text-base-600 dark:text-base-400 mx-4 mt-2 text-xs">
289
289
+
{#if src.phase === 'idle'}
290
290
+
loading...
291
291
+
{:else if src.phase === 'fetching'}
292
292
+
fetching {SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count +
293
293
+
src.pendingUris.length} found)
294
294
+
{:else if src.phase === 'hydrating'}
295
295
+
indexing {src.indexed}/{src.totalToIndex}
296
296
+
{SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count} searchable)
297
297
+
{:else}
298
298
+
{SOURCE_LABELS[searchState.activeSource].toLowerCase()}: {src.count}{#if results.length > 0}, {results.length}
299
299
+
results{/if}
300
300
+
{/if}
301
301
+
</span>
302
302
+
</Navbar>
267
303
268
304
{#if results.length > 0}
269
269
-
<ul class="{showFilters ? 'pt-90 md:pt-80' : 'pt-32 md:pt-20'} flex flex-col divide-y divide-base-200 dark:divide-base-800 text-sm">
305
305
+
<ul
306
306
+
class="{showFilters
307
307
+
? 'pt-90 md:pt-80'
308
308
+
: 'pt-32 md:pt-20'} divide-base-200 dark:divide-base-800 flex flex-col divide-y text-sm"
309
309
+
>
270
310
{#each results as result (result.doc.uri)}
271
311
<li class="py-4">
272
312
<BlueskyPost
273
273
-
274
313
liked={result.doc.sources?.includes('likes')}
275
314
bookmarked={result.doc.sources?.includes('bookmarks')}
276
315
showLogo
···
287
326
{/if}
288
327
</div>
289
328
{:else if search || hasActiveFilters}
290
290
-
<div class="text-base-600 dark:text-base-400 {showFilters ? 'pt-90 md:pt-80' : 'pt-32 md:pt-20'} text-center text-sm font-semibold">No results</div>
329
329
+
<div
330
330
+
class="text-base-600 dark:text-base-400 {showFilters
331
331
+
? 'pt-90 md:pt-80'
332
332
+
: 'pt-32 md:pt-20'} text-center text-sm font-semibold"
333
333
+
>
334
334
+
No results
335
335
+
</div>
291
336
{/if}
292
337
293
338
{#if scrollY > 300}
···
297
342
aria-label="Scroll to top"
298
343
>
299
344
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
300
300
-
<path fill-rule="evenodd" d="M9.47 6.47a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L10 8.06l-3.72 3.72a.75.75 0 0 1-1.06-1.06l4.25-4.25Z" clip-rule="evenodd" />
345
345
+
<path
346
346
+
fill-rule="evenodd"
347
347
+
d="M9.47 6.47a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L10 8.06l-3.72 3.72a.75.75 0 0 1-1.06-1.06l4.25-4.25Z"
348
348
+
clip-rule="evenodd"
349
349
+
/>
301
350
</svg>
302
351
</button>
303
352
{/if}