diff --git a/src/components/LabelCircle.tsx b/src/components/LabelCircle.tsx index dc287b7..82079c2 100644 --- a/src/components/LabelCircle.tsx +++ b/src/components/LabelCircle.tsx @@ -11,7 +11,6 @@ export function LabelCircle(props: { contact: boolean; label: boolean; channel?: HackActivityType; - onError?: () => void; }) { const [gradient] = createResource(async () => { if (props.name && props.contact) { @@ -44,8 +43,9 @@ export function LabelCircle(props: { {"image"} { - props.onError && props.onError(); + onError={(e) => { + // This doesn't stop the console errors from showing up + e.stopPropagation(); setErrored(true); }} /> diff --git a/src/routes/Search.tsx b/src/routes/Search.tsx index f3921e6..fc7eb14 100644 --- a/src/routes/Search.tsx +++ b/src/routes/Search.tsx @@ -3,6 +3,7 @@ import { Capacitor } from "@capacitor/core"; import { TagItem } from "@mutinywallet/mutiny-wasm"; import { A, useNavigate } from "@solidjs/router"; import { + createEffect, createMemo, createResource, createSignal, @@ -36,6 +37,7 @@ import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; import { actuallyFetchNostrProfile, + debounce, hexpubFromNpub, profileToPseudoContact, PseudoContact, @@ -69,10 +71,19 @@ export function Search() { function ActualSearch() { const [searchValue, setSearchValue] = createSignal(""); + const [debouncedSearchValue, setDebouncedSearchValue] = createSignal(""); const [state, actions] = useMegaStore(); const navigate = useNavigate(); const i18n = useI18n(); + const trigger = debounce((message: string) => { + setDebouncedSearchValue(message); + }, 250); + + createEffect(() => { + trigger(searchValue()); + }); + async function contactsFetcher() { try { const contacts: TagItem[] = @@ -87,7 +98,7 @@ function ActualSearch() { const [contacts] = createResource(contactsFetcher); const filteredContacts = createMemo(() => { - const s = searchValue().toLowerCase(); + const s = debouncedSearchValue().toLowerCase(); return ( contacts()?.filter((c) => { return ( @@ -109,10 +120,10 @@ function ActualSearch() { }); const showSendButton = createMemo(() => { - if (searchValue() === "") { + if (debouncedSearchValue() === "") { return false; } else { - const text = searchValue().trim(); + const text = debouncedSearchValue().trim(); // Only want to check for something parseable if it's of reasonable length if (text.length < 6) { return false; @@ -133,7 +144,7 @@ function ActualSearch() { function handleContinue() { actions.handleIncomingString( - searchValue().trim(), + debouncedSearchValue().trim(), (error) => { showToast(error); }, @@ -273,31 +284,35 @@ function ActualSearch() {
-
-

Contacts

-
- 0}> - - {(contact) => ( - sendToContact(contact)} - /> - )} - - + +
+

Contacts

+
+ 0}> + + {(contact) => ( + sendToContact(contact)} + /> + )} + + +
- -

Global Search

- }> + }> + +

+ Global Search +

-
-
+ +
diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts new file mode 100644 index 0000000..81c6635 --- /dev/null +++ b/src/utils/debounce.ts @@ -0,0 +1,42 @@ +// copied from https://github.com/solidjs-community/solid-primitives/tree/main/packages/scheduled#readme + +import { getOwner, onCleanup } from "solid-js"; + +export type ScheduleCallback = ( + callback: (...args: Args) => void, + wait?: number +) => Scheduled; + +export interface Scheduled { + (...args: Args): void; + clear: VoidFunction; +} + +/** + * Creates a callback that is debounced and cancellable. The debounced callback is called on **trailing** edge. + * + * The timeout will be automatically cleared on root dispose. + * + * @param callback The callback to debounce + * @param wait The duration to debounce in milliseconds + * @returns The debounced function + * + * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/scheduled#debounce + * + * @example + * ```ts + * const fn = debounce((message: string) => console.log(message), 250); + * fn('Hello!'); + * fn.clear() // clears a timeout in progress + * ``` + */ +export const debounce: ScheduleCallback = (callback, wait) => { + let timeoutId: ReturnType | undefined; + const clear = () => clearTimeout(timeoutId); + if (getOwner()) onCleanup(clear); + const debounced: typeof callback = (...args) => { + if (timeoutId !== undefined) clear(); + timeoutId = setTimeout(() => callback(...args), wait); + }; + return Object.assign(debounced, { clear }); +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index 4e0b2ed..754f092 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -18,3 +18,4 @@ export * from "./nostr"; export * from "./currencies"; export * from "./bech32"; export * from "./keypad"; +export * from "./debounce";