style: format static/search/render.ts
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { dedupeByID, dedupeWithin } from "../dedupe";
|
|
||||||
import type { SearchItem } from "./state";
|
import type { SearchItem } from "./state";
|
||||||
|
|
||||||
|
import { dedupeByID, dedupeWithin } from "../dedupe";
|
||||||
import {
|
import {
|
||||||
searchResults,
|
searchResults,
|
||||||
searchClearButtons,
|
searchClearButtons,
|
||||||
@@ -51,7 +52,7 @@ const buildSvgIcon = (pathData: string, className: string): SVGSVGElement => {
|
|||||||
|
|
||||||
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||||
path.setAttribute("d", pathData);
|
path.setAttribute("d", pathData);
|
||||||
svg.appendChild(path);
|
svg.append(path);
|
||||||
|
|
||||||
return svg;
|
return svg;
|
||||||
};
|
};
|
||||||
@@ -62,7 +63,7 @@ const buildFallbackIcon = (item: SearchItem): HTMLElement => {
|
|||||||
"flex aspect-2/3 w-full items-center justify-center bg-background-button text-foreground-muted";
|
"flex aspect-2/3 w-full items-center justify-center bg-background-button text-foreground-muted";
|
||||||
|
|
||||||
const path = iconPaths[item.icon || "search"] || iconPaths.search;
|
const path = iconPaths[item.icon || "search"] || iconPaths.search;
|
||||||
icon.appendChild(buildSvgIcon(path, "size-7"));
|
icon.append(buildSvgIcon(path, "size-7"));
|
||||||
return icon;
|
return icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,16 +126,14 @@ export const runSelectedItem = (): void => {
|
|||||||
window.location.href = item.href;
|
window.location.href = item.href;
|
||||||
};
|
};
|
||||||
|
|
||||||
const cleanLabel = (item: SearchItem): string => {
|
const cleanLabel = (item: SearchItem): string => item.label;
|
||||||
return item.label;
|
|
||||||
};
|
|
||||||
|
|
||||||
const animeMalID = (item: SearchItem): number | null => {
|
const animeMalID = (item: SearchItem): number | null => {
|
||||||
if (item.type !== "anime") {
|
if (item.type !== "anime") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const match = item.id.match(/^anime:(\d+)$/);
|
const match = /^anime:(\d+)$/.exec(item.id);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -159,7 +158,7 @@ const buildWatchlistButton = (item: SearchItem): HTMLButtonElement | null => {
|
|||||||
button.dataset.watchlistTitle = cleanLabel(item);
|
button.dataset.watchlistTitle = cleanLabel(item);
|
||||||
button.dataset.watchlistState = inWatchlist ? "in" : "out";
|
button.dataset.watchlistState = inWatchlist ? "in" : "out";
|
||||||
button.setAttribute("aria-label", inWatchlist ? "Remove from Watchlist" : "Add to Watchlist");
|
button.setAttribute("aria-label", inWatchlist ? "Remove from Watchlist" : "Add to Watchlist");
|
||||||
button.appendChild(
|
button.append(
|
||||||
buildSvgIcon(
|
buildSvgIcon(
|
||||||
iconPaths.bookmark,
|
iconPaths.bookmark,
|
||||||
"size-6 watchlist-icon fill-none group-data-[watchlist-state=in]:fill-current [&_path]:fill-none group-data-[watchlist-state=in]:[&_path]:fill-current",
|
"size-6 watchlist-icon fill-none group-data-[watchlist-state=in]:fill-current [&_path]:fill-none group-data-[watchlist-state=in]:[&_path]:fill-current",
|
||||||
@@ -178,29 +177,31 @@ const buildCard = (item: SearchItem, index: number): HTMLAnchorElement => {
|
|||||||
card.dataset.resultIndex = String(index);
|
card.dataset.resultIndex = String(index);
|
||||||
card.setAttribute("role", "option");
|
card.setAttribute("role", "option");
|
||||||
card.setAttribute("aria-selected", String(index === getSelectedIndex()));
|
card.setAttribute("aria-selected", String(index === getSelectedIndex()));
|
||||||
card.addEventListener("mouseenter", () => selectItem(index, false));
|
card.addEventListener("mouseenter", () => {
|
||||||
|
selectItem(index, false);
|
||||||
|
});
|
||||||
|
|
||||||
const media = document.createElement("div");
|
const media = document.createElement("div");
|
||||||
media.className = "relative mb-3 overflow-hidden bg-background-button";
|
media.className = "relative mb-3 overflow-hidden bg-background-button";
|
||||||
media.appendChild(buildPosterImage(item));
|
media.append(buildPosterImage(item));
|
||||||
|
|
||||||
const watchlistButton = buildWatchlistButton(item);
|
const watchlistButton = buildWatchlistButton(item);
|
||||||
if (watchlistButton) {
|
if (watchlistButton) {
|
||||||
media.appendChild(watchlistButton);
|
media.append(watchlistButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
card.appendChild(media);
|
card.append(media);
|
||||||
|
|
||||||
const title = document.createElement("div");
|
const title = document.createElement("div");
|
||||||
title.className = "line-clamp-2 text-sm font-semibold leading-snug text-foreground";
|
title.className = "line-clamp-2 text-sm font-semibold leading-snug text-foreground";
|
||||||
title.textContent = cleanLabel(item);
|
title.textContent = cleanLabel(item);
|
||||||
card.appendChild(title);
|
card.append(title);
|
||||||
|
|
||||||
if (item.subtitle) {
|
if (item.subtitle) {
|
||||||
const subtitle = document.createElement("div");
|
const subtitle = document.createElement("div");
|
||||||
subtitle.className = "mt-1 truncate text-xs font-medium text-foreground-muted";
|
subtitle.className = "mt-1 truncate text-xs font-medium text-foreground-muted";
|
||||||
subtitle.textContent = item.subtitle;
|
subtitle.textContent = item.subtitle;
|
||||||
card.appendChild(subtitle);
|
card.append(subtitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
@@ -213,7 +214,7 @@ const buildSection = (title: string, items: SearchItem[], startIndex: number): H
|
|||||||
const heading = document.createElement("h2");
|
const heading = document.createElement("h2");
|
||||||
heading.className = "mb-4 text-base font-bold text-foreground md:text-lg";
|
heading.className = "mb-4 text-base font-bold text-foreground md:text-lg";
|
||||||
heading.textContent = title;
|
heading.textContent = title;
|
||||||
section.appendChild(heading);
|
section.append(heading);
|
||||||
|
|
||||||
const list = document.createElement("div");
|
const list = document.createElement("div");
|
||||||
list.setAttribute("role", "listbox");
|
list.setAttribute("role", "listbox");
|
||||||
@@ -222,10 +223,10 @@ const buildSection = (title: string, items: SearchItem[], startIndex: number): H
|
|||||||
|
|
||||||
items.forEach((item, itemIndex) => {
|
items.forEach((item, itemIndex) => {
|
||||||
const index = startIndex + itemIndex;
|
const index = startIndex + itemIndex;
|
||||||
list.appendChild(buildCard(item, index));
|
list.append(buildCard(item, index));
|
||||||
});
|
});
|
||||||
|
|
||||||
section.appendChild(list);
|
section.append(list);
|
||||||
return section;
|
return section;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -241,14 +242,14 @@ export const renderEmptyState = (query: string): void => {
|
|||||||
const title = document.createElement("div");
|
const title = document.createElement("div");
|
||||||
title.className = "text-2xl font-semibold text-foreground";
|
title.className = "text-2xl font-semibold text-foreground";
|
||||||
title.textContent = query ? "No results found" : "Start typing to search your anime";
|
title.textContent = query ? "No results found" : "Start typing to search your anime";
|
||||||
empty.appendChild(title);
|
empty.append(title);
|
||||||
|
|
||||||
const subtitle = document.createElement("p");
|
const subtitle = document.createElement("p");
|
||||||
subtitle.className = "mx-auto mt-3 max-w-lg text-sm leading-6 text-foreground-muted";
|
subtitle.className = "mx-auto mt-3 max-w-lg text-sm leading-6 text-foreground-muted";
|
||||||
subtitle.textContent = query
|
subtitle.textContent = query
|
||||||
? "Try a shorter title, alternate spelling, or browse the full search results."
|
? "Try a shorter title, alternate spelling, or browse the full search results."
|
||||||
: "Search anime titles and open a result to view its details.";
|
: "Search anime titles and open a result to view its details.";
|
||||||
empty.appendChild(subtitle);
|
empty.append(subtitle);
|
||||||
|
|
||||||
searchResults.replaceChildren(empty);
|
searchResults.replaceChildren(empty);
|
||||||
};
|
};
|
||||||
@@ -265,14 +266,14 @@ export const renderSearchErrorState = (query: string): void => {
|
|||||||
const title = document.createElement("div");
|
const title = document.createElement("div");
|
||||||
title.className = "text-2xl font-semibold text-foreground";
|
title.className = "text-2xl font-semibold text-foreground";
|
||||||
title.textContent = "Search is unavailable right now";
|
title.textContent = "Search is unavailable right now";
|
||||||
empty.appendChild(title);
|
empty.append(title);
|
||||||
|
|
||||||
const subtitle = document.createElement("p");
|
const subtitle = document.createElement("p");
|
||||||
subtitle.className = "mx-auto mt-3 max-w-lg text-sm leading-6 text-foreground-muted";
|
subtitle.className = "mx-auto mt-3 max-w-lg text-sm leading-6 text-foreground-muted";
|
||||||
subtitle.textContent = query
|
subtitle.textContent = query
|
||||||
? "Try again in a moment or narrow the search query."
|
? "Try again in a moment or narrow the search query."
|
||||||
: "Try again in a moment.";
|
: "Try again in a moment.";
|
||||||
empty.appendChild(subtitle);
|
empty.append(subtitle);
|
||||||
|
|
||||||
searchResults.replaceChildren(empty);
|
searchResults.replaceChildren(empty);
|
||||||
};
|
};
|
||||||
@@ -288,9 +289,8 @@ const groupedItems = (items: SearchItem[]): Map<string, SearchItem[]> => {
|
|||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
const orderedGroupKeys = (groups: Map<string, SearchItem[]>): string[] => {
|
const orderedGroupKeys = (groups: Map<string, SearchItem[]>): string[] =>
|
||||||
return groupOrder.filter((key) => groups.has(key));
|
groupOrder.filter((key) => groups.has(key));
|
||||||
};
|
|
||||||
|
|
||||||
export const renderItems = (items: SearchItem[]): void => {
|
export const renderItems = (items: SearchItem[]): void => {
|
||||||
if (!searchResults) {
|
if (!searchResults) {
|
||||||
@@ -320,12 +320,14 @@ export const renderItems = (items: SearchItem[]): void => {
|
|||||||
|
|
||||||
const section = buildSection(typeLabels[key] || "Results", groupItems, cursor);
|
const section = buildSection(typeLabels[key] || "Results", groupItems, cursor);
|
||||||
section.classList.add("mb-12");
|
section.classList.add("mb-12");
|
||||||
shell.appendChild(section);
|
shell.append(section);
|
||||||
cursor += groupItems.length;
|
cursor += groupItems.length;
|
||||||
});
|
});
|
||||||
|
|
||||||
searchResults.replaceChildren(shell);
|
searchResults.replaceChildren(shell);
|
||||||
shell.querySelectorAll<HTMLElement>("[role='listbox']").forEach((list) => dedupeWithin(list));
|
shell.querySelectorAll<HTMLElement>("[role='listbox']").forEach((list) => {
|
||||||
|
dedupeWithin(list);
|
||||||
|
});
|
||||||
selectItem(0, false);
|
selectItem(0, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user