fix(search): link results to book detail page and add cover thumbnails
Release / build-and-push (push) Successful in 2m24s
Release / build-and-push (push) Successful in 2m24s
Search results navigated to /bookshelf with no filters instead of the selected book's page. Results now link to /media/:id and display cover thumbnails, with cover URLs resolved server-side via ResolveMediaURL. Removes the dead selectedBook localStorage plumbing.
This commit is contained in:
@@ -1791,6 +1791,10 @@ func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error {
|
||||
"results": []interface{}{},
|
||||
})
|
||||
}
|
||||
for i := range results {
|
||||
resolved := utils.ResolveMediaURL(results[i].LibraryID, results[i].CoverImagePath)
|
||||
results[i].CoverImagePath = pgtype.Text{String: resolved, Valid: resolved != ""}
|
||||
}
|
||||
return c.JSON(http.StatusOK, results)
|
||||
}
|
||||
|
||||
|
||||
+10
-20
@@ -1,5 +1,4 @@
|
||||
import { Alpine } from "./alpine";
|
||||
import { setSelectedLibrary } from "./storage";
|
||||
|
||||
let searchInputTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
const SEARCH_DEBOUNCE_MS = 300;
|
||||
@@ -190,12 +189,6 @@ function showSearchResults(results: MediaItemSummary[], query: string, activeId?
|
||||
|
||||
searchResults.dataset.selectedIndex = "-1";
|
||||
|
||||
const libraryIconMap: Record<string, string> = {
|
||||
ebooks: "📚",
|
||||
comics: "📖",
|
||||
manga: "🗾",
|
||||
};
|
||||
|
||||
let html = `
|
||||
<div class="p-3 border-b" style="border-color: var(--border)">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide" style="color: var(--text-secondary)">
|
||||
@@ -206,19 +199,23 @@ function showSearchResults(results: MediaItemSummary[], query: string, activeId?
|
||||
`;
|
||||
|
||||
results.forEach((item, index) => {
|
||||
const icon = libraryIconMap[item.library_type_name] || "📁";
|
||||
const titleHtml = highlightMatch(item.title, query);
|
||||
const authorHtml = item.author ? highlightMatch(item.author, query) : "";
|
||||
const coverUrl = item.cover_image_path || "/static/placeholder-book.svg";
|
||||
|
||||
html += `
|
||||
<div class="search-result-item p-3 border-b hover:bg-opacity-50 transition-colors cursor-pointer"
|
||||
style="border-color: var(--border); background-color: var(--bg-secondary)"
|
||||
data-index="${index}">
|
||||
<a href="/bookshelf"
|
||||
class="block"
|
||||
onclick="window.selectLibraryAndBook('${item.library_id}', '${item.id}')">
|
||||
<a href="/media/${item.id}" class="block">
|
||||
<div class="flex items-start space-x-3">
|
||||
<div class="text-2xl">${icon}</div>
|
||||
<div class="w-10 h-14 flex-shrink-0 rounded overflow-hidden bg-gradient-to-br from-gray-700 to-gray-900">
|
||||
<img src="${coverUrl}"
|
||||
alt="${searchEscapeHtml(item.title)}"
|
||||
class="w-full h-full object-cover"
|
||||
loading="lazy"
|
||||
onerror="this.src='/static/placeholder-book.svg'">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h4 class="text-sm font-medium truncate" style="color: var(--text-primary)">
|
||||
${titleHtml}
|
||||
@@ -323,15 +320,8 @@ function searchEscapeHtml(text: string): string {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function selectLibraryAndBook(libraryId: string, bookId: string): void {
|
||||
setSelectedLibrary(libraryId);
|
||||
localStorage.setItem("selectedBook", bookId);
|
||||
hideSearchResults();
|
||||
}
|
||||
|
||||
export { selectLibraryAndBook, initializeSearch };
|
||||
export { initializeSearch };
|
||||
|
||||
Alpine.data("search", () => ({
|
||||
selectLibraryAndBook,
|
||||
initializeSearch,
|
||||
}));
|
||||
|
||||
@@ -45,14 +45,6 @@ function setSelectedLibrary(libraryId: string): void {
|
||||
document.cookie = `selectedLibrary=${encodeURIComponent(value)};path=/;max-age=${365 * 24 * 60 * 60};samesite=lax`;
|
||||
}
|
||||
|
||||
function getSelectedBook(): string | null {
|
||||
return localStorage.getItem("selectedBook");
|
||||
}
|
||||
|
||||
function setSelectedBook(bookId: string): void {
|
||||
localStorage.setItem("selectedBook", bookId);
|
||||
}
|
||||
|
||||
function clearAll(): void {
|
||||
localStorage.clear();
|
||||
}
|
||||
@@ -61,14 +53,12 @@ export {
|
||||
ALL_LIBRARIES,
|
||||
clearAll,
|
||||
getRefreshToken,
|
||||
getSelectedBook,
|
||||
getSelectedLibrary,
|
||||
getTheme,
|
||||
getToken,
|
||||
removeRefreshToken,
|
||||
removeToken,
|
||||
setRefreshToken,
|
||||
setSelectedBook,
|
||||
setSelectedLibrary,
|
||||
setTheme,
|
||||
setToken
|
||||
|
||||
Reference in New Issue
Block a user