Skip to content

fix(#298): align catalogue card rows, keeping subtitle space conditional - #302

Merged
fabiodalez-dev merged 6 commits into
mainfrom
fix/book-title-alignment-298
Jul 29, 2026
Merged

fix(#298): align catalogue card rows, keeping subtitle space conditional#302
fabiodalez-dev merged 6 commits into
mainfrom
fix/book-title-alignment-298

Conversation

@fabiodalez-dev

@fabiodalez-dev fabiodalez-dev commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Builds on @Himura2la's #298. The underlying observation is right — the catalogue cards don't line up cleanly — but the proposed change (removing the mobile min-height on .book-title) doesn't fix it: with the 2.8em base rule still global, removing the 2.4em mobile override just makes the title inherit the base (taller, not shorter), and it doesn't touch what actually misaligns the rows.

What actually misaligns the cards

  • .book-title had a fixed min-height of two lines: a 3-line title overflows it and a 1-line title leaves a gap, so author/publisher drift between cards.
  • The subtitle is rendered only when the book has one (.book-author/.book-meta reserve their space with a hidden placeholder; the subtitle didn't). A card with a subtitle pushes everything below it down relative to neighbours without one.

On a real catalogue only a small fraction of books have a subtitle, so reserving that space on every card (my first attempt) wastes it on most rows.

Fix — conditional space, aligned per row

Keep the subtitle conditional, and equalise per grid row with a small layout script:

  • every title in a row is set to the row's tallest title;
  • shorter real subtitles in a row are padded to the tallest;
  • cards in a subtitle row that have no subtitle get a hidden .book-subtitle placeholder (same margins) of that height.

So a row with no subtitle stays compact, and a row that contains one lines up title → subtitle → author → publisher → "Details" across all its cards. It recomputes on resize. Pure layout — only heights are touched; colours stay on the theme variables, so it's identical across every theme and in dark mode.

Tests

tests/catalog-subtitle-align-298.spec.js seeds a catalogue with plain and subtitled books and asserts, per row: subtitle rows keep authors aligned across cards, a placeholder is reserved on their plain cards, and subtitle-less rows get none. (This test caught a real bug during development: two subtitles of different length in the same row — now fixed by equalising the real subtitles too.)

Full-tree PHPStan level 5 clean.

Summary by CodeRabbit

  • Miglioramenti
    • Migliorata la resa delle card nel catalogo per un allineamento più preciso di titolo, autore e metadati, anche con testi lunghi.
    • Troncamento coerente: titolo fino a 2 righe; autore e metadati su 1 riga.
    • Riallineamento per riga della griglia con gestione dei sottotitoli opzionali per mantenere l’aspetto ordinato al resize e in responsive.
  • Test
    • Aggiunta una nuova verifica E2E per validare l’allineamento per riga con/senza sottotitolo, includendo scenari mobile e aggiornamenti via filtri/sort.

…e-less rows

The book title had a fixed min-height and the subtitle was rendered only when
present, so cards with a subtitle pushed author/publisher/"Details" down out of
line with their neighbours, while cards with a short title left a gap. #298
proposed removing the mobile min-height, but that only makes the title inherit
the 2.8em base (taller, not shorter) and doesn't address alignment.

Instead: keep the subtitle conditional (no reserved space on the majority of
rows that have none) and equalise per grid row with a small layout script — it
sets every title in a row to the row's tallest title, pads the shorter real
subtitles, and injects a hidden .book-subtitle placeholder on the cards of a
subtitle row that have none. Result: rows with no subtitle stay compact; rows
that contain one line up title → subtitle → author → publisher → Details across
all their cards. Pure layout (heights only) — colours stay on the theme
variables, so it's identical across themes.

tests/catalog-subtitle-align-298.spec.js seeds a catalogue with plain and
subtitled books and asserts, per row: subtitle rows keep authors aligned, a
placeholder is reserved on their plain cards, and subtitle-less rows get none.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 62a50b4d-e0c3-4a64-8a70-108771cdb051

📥 Commits

Reviewing files that changed from the base of the PR and between 9b7e97b and 338387b.

📒 Files selected for processing (3)
  • app/Views/frontend/catalog-grid.php
  • app/Views/frontend/catalog.php
  • tests/catalog-subtitle-align-298.spec.js

📝 Walkthrough

Walkthrough

La griglia catalogo usa troncamenti CSS per titoli, autori e metadati. Uno script equalizza titolo e sottotitolo per riga, creando placeholder nascosti quando necessario e reagendo agli aggiornamenti AJAX. Una spec Playwright verifica i casi desktop, mobile e multi-griglia.

Changes

Allineamento delle card catalogo

Layer / File(s) Summary
Vincoli CSS per il contenuto delle card
app/Views/frontend/catalog-grid.php
I titoli sono limitati a due righe; autori e metadati usano contenitori a riga singola con altezza fissa e troncamento.
Equalizzazione per riga e aggiornamenti AJAX
app/Views/frontend/catalog-grid.php
app/Views/frontend/catalog.php
Lo script equalizza le altezze per riga, inserisce subtitle-ph dove manca il sottotitolo e ripete l’allineamento dopo gli aggiornamenti della griglia.
Verifica E2E dei casi di allineamento
tests/catalog-subtitle-align-298.spec.js
La spec prepara dati controllati e verifica allineamento, layout mobile, refresh AJAX e isolamento tra griglie.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Catalogo
  participant BooksGrid
  participant ScriptAllineamento
  participant Card
  Catalogo->>BooksGrid: aggiorna le card via AJAX
  BooksGrid->>ScriptAllineamento: dispatch pinakes:catalog-grid-updated
  ScriptAllineamento->>Card: raggruppa per riga e misura le altezze
  ScriptAllineamento->>Card: applica altezze e placeholder subtitle-ph
  Card-->>BooksGrid: restituisce il layout riallineato
Loading

Possibly related PRs

  • fabiodalez-dev/Pinakes#298: modifica lo styling di .book-title nello stesso template, intervenendo sul precedente utilizzo di min-height.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Il titolo riassume correttamente l’allineamento delle card del catalogo e la gestione condizionale dello spazio del sottotitolo.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/book-title-alignment-298

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/Views/frontend/catalog-grid.php (1)

200-211: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Allinea line-height a height in .book-author.

height: 1.3em con font-size fixed funziona solo se la riga è calcolata su 1.3; senza line-height esplicito il testo può essere tagliato sopra/sotto dal box con overflow: hidden. Imposta lo stesso valore coerente tra font-size, height e line-height.

🛠️ Fix proposto
 .book-author {
     font-size: 0.875rem;
     color: var(--text-secondary);
     margin-bottom: 0.5rem;
     /* `#298`: fixed single-line box so a long author name can't push the row
        below out of alignment with adjacent cards. */
     height: 1.3em;
+    line-height: 1.3;
     display: -webkit-box;
     -webkit-line-clamp: 1;
     -webkit-box-orient: vertical;
     overflow: hidden;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Views/frontend/catalog-grid.php` around lines 200 - 211, Update the
.book-author rule to define an explicit line-height matching its 1.3em height,
keeping the font-size and single-line clamping behavior aligned so the text is
not vertically clipped.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Views/frontend/catalog-grid.php`:
- Around line 324-357: Limit row grouping to each individual .books-grid
container instead of combining all .book-card elements globally. Update align()
to iterate over every .books-grid and call rowsOf() only with that grid’s cards,
preserving separate title/subtitle sizing and placeholder creation for each
grid.

---

Outside diff comments:
In `@app/Views/frontend/catalog-grid.php`:
- Around line 200-211: Update the .book-author rule to define an explicit
line-height matching its 1.3em height, keeping the font-size and single-line
clamping behavior aligned so the text is not vertically clipped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 01d512c1-730b-4b39-a352-22f7a36e1f2e

📥 Commits

Reviewing files that changed from the base of the PR and between 96f2745 and 5ada527.

📒 Files selected for processing (2)
  • app/Views/frontend/catalog-grid.php
  • tests/catalog-subtitle-align-298.spec.js

Comment thread app/Views/frontend/catalog-grid.php Outdated
CodeRabbit: align() grouped every .book-card on the page by vertical position,
so if a page renders two .books-grid containers, cards from different grids at
the same top could be merged into one logical row and get wrong placeholders /
heights. Iterate over each .books-grid and group only its own cards.
…ight

CodeRabbit: .book-author has height:1.3em + overflow:hidden but no explicit
line-height, so the default (~1.2) could clip the single line top/bottom. Set
line-height:1.3 to match the box height (.book-meta already pairs 1.5/1.5em).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/Views/frontend/catalog-grid.php (1)

38-38: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Usare JSON_HEX_TAG nella serializzazione inline.

$defaultCoverUrl viene inserito nell’handler JavaScript senza JSON_HEX_TAG. Anche se oggi il valore deriva da un path fisso, la view viola il requisito di sicurezza per app/Views/** e resta fragile se il valore diventa configurabile.

Proposta
-                         onerror="this.onerror=null;this.src=<?= htmlspecialchars(json_encode($defaultCoverUrl), ENT_QUOTES, 'UTF-8') ?>">
+                         onerror="this.onerror=null;this.src=<?= htmlspecialchars(json_encode($defaultCoverUrl, JSON_HEX_TAG), ENT_QUOTES, 'UTF-8') ?>">

As per path instructions, le view devono usare json_encode(..., JSON_HEX_TAG) per ogni dato PHP inserito in JavaScript.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Views/frontend/catalog-grid.php` at line 38, Aggiorna la serializzazione
di $defaultCoverUrl nell’attributo onerror della view per includere JSON_HEX_TAG
insieme alle opzioni esistenti di json_encode. Mantieni invariati
htmlspecialchars e il comportamento di fallback dell’immagine, assicurando che
ogni dato PHP inserito in JavaScript usi la codifica richiesta.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Views/frontend/catalog-grid.php`:
- Around line 382-386: Aggiungere una regressione in
tests/catalog-subtitle-align-298.spec.js che renderizzi due elementi .books-grid
con card alla stessa coordinata verticale, quindi verifichi separatamente
l’allineamento delle card all’interno di ciascuna griglia. Evitare raccolte o
asserzioni globali: usare ciascun .books-grid come ambito indipendente per
confermare che le righe non vengano unite tra griglie.

---

Outside diff comments:
In `@app/Views/frontend/catalog-grid.php`:
- Line 38: Aggiorna la serializzazione di $defaultCoverUrl nell’attributo
onerror della view per includere JSON_HEX_TAG insieme alle opzioni esistenti di
json_encode. Mantieni invariati htmlspecialchars e il comportamento di fallback
dell’immagine, assicurando che ogni dato PHP inserito in JavaScript usi la
codifica richiesta.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 953f64f8-7bda-4932-8363-380ae4ce0774

📥 Commits

Reviewing files that changed from the base of the PR and between 5ada527 and 9b7e97b.

📒 Files selected for processing (1)
  • app/Views/frontend/catalog-grid.php

Comment thread app/Views/frontend/catalog-grid.php
CodeRabbit: the spec only exercised a single grid, so a return to global row
grouping wouldn't be caught. Add a case that builds two side-by-side grids
sharing the same row top, and asserts a subtitle in grid A reserves space only
within grid A — grid B (no subtitle) is untouched.
@fabiodalez-dev

Copy link
Copy Markdown
Owner Author

Fixed the post-AJAX alignment gap in a7810c0. The catalogue now emits a dedicated event after replacing grid HTML; the alignment handler reruns for filter/sort/pagination refreshes. Added a real Playwright regression that changes sorting through AJAX and verifies replacement-card alignment (targeted spec: 3/3 pass).

Five review findings on the alignment script/test:

1. The script measured heights on DOMContentLoaded/load only, never on
   document.fonts.ready — a late web-font swap could reflow a title from one to
   two lines after the pass, clipping it (line-clamp + fixed height) and leaving
   the row misaligned until a resize. Now re-aligns on fonts.ready.
2. Layout thrashing: alignGrid() interleaved reads (getBoundingClientRect /
   offsetHeight) and writes (height) row by row, forcing repeated synchronous
   reflows, and ran twice on initial load. Split into a single READ phase then a
   single WRITE phase, and coalesced all triggers (load, resize, AJAX, fonts)
   through one requestAnimationFrame.
3. equalise wrote height:0px when every card measured 0 (grid inside a
   display:none ancestor), collapsing titles. Now skips a row whose titles
   measure 0 (not laid out).
4. Added a mobile single-column test (375px): asserts one column, zero spurious
   placeholders, and no zero-height titles — a path the suite never exercised.
5. Test 1 now waits for document.fonts.ready before measuring (was a fixed 600ms
   that could sample a pre-font-swap layout) and pins its assertions to the
   seeded fixture so ambient data can't silently substitute unrelated books.

Verified: all 4 E2E tests green (alignment unchanged for the asserted cases).
@fabiodalez-dev

Copy link
Copy Markdown
Owner Author

Self-reviewed the alignment script before release. All findings P2; fixed in 338387b:

  • Re-align on document.fonts.ready: the pass ran on DOMContentLoaded/load only, so a late web-font swap could reflow a title from one line to two after alignment, clipping it (line-clamp + fixed height) and leaving the row misaligned until a resize.
  • Removed layout thrashing: alignGrid() interleaved reads (getBoundingClientRect/offsetHeight) and writes (height) row by row, and ran twice on initial load. Split into a single READ phase then a single WRITE phase, and coalesced every trigger (load, resize, AJAX, fonts) through one requestAnimationFrame.
  • Zero-height guard: skips a row whose titles measure 0 (grid inside a display:none ancestor) rather than collapsing every title to 0px.
  • Mobile single-column test (375px): asserts one column, zero spurious placeholders, no zero-height titles — a path the suite never exercised.
  • Test 1 now waits for document.fonts.ready (was a fixed 600ms that could sample a pre-swap layout) and pins its assertions to the seeded fixture.

All 4 E2E tests green; alignment behaviour unchanged for the asserted cases. Cross-checked against #303: disjoint regions in the catalogue views, no semantic conflict.

@fabiodalez-dev
fabiodalez-dev merged commit 6b10c69 into main Jul 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant