feat: add poster retry and dedupe to search
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { dedupeByID, dedupeWithin } from "./dedupe";
|
||||||
|
|
||||||
interface CommandPaletteItem {
|
interface CommandPaletteItem {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
@@ -53,6 +55,7 @@ const typeLabels: Record<string, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const groupOrder = ["anime"];
|
const groupOrder = ["anime"];
|
||||||
|
const maxPosterImageRetries = 2;
|
||||||
|
|
||||||
const isMac = (): boolean => /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
const isMac = (): boolean => /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
||||||
|
|
||||||
@@ -134,11 +137,24 @@ const buildPosterImage = (item: CommandPaletteItem): HTMLElement => {
|
|||||||
return buildFallbackIcon(item);
|
return buildFallbackIcon(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const source = item.image || "";
|
||||||
|
let retries = 0;
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.className = "aspect-2/3 w-full bg-background-button object-cover";
|
img.className = "aspect-2/3 w-full bg-background-button object-cover";
|
||||||
img.src = item.image || "";
|
|
||||||
img.alt = "";
|
img.alt = "";
|
||||||
img.loading = "lazy";
|
img.loading = "lazy";
|
||||||
|
img.addEventListener("error", () => {
|
||||||
|
if (retries < maxPosterImageRetries) {
|
||||||
|
retries += 1;
|
||||||
|
const retryURL = new URL(source);
|
||||||
|
retryURL.searchParams.set("_retry", String(retries));
|
||||||
|
img.src = retryURL.toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.replaceWith(buildFallbackIcon(item));
|
||||||
|
});
|
||||||
|
img.src = source;
|
||||||
return img;
|
return img;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,6 +254,7 @@ const buildCard = (item: CommandPaletteItem, index: number): HTMLAnchorElement =
|
|||||||
card.className =
|
card.className =
|
||||||
"group block min-w-0 text-foreground no-underline transition focus-visible:outline-none hover:no-underline";
|
"group block min-w-0 text-foreground no-underline transition focus-visible:outline-none hover:no-underline";
|
||||||
card.dataset.commandPaletteItem = item.id;
|
card.dataset.commandPaletteItem = item.id;
|
||||||
|
card.dataset.id = item.id;
|
||||||
card.dataset.resultIndex = String(index);
|
card.dataset.resultIndex = String(index);
|
||||||
card.setAttribute("role", "option");
|
card.setAttribute("role", "option");
|
||||||
card.setAttribute("aria-selected", String(index === selectedIndex));
|
card.setAttribute("aria-selected", String(index === selectedIndex));
|
||||||
@@ -285,6 +302,7 @@ const buildCompactItem = (item: CommandPaletteItem, index: number): HTMLAnchorEl
|
|||||||
row.className =
|
row.className =
|
||||||
"group flex min-h-16 items-center gap-3 px-3 py-2 text-foreground no-underline transition hover:bg-surface-hover hover:no-underline focus-visible:outline-none";
|
"group flex min-h-16 items-center gap-3 px-3 py-2 text-foreground no-underline transition hover:bg-surface-hover hover:no-underline focus-visible:outline-none";
|
||||||
row.dataset.commandPaletteItem = item.id;
|
row.dataset.commandPaletteItem = item.id;
|
||||||
|
row.dataset.id = item.id;
|
||||||
row.dataset.resultIndex = String(index);
|
row.dataset.resultIndex = String(index);
|
||||||
row.setAttribute("role", "option");
|
row.setAttribute("role", "option");
|
||||||
row.setAttribute("aria-selected", String(index === selectedIndex));
|
row.setAttribute("aria-selected", String(index === selectedIndex));
|
||||||
@@ -399,7 +417,7 @@ const renderItems = (items: CommandPaletteItem[]): void => {
|
|||||||
const shell = document.createElement("div");
|
const shell = document.createElement("div");
|
||||||
shell.className = "mx-auto w-full max-w-5xl px-5 py-9 md:px-8 md:py-12";
|
shell.className = "mx-auto w-full max-w-5xl px-5 py-9 md:px-8 md:py-12";
|
||||||
|
|
||||||
const groups = groupedItems(items);
|
const groups = groupedItems(dedupeByID(items, (item) => item.id));
|
||||||
const keys = orderedGroupKeys(groups);
|
const keys = orderedGroupKeys(groups);
|
||||||
resultItems = keys.flatMap((key) => groups.get(key) || []);
|
resultItems = keys.flatMap((key) => groups.get(key) || []);
|
||||||
let cursor = 0;
|
let cursor = 0;
|
||||||
@@ -418,6 +436,7 @@ const renderItems = (items: CommandPaletteItem[]): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
searchResults.replaceChildren(shell);
|
searchResults.replaceChildren(shell);
|
||||||
|
shell.querySelectorAll<HTMLElement>("[role='listbox']").forEach((list) => dedupeWithin(list));
|
||||||
selectItem(0, false);
|
selectItem(0, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -427,7 +446,7 @@ const appendItems = (items: CommandPaletteItem[]): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const existingIDs = new Set(resultItems.map((item) => item.id));
|
const existingIDs = new Set(resultItems.map((item) => item.id));
|
||||||
const nextItems = items.filter((item) => !existingIDs.has(item.id));
|
const nextItems = dedupeByID(items, (item) => item.id).filter((item) => !existingIDs.has(item.id));
|
||||||
if (nextItems.length === 0) {
|
if (nextItems.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user