Skip to content

feat(quicklook): one detail modal everywhere — search, dashboard & Explorer#69

Open
ndandan wants to merge 13 commits into
Shoshuo:mainfrom
ndandan:pr/search-detail-modal
Open

feat(quicklook): one detail modal everywhere — search, dashboard & Explorer#69
ndandan wants to merge 13 commits into
Shoshuo:mainfrom
ndandan:pr/search-detail-modal

Conversation

@ndandan

@ndandan ndandan commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What

One detail modal everywhere. Clicking a result in top-bar search, a dashboard tile, or a Discover/Explorer poster now opens the same app-wide quick-look modal — with rich detail and a context-aware action.

This started as "open the quick-look from search" and, following review feedback (thanks!), grew to fold the Discovery/Explorer modal's richer content into that single quick-look and retire the page-bound modal — one component to maintain instead of two.

  • Rich body — backdrop, poster, rating, genres, cast, streaming providers, trailer, TMDb/IMDb links, watchlist ☆.
  • Release / air dates — movies: theater / digital / physical (next upcoming emphasised); TV: a Continuing / Ended pill + first-aired and next-episode (or end) dates.
  • ActionManage (deep-link to the exact Radarr/Sonarr instance) when the title is in a library; Add (the shared quick-add flow) when it isn't.

How

  • The quick-look is app-global (templates/_quicklook.html.twig, included by base.html.twig) — used by search, dashboard tiles and Explorer.
  • Action model resolved server-side. quickLookTmdb cross-references the cached Radarr/Sonarr libraries (quickLookLibraryMatch) to decide Manage-vs-Add, so every entry point behaves the same. Fails open: if the library can't be read it offers Add rather than erroring.
  • No extra API calls — cast / providers / trailer / IMDb come straight out of the payload getMovie/getTv already append (append_to_response).
  • Explorer page repointed at the global quick-look; its bespoke ex-detail-modal (~270 lines of markup/CSS/JS) is deleted. The search-side decorateAction patching is gone too — the server-rendered body is authoritative (which also fixes online-in-library results deep-linking to the right instance instead of the default).
  • A shared [data-ql-add] handler resolves the TMDb id then hands off to the existing quick-add picker. Library items with no tmdbId degrade gracefully.

The modal fails open to a small graceful body. Labels are i18n'd (en + fr).

Tests / DoD

  • DashboardControllerTest covers the movie/series view-model builders (library + TMDb), the cast/providers/trailer extraction + external ids, and the in-library Manage deep-link / fail-open Add paths.
  • Full suite green (lint + Twig + PHPUnit).
  • Beta-tested end-to-end on a live instance (Unraid): search, dashboard and Explorer all open the unified modal with correct Manage/Add behaviour.
  • CHANGELOG [Unreleased] updated.

Additive and opt-in — no behavioural change to existing pages beyond results now opening the richer modal, and the Explorer page using the shared one.

ndandan and others added 13 commits June 26, 2026 20:56
… model

Add movieReleaseChips() and tmdbMovieReleaseDates() private helpers to
DashboardController. Wire releaseDates key into both quickLookLibrary
(from Radarr inCinemasAt/digitalAt/physicalAt fields) and quickLookTmdb
(parsed from TMDb release_dates.results append). Series gets empty list;
movies get fixed-order cinema→digital→physical chips with upcoming flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…odel

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds testQuickLookLibrarySeriesEndedShowsEndDate to pin that a Sonarr
series with status=ended emits airStatus='ended', includes both the
first_aired and ended release chips from previousAiring, and must NOT
emit a next_episode chip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…partial

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…es + Add/Manage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s series

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s emphasis

Adds .ql-dates flex row, .ql-date pill chips (label+value layout), .ql-date.is-upcoming
accent emphasis via var(--tblr-primary), and .ql-airstatus badge with is-continuing
(green) / is-ended (muted) modifiers. Colour strategy follows existing rgba+Tabler-
variable pattern for automatic light/dark adaptation; no new raw hex introduced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Continuing/Ended pill sat in a flex row beside the taller two-line
date chips and stretched to their height with its text pinned to the top.
Center the row's items and make the pill an inline-flex that centers its
own label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upstream's DashboardController has no DashboardLayoutService dependency
(a fork-only feature), so the new quick-look tests construct it with the
upstream 11-arg signature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…watchlist

Fold the Discovery (Explorer) modal's richer content into the global
quick-look so one modal serves the dashboard, top-bar search and (next)
the Explorer page — the maintainer's "one modal, more info, less code"
ask, reached by building on the more capable quick-look rather than the
page-bound Explorer modal (keeps library-aware Manage deep-links +
release-date chips).

- quickLookTmdb: extract cast/providers/trailer/imdb via new
  quickLookExtras() — zero extra API calls (data already in the
  append_to_response payload). Carries tmdbId/tmdbType/posterPath.
- _quicklook_body: cast strip, providers row, trailer embed, TMDb/IMDb
  links, watchlist button (all |default-guarded -> library items
  unchanged).
- _quicklook: global watchlist index bootstrap + delegated toggle;
  a MutationObserver reflects state onto the button on each fragment
  load (no per-call-site wiring).
- i18n (en/fr) + CSS; test for cast/providers/trailer scoring + ids.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 3 — repoint the Explorer/Discover page at the app-wide quick-look
and delete its bespoke ex-detail-modal (~270 lines of markup/CSS/JS), so
one modal serves dashboard, search and Explorer. This is the maintainer's
"one modal, more info, less code" ask, reached by enriching the quick-look
rather than adopting the page-bound Explorer modal.

To make that lossless, the quick-look now resolves the action model
server-side:
- quickLookTmdb cross-references the cached Radarr/Sonarr libraries
  (quickLookLibraryMatch) — in-library => Manage deep-link to the exact
  instance + status badge; otherwise the body renders an Add button.
  Fail-open: a library read error degrades to Add, never errors.
- _quicklook_body: Manage link vs Add button (data-ql-add).
- _quicklook: global [data-ql-add] handler resolves TMDb -> *arr then
  hands off to the shared quick-add picker (mirrors the old Explorer Add).
- base.html.twig: drop the now-redundant search decorateAction — the body
  is authoritative (also fixes online-in-library deep-links to the right
  instance instead of the default).
- explorer: card click opens window.prismarrQl; ex-detail-modal removed.
  Grid stars + filters + watchlist bootstrap kept.

Tests: in-library Manage deep-link + fail-open Add paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ndandan ndandan changed the title feat(search): rich detail modal from top-bar search with release/air dates feat(quicklook): one detail modal everywhere — search, dashboard & Explorer Jun 27, 2026
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