diff --git a/GanjooRazor/Pages/Index.cshtml b/GanjooRazor/Pages/Index.cshtml index c7d4ed39..3a0b717a 100644 --- a/GanjooRazor/Pages/Index.cshtml +++ b/GanjooRazor/Pages/Index.cshtml @@ -76,7 +76,7 @@ else - + @@ -197,12 +197,12 @@ else
- مرور کتابها + قفسهٔ کتابها
-
+
diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 7a87f030..d08e1141 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -342,7 +342,94 @@ select { color: var(--ink-black); } -/* Home page "مرور کتابها" book shelf - see initHomeBooksShelf()/buildBookSpine() in bk.js. */ +/* A book matched by the top search box's live filter (see onHomeSearchInput()/ + buildHomeBookResultChip() in bk.js) - rendered alongside matching poets in #home-found-poets, so + it needs the same flex-row layout .spacer:has(.poet) gives poet results, but triggered on its own + class too since a search can match only books and no poets at all. */ +.spacer:has(.home-book-result) { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: flex-start; + gap: 14px 28px; + margin: 15px auto 25px auto; + padding: 0; + clear: both; +} + +/* Sized and laid out to match .spacer .poet exactly (110px column, 76x96 "portrait" area, same pill + caption below) so a book result sits proportionate to the poet results next to it instead of + looming over them as its own, differently-sized shape. */ +.home-book-result { + display: flex; + flex-direction: column; + align-items: center; + width: 110px; + margin: 0 0 10px 0; + text-decoration: none; + transition: transform 0.25s ease; +} + +.home-book-result:hover { + transform: translateY(-5px); +} + +.home-book-result-cover { + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 96px; + border-radius: 10px; + padding: 6px; + overflow: hidden; + text-align: center; + color: #fdf8ee; + font-family: 'IranNastaliq', serif; + font-size: 1rem; + line-height: 1.35; + box-shadow: + 0 0 0 2px var(--gold), + 0 0 0 5px var(--bg-page), + 0 0 0 7px var(--border-gold), + 0 4px 12px rgba(0, 0, 0, 0.15); + transition: box-shadow 0.25s ease; +} + +.home-book-result:hover .home-book-result-cover { + box-shadow: + 0 0 0 2px var(--brand), + 0 0 0 5px var(--bg-page), + 0 0 0 7px var(--brand), + 0 6px 18px rgba(0, 0, 0, 0.22); +} + +.home-book-result-caption { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + text-align: center; + margin: 5px 0 8px 0; + padding: 6px 12px; + border-radius: 12px; + background-color: var(--card-inner); + border: 1px solid var(--border-gold); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); + font-size: 0.85rem; + font-weight: 600; + color: var(--lapis); + transition: all 0.2s ease; +} + +.home-book-result:hover .home-book-result-caption { + background-color: var(--gold-subtle); + border-color: var(--brand); + transform: translateY(-1px); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12); +} + +/* Home page "قفسهٔ کتابها" book shelf - see initHomeBooksShelf()/buildBookSpine() in bk.js. */ #books-shelf-outer { position: relative; } diff --git a/GanjooRazor/wwwroot/js/bk.js b/GanjooRazor/wwwroot/js/bk.js index ee1d77a7..93b8c731 100644 --- a/GanjooRazor/wwwroot/js/bk.js +++ b/GanjooRazor/wwwroot/js/bk.js @@ -1560,6 +1560,31 @@ function persianizeNumerals(value) { // behavior into the top box: typing filters poets live (same underlying match as onInlineSearch, // against every ".poet" element's data-value), while submitting the form (Enter / the "بیاب" button) // still does the original full poem search unchanged - so nothing about submission itself changes. +// homeBooksCache is filled once by initHomeBooksShelf() further below - the same catalog backing +// the "قفسهٔ کتابها" shelf is reused here so a search also matches book names, not just poets. +var homeBooksCache = []; + +function buildHomeBookResultChip(book) { + var a = document.createElement('a'); + a.className = 'home-book-result'; + a.href = book.fullUrl || '#'; + + // Same 76x96 "portrait" box a poet result uses, just filled with the book's own hashed color + // and its name instead of a photo - see .home-book-result-cover in p8.css for the sizing. + var cover = document.createElement('span'); + cover.className = 'home-book-result-cover'; + cover.style.background = 'hsl(' + hashBookColorHue(book.id) + ', 42%, 32%)'; + cover.textContent = book.name; + + var caption = document.createElement('span'); + caption.className = 'home-book-result-caption'; + caption.textContent = book.poetName || ''; + + a.appendChild(cover); + a.appendChild(caption); + return a; +} + function onHomeSearchInput(value) { var clearBtn = document.getElementById('home-search-clear'); var popularRow = document.getElementById('home-popular-poets-row'); @@ -1603,6 +1628,13 @@ function onHomeSearchInput(value) { foundNode.appendChild(poets[i].cloneNode(true)); } + for (var k = 0; k < homeBooksCache.length; k++) { + var book = homeBooksCache[k]; + if (book.name && book.name.indexOf(replaced) !== -1) { + foundNode.appendChild(buildHomeBookResultChip(book)); + } + } + var hasMatches = foundNode.childElementCount > 0; foundNode.style.display = hasMatches ? '' : 'none'; // No matching poet: there's nothing useful to show in place of the favorites row, so put the @@ -1620,7 +1652,7 @@ function clearHomeSearch() { input.focus(); } -// Home page (Index.cshtml) only: "مرور کتابها" - a horizontally scrollable shelf of book "spines", +// Home page (Index.cshtml) only: "قفسهٔ کتابها" - a horizontally scrollable shelf of book "spines", // Grokipedia-homepage-style. Fetched once from this page's own "?Handler=BookCatalog" (which proxies // RMuseum's api/ganjoor/book-catalog server-side) rather than calling that API directly from browser // JS - same convention every other client-side data fetch on this site follows. There's no cover-art @@ -1744,6 +1776,7 @@ function initHomeBooksShelf() { url: '?Handler=BookCatalog', success: function (books) { if (!books || books.length === 0) return; + homeBooksCache = books; var frag = document.createDocumentFragment(); for (var i = 0; i < books.length; i++) { frag.appendChild(buildBookSpine(books[i]));