<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/tests/test_video_detail_measured.py, branch main</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=main</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-02T07:49:41Z</updated>
<entry>
<title>fix(hub): the show detail modal must not move when the season does</title>
<updated>2026-09-02T07:49:41Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-02T07:49:41Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=9e3dfcb8229e0cb3d8e296acd09cf5e2acb9565e'/>
<id>urn:sha1:9e3dfcb8229e0cb3d8e296acd09cf5e2acb9565e</id>
<content type='text'>
The previous pass fixed the synopsis and the cast, and the dialog still
jumped: the episode count moves things a fixed-height synopsis cannot reach.

- The body scrolled as a whole, so a thirteen-episode season pushed the modal
  to its max-height where a six-episode one had not. `.video-overlay` centres
  its child, so the taller modal also *started higher up the screen* — title
  bar, close button and all. `.video-detail-steady` (a multi-season show only)
  gives the modal a height rather than a max-height, makes the body a flex
  column, and hands the leftover to the episode list as the one scrolling
  part. A constant-height box is centred in the same place every time, so both
  halves settle at once.
- A scrolling season draws a scrollbar where a non-scrolling one draws none,
  which is a scrollbar's width of content and re-wrapped the file path above
  it, shifting everything below by a line. `scrollbar-gutter: stable`.
- The season panel was clipped by the modal's own `overflow: hidden` whenever
  the seasons outran the room under the picker — at a 740px viewport it wanted
  320px and had 288, and the rest sat where no scroll could reach it. It is
  `position: fixed` now, placed by `placeSeasonPanel()`, which takes the
  trigger's rect and the window height, picks whichever side has more room,
  and caps the panel to it.

Scoped to multi-season shows throughout: a movie has no season to switch to
and a fixed height would buy it nothing but empty space.

test_video_detail_measured.py now builds each block inside a real
`.video-overlay`, since the centring is half the defect, and asserts the modal
top and height as well as the picker's offset — for a long and a short
synopsis and for a six- and a twenty-four-episode season.
test_season_panel_placement.py runs placeSeasonPanel() in node over a rect and
a window height. Two guards are declarations rather than rectangles and say so
in their docstrings: headless Chrome gives the probe zero-width overlay
scrollbars, so the gutter cannot be measured there.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML
</content>
</entry>
<entry>
<title>fix(hub): steady the show detail modal, and give a series its director</title>
<updated>2026-09-02T01:23:46Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-02T01:13:53Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=12b6dc4dd3e009f2e844d87181800aa12d07a3a6'/>
<id>urn:sha1:12b6dc4dd3e009f2e844d87181800aa12d07a3a6</id>
<content type='text'>
Opening a different season of the same show moved everything under the
synopsis, which is where the season control and the episode list are, so the
thing just clicked was no longer under the pointer.

- The synopsis is exactly three lines for a multi-season show, with a "read
  more" link floated into the third line box (-webkit-line-clamp only ever
  puts its ellipsis at the end of the last line and leaves no room after it).
  Clamped from above and pinned from below to the same number: a constant,
  not a range — a season summary runs two lines and the next one twelve, and
  a band still reads as a jump. Whether three lines is all of it depends on
  the modal's width, so it is measured in the browser and re-measured on a
  resize.
- The cast is clamped to two lines.
- SeasonMenu replaces SeasonTabs: the tab row scrolled sideways once a show
  had more seasons than fit, which is close to unusable on a phone. One
  trigger reading "Season 5 · 1997" and a menu of every season with its
  episode count, one row high whatever the season count.
- media_meta_resp.director was filled from the credits crew's job ==
  "Director", a movie shape. TMDB's aggregate tv_credits crew is routinely
  empty and never carries that job, so every show answered null and the modal
  dropped the line. It now comes from created_by on the show details. Cached
  show metadata keeps its null until TMDB_META_TTL_SECS expires or an
  operator re-matches.

The facts line is joined rather than concatenated (a title with no rating
used to open with " · ") and carries the show's own year next to the
director; the selected season's air year moved onto the picker.

test_video_detail_measured.py asserts rectangles through layout_probe.py, not
declarations: the picker's offset inside its own modal body is the same pixel
either way, the synopsis and cast heights, where the read-more link lands,
and the open menu at 320 px. Each measured block sits in a whole-pixel-height
container, or two identical layouts an eighth of a pixel apart round to tops
one pixel apart. test_tmdb_show_director.py covers the credit.
docs/mediacenter.md §10.4.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML
</content>
</entry>
</feed>
