fix: reserve detail cover box and async-decode list/shelf covers
- The manga detail desktop overview cover had no reserved aspect-ratio, so the meta column reflowed when it decoded. Give .cover aspect-ratio: 2/3 + object-fit: cover (mirrors MangaCard). - Add decoding="async" to the detail hero/overview covers and the list/shelf covers (bookmarks, history, continue-reading, collections, tagged rows) so decode stays off the main thread — previously only MangaCard had it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
@@ -1558,7 +1558,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mangalord"
|
||||
version = "0.115.1"
|
||||
version = "0.115.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mangalord"
|
||||
version = "0.115.1"
|
||||
version = "0.115.2"
|
||||
edition = "2021"
|
||||
default-run = "mangalord"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mangalord-frontend",
|
||||
"version": "0.115.1",
|
||||
"version": "0.115.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
alt=""
|
||||
class="cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
{:else}
|
||||
<div class="cover cover-placeholder">
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
alt=""
|
||||
class="collage-cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
alt=""
|
||||
class="cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
{:else}
|
||||
<span class="cover cover-placeholder">
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
alt=""
|
||||
class="cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
{:else}
|
||||
<div class="cover cover-placeholder">
|
||||
|
||||
@@ -29,6 +29,16 @@ describe('HistoryList', () => {
|
||||
expect(cont.getAttribute('href')).toBe('/manga/m1/chapter/c9');
|
||||
});
|
||||
|
||||
it('renders covers with lazy loading and async decode', () => {
|
||||
render(HistoryList, {
|
||||
props: { entries: [entry({ manga_cover_image_path: 'mangas/m1/cover.jpg' })] }
|
||||
});
|
||||
const img = document.querySelector('img.cover') as HTMLImageElement;
|
||||
expect(img).not.toBeNull();
|
||||
expect(img.getAttribute('loading')).toBe('lazy');
|
||||
expect(img.getAttribute('decoding')).toBe('async');
|
||||
});
|
||||
|
||||
it('appends the page number to the continue line only past page 1', () => {
|
||||
// The page suffix is a separate text node from "Continue Chapter N",
|
||||
// so assert against the link's normalized text rather than getByText.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<li class="row" data-testid={testid}>
|
||||
<a {href} class="cover-link" aria-hidden="true" tabindex="-1">
|
||||
{#if primaryCover}
|
||||
<img src={fileUrl(primaryCover)} alt="" class="cover" loading="lazy" />
|
||||
<img src={fileUrl(primaryCover)} alt="" class="cover" loading="lazy" decoding="async" />
|
||||
{:else}
|
||||
<div class="cover cover-placeholder"></div>
|
||||
{/if}
|
||||
@@ -46,7 +46,7 @@
|
||||
{#if item.sample_storage_keys.length > 1}
|
||||
<div class="samples">
|
||||
{#each item.sample_storage_keys.slice(1) as key (key)}
|
||||
<img src={fileUrl(key)} alt="" class="sample" loading="lazy" />
|
||||
<img src={fileUrl(key)} alt="" class="sample" loading="lazy" decoding="async" />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<li class="row" data-testid={testid}>
|
||||
<a {href} class="cover-link" aria-hidden="true" tabindex="-1">
|
||||
{#if primaryCover}
|
||||
<img src={fileUrl(primaryCover)} alt="" class="cover" loading="lazy" />
|
||||
<img src={fileUrl(primaryCover)} alt="" class="cover" loading="lazy" decoding="async" />
|
||||
{:else}
|
||||
<div class="cover cover-placeholder"></div>
|
||||
{/if}
|
||||
@@ -50,7 +50,7 @@
|
||||
{#if sampleStrip.length > 0}
|
||||
<div class="samples">
|
||||
{#each sampleStrip as key (key)}
|
||||
<img src={fileUrl(key)} alt="" class="sample" loading="lazy" />
|
||||
<img src={fileUrl(key)} alt="" class="sample" loading="lazy" decoding="async" />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
alt=""
|
||||
class="cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</a>
|
||||
<div class="meta">
|
||||
|
||||
@@ -380,6 +380,7 @@
|
||||
src={fileUrl(manga.cover_image_path)}
|
||||
alt=""
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
/>
|
||||
{/if}
|
||||
<div class="hero-text">
|
||||
@@ -401,6 +402,7 @@
|
||||
alt="{manga.title} cover"
|
||||
class="cover"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
data-testid="manga-cover"
|
||||
/>
|
||||
{/if}
|
||||
@@ -791,7 +793,10 @@
|
||||
|
||||
.cover {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
/* Reserve the 2/3 box so the meta column doesn't reflow when the
|
||||
cover decodes (mirrors MangaCard's cover). */
|
||||
aspect-ratio: 2 / 3;
|
||||
object-fit: cover;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user