From 7cda75c75163588b510cc1ac2556be247d363cb9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:55:40 +0000 Subject: [PATCH] feat: Improve Domain Search UX with spinner and reactive search - Added `CircularProgress` spinner to `DomainSearch` input. - Made search reactive to `domainName` changes (handling paste). - Added `util` polyfill to `vite.config.ts`. - Updated `.Jules/palette.md` with learning. Co-authored-by: yeboster <23556525+yeboster@users.noreply.github.com> --- .Jules/palette.md | 5 +++++ .jules/palette.md | 1 + src/routes/DomainSearch.svelte | 29 ++++++++++++++++++++++++----- vite.config.ts | 2 +- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index d6d129b..d974090 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -2,3 +2,8 @@ **Learning:** Async buttons that handle errors often fail to reset their error state on subsequent attempts. This leads to a confusing UX where a successful retry still displays the error icon, making the user believe the action failed again. **Action:** Always ensure that error flags (e.g., `hasError`) are reset at the _start_ of the async operation, not just set in the `catch` block. + +## 2024-10-24 - In-Place Loading Indicators + +**Learning:** Replacing static icons (like search) with loading spinners within the same container (e.g., input field) prevents layout shifts and provides immediate, contextual feedback. +**Action:** Use conditional rendering to swap icons for spinners in `trailingIcon` slots or button contents during async operations. diff --git a/.jules/palette.md b/.jules/palette.md index 00f41cd..9cc85e1 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,4 @@ ## 2024-10-24 - Accessible Icon Props and Loading Button State + **Learning:** Svelte wrapper components (like `Icon.svelte`) must spread `$$restProps` to allow passing accessibility attributes (e.g., `aria-label`) from parent components. Without this, icons remain inaccessible to screen readers. Also, persistent "Success" states on buttons can be confusing; auto-resetting them after a timeout improves clarity. **Action:** Always include `{...$$restProps}` in wrapper components and implement auto-reset logic for temporary success states in interactive elements. diff --git a/src/routes/DomainSearch.svelte b/src/routes/DomainSearch.svelte index 48c50fd..1f7e1f5 100644 --- a/src/routes/DomainSearch.svelte +++ b/src/routes/DomainSearch.svelte @@ -22,8 +22,17 @@ $: invalid = domainName !== '' && !validator.validate(domainName, { raiseError: false }); $: nameSearchedLabel = nameSearched ? `${nameSearched}.${$metaNamesSdk.config.tld}` : null; - function debounce() { + $: debounce(domainName); + + function debounce(name: string) { clearTimeout(debounceTimer); + + if (name === '' || invalid) { + domain = undefined; + isLoading = false; + return; + } + debounceTimer = setTimeout(async () => await search(), 400); } @@ -60,7 +69,6 @@ class="domain-input" variant="outlined" bind:value={domainName} - on:keyup={() => debounce()} bind:invalid label="Domain name" withTrailingIcon @@ -68,9 +76,20 @@ >
- - - + {#if isLoading} +
+ +
+ {:else} + + + + {/if}
diff --git a/vite.config.ts b/vite.config.ts index a9322d6..6094564 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,7 +14,7 @@ export default defineConfig({ }), sveltekit(), nodePolyfills({ - include: ['buffer', 'crypto', 'stream'] + include: ['buffer', 'crypto', 'stream', 'util'] }), tsconfigPaths() ],