diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-14 01:31:34 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-14 01:31:34 -0700 |
| commit | cdd28b6c0a3a6444b9ae79b123fe4fa7401de5ab (patch) | |
| tree | 6e04f0ca2d05825d98a1c78b56eb7c30752b4657 /templates/detail.html | |
| parent | 4279408876268f4960c98492d3814f5475e36e38 (diff) | |
Refine Lumi layouts and public profile
Diffstat (limited to 'templates/detail.html')
| -rw-r--r-- | templates/detail.html | 455 |
1 files changed, 282 insertions, 173 deletions
diff --git a/templates/detail.html b/templates/detail.html index 9c558f7..f51372d 100644 --- a/templates/detail.html +++ b/templates/detail.html @@ -17,236 +17,335 @@ <button type="button" id="change-poster-btn" - class="secondary-button" - style="width: 100%; margin-top: 12px;" + class="secondary-button detail-poster-button" data-tmdb-id="{{ film.tmdb_id }}" data-film-id="{{ film.id }}" >Change Poster</button> - - <div id="poster-picker" style="display: none; margin-top: 12px;"> - <p id="poster-picker-status" style="color: var(--muted); font-size: 0.86rem; margin: 0 0 10px;">Loading posters…</p> - <div id="poster-grid" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;"></div> - </div> {% endif %} - - <div class="detail-aside-meta"> - <div> - <span class="summary-label">Shelf</span> - <strong>{{ film.shelf|title }}</strong> - </div> - <div> - <span class="summary-label">Watched</span> - <strong>{% if film.date_watched %}{{ film.date_watched }}{% else %}Not set{% endif %}</strong> - </div> - <div> - <span class="summary-label">Stars</span> - <strong>{% if film.stars %}{% for _ in range(film.stars) %}✦{% endfor %}{% else %}Unstarred{% endif %}</strong> - </div> - </div> </aside> <section class="detail-body"> - <p class="eyebrow">{{ film.shelf|title }} Entry</p> - <h1>{{ film.title }}</h1> - {% if film.original_title %} - <p class="original-title">{{ film.original_title }}</p> - {% endif %} - <div class="detail-subtitle"> - <p class="subtitle"> - {% if film.year %}{{ film.year }}{% endif %} - {% set directors = split_credit_names(film.director) %} - {% if directors %} - {% if film.year %} · {% endif %} - {% for director in directors %} - <a class="inline-link" href="{{ director_href(director) }}">{{ director }}</a>{% if not loop.last %}, {% endif %} - {% endfor %} + <section class="detail-hero"> + <div class="detail-hero-copy"> + <p class="eyebrow">{{ film.shelf|title }} Entry</p> + <h1>{{ film.title }}</h1> + {% if film.original_title %} + <p class="original-title">{{ film.original_title }}</p> {% endif %} - </p> - {% if ratings %} - <div class="ratings-inline"> - {% if ratings.imdb %} - <span class="rating-badge"> - <img src="/static/logos/imdb.svg" alt="IMDb" height="18"> - <span>{{ ratings.imdb }}</span> - </span> - {% endif %} - {% if ratings.rt %} - <span class="rating-badge"> - <img src="/static/logos/rt.svg" alt="Rotten Tomatoes" height="18"> - <span>{{ ratings.rt }}</span> - </span> - {% endif %} - {% if ratings.metacritic %} - <span class="rating-badge"> - <img src="/static/logos/metacritic.svg" alt="Metacritic" height="18"> - <span>{{ ratings.metacritic }}</span> - </span> + <div class="detail-subtitle"> + <p class="subtitle"> + {% if film.year %}{{ film.year }}{% endif %} + {% set directors = split_credit_names(film.director) %} + {% if directors %} + {% if film.year %} · {% endif %} + {% for director in directors %} + <a class="inline-link" href="{{ director_href(director) }}">{{ director }}</a>{% if not loop.last %}, {% endif %} + {% endfor %} + {% endif %} + </p> + {% if ratings %} + <div class="ratings-inline"> + {% if ratings.imdb %} + <span class="rating-badge"> + <img src="/static/logos/imdb.svg" alt="IMDb" height="18"> + <span>{{ ratings.imdb }}</span> + </span> + {% endif %} + {% if ratings.rt %} + <span class="rating-badge"> + <img src="/static/logos/rt.svg" alt="Rotten Tomatoes" height="18"> + <span>{{ ratings.rt }}</span> + </span> + {% endif %} + {% if ratings.metacritic %} + <span class="rating-badge"> + <img src="/static/logos/metacritic.svg" alt="Metacritic" height="18"> + <span>{{ ratings.metacritic }}</span> + </span> + {% endif %} + </div> + {% endif %} + </div> + </div> + + <div class="detail-actions"> + <a class="secondary-button" href="/films/{{ film.id }}/edit">Edit</a> + {% if film.shelf == 'queue' %} + <a class="button-link" href="/films/{{ film.id }}/edit?shelf=diary">Mark watched</a> + <form method="post" action="/films/{{ film.id }}/shelf/abandoned"> + <button class="secondary-button" type="submit">Abandon</button> + </form> + {% elif film.shelf == 'diary' %} + <form method="post" action="/films/{{ film.id }}/shelf/queue"> + <button class="secondary-button" type="submit">Move to queue</button> + </form> + <form method="post" action="/films/{{ film.id }}/shelf/abandoned"> + <button class="secondary-button" type="submit">Mark abandoned</button> + </form> + {% else %} + <a class="button-link" href="/films/{{ film.id }}/edit?shelf=diary">Mark watched</a> + <form method="post" action="/films/{{ film.id }}/shelf/queue"> + <button class="secondary-button" type="submit">Move to queue</button> + </form> {% endif %} + <form method="post" action="/films/{{ film.id }}/delete"> + <button class="danger-button" type="submit">Delete</button> + </form> </div> - {% endif %} - </div> + </section> - <section class="detail-grid"> - <article class="detail-panel"> - <p class="eyebrow">Watch log</p> - <div class="detail-meta"> - {% if film.date_watched %}<span>{{ film.date_watched }}</span>{% endif %} - {% if film.runtime %}<span>{{ film.runtime }} min</span>{% endif %} - {% if film.rewatch %}<span>Rewatch{% if film.rewatch_count %} #{{ film.rewatch_count }}{% endif %}</span>{% endif %} - {% if film.watched_with %}<span>With {{ film.watched_with }}</span>{% endif %} - {% if film.context %}<span>{{ film.context }}</span>{% endif %} - {% if film.how_found %}<span>{{ film.how_found }}</span>{% endif %} + <section class="detail-columns"> + <aside class="detail-sidebar"> + <div class="detail-aside-meta"> + <div> + <span class="summary-label">Shelf</span> + <strong>{{ film.shelf|title }}</strong> + </div> + <div> + <span class="summary-label">Watched</span> + <strong>{% if film.date_watched %}{{ film.date_watched }}{% else %}Not set{% endif %}</strong> + </div> + <div> + <span class="summary-label">Stars</span> + <strong>{% if film.stars %}{% for _ in range(film.stars) %}✦{% endfor %}{% else %}Unstarred{% endif %}</strong> + </div> </div> - </article> - <article class="detail-panel"> - <p class="eyebrow">Production</p> - <div class="detail-meta"> - {% if film.genre %}<span>{{ film.genre }}</span>{% endif %} - {% if film.country %}<span>{{ film.country }}</span>{% endif %} - {% if film.language %}<span>{{ film.language }}</span>{% endif %} - {% if film.year %}<span>{{ film.year }}</span>{% endif %} - {% if film.tmdb_id %}<span>TMDB {{ film.tmdb_id }}</span>{% endif %} - </div> - </article> - </section> + <article class="detail-panel"> + <p class="eyebrow">Watch log</p> + <div class="fact-list"> + {% if film.date_watched %} + <div class="fact-row"> + <span class="fact-label">Watched</span> + <span class="fact-value">{{ film.date_watched }}</span> + </div> + {% endif %} + {% if film.runtime %} + <div class="fact-row"> + <span class="fact-label">Runtime</span> + <span class="fact-value">{{ film.runtime }} min</span> + </div> + {% endif %} + {% if film.rewatch %} + <div class="fact-row"> + <span class="fact-label">Rewatch</span> + <span class="fact-value">Yes{% if film.rewatch_count %} · #{{ film.rewatch_count }}{% endif %}</span> + </div> + {% endif %} + {% if film.watched_with %} + <div class="fact-row"> + <span class="fact-label">With</span> + <span class="fact-value">{{ film.watched_with }}</span> + </div> + {% endif %} + {% if film.context %} + <div class="fact-row"> + <span class="fact-label">Context</span> + <span class="fact-value">{{ film.context }}</span> + </div> + {% endif %} + {% if film.how_found %} + <div class="fact-row"> + <span class="fact-label">Found</span> + <span class="fact-value">{{ film.how_found }}</span> + </div> + {% endif %} + </div> + </article> - {% if rewatch_history|length > 1 %} - <section class="detail-panel"> - <p class="eyebrow">Rewatches</p> - <div class="rewatch-list"> - {% for entry in rewatch_history %} - <div class="rewatch-row"> - <div> - <p class="rewatch-meta">{{ entry.date_watched }}</p> - <p class="rewatch-rating"> - <span class="rewatch-stars">{% for _ in range(entry.stars) %}✦{% endfor %}</span> - {% if entry.watched_with %}<span class="rewatch-companion">with {{ entry.watched_with }}</span>{% endif %} - </p> + <article class="detail-panel"> + <p class="eyebrow">Production</p> + <div class="fact-list"> + {% if film.genre %} + <div class="fact-row"> + <span class="fact-label">Genre</span> + <span class="fact-value">{{ film.genre }}</span> + </div> + {% endif %} + {% if film.country %} + <div class="fact-row"> + <span class="fact-label">Country</span> + <span class="fact-value">{{ film.country }}</span> + </div> + {% endif %} + {% if film.language %} + <div class="fact-row"> + <span class="fact-label">Lang</span> + <span class="fact-value">{{ film.language }}</span> + </div> + {% endif %} + {% if film.year %} + <div class="fact-row"> + <span class="fact-label">Year</span> + <span class="fact-value">{{ film.year }}</span> + </div> + {% endif %} + {% if film.tmdb_id %} + <div class="fact-row"> + <span class="fact-label">TMDB</span> + <span class="fact-value">{{ film.tmdb_id }}</span> + </div> + {% endif %} </div> - {% if not loop.first %} - <span class="rewatch-delta"> - {% set prev_entry = rewatch_history[loop.index - 2] %} - {% if prev_entry.date_watched %} - {% set days = (entry.date_watched - prev_entry.date_watched).days %} - {{ days }}d - {% if entry.stars != prev_entry.stars %} - <span class="rewatch-delta-rating">({{ prev_entry.stars }}→{{ entry.stars }})</span> + </article> + </aside> + + <div class="detail-main"> + {% if tmdb_context %} + <section class="detail-panel detail-panel-feature"> + <p class="eyebrow">Summary</p> + {% if tmdb_context.tagline %} + <p class="detail-tagline">{{ tmdb_context.tagline }}</p> + {% endif %} + {% if tmdb_context.overview %} + <p class="detail-overview">{{ tmdb_context.overview }}</p> {% endif %} + {% if tmdb_context.cast %} + <div class="detail-cast"> + <span class="summary-label">Cast</span> + <p>{{ tmdb_context.cast|join(", ") }}</p> + </div> {% endif %} - </span> + </section> + {% endif %} + + <section class="detail-panel detail-panel-feature"> + <p class="eyebrow">Notes</p> + {% if film.notes %} + <div class="notes-body">{{ film.notes }}</div> + {% else %} + <p class="muted">No notes saved.</p> {% endif %} - </div> - {% endfor %} - </div> - </section> - {% endif %} + </section> - {% if tmdb_context %} - <section class="detail-panel"> - <p class="eyebrow">Summary</p> - {% if tmdb_context.tagline %} - <p class="detail-tagline">{{ tmdb_context.tagline }}</p> - {% endif %} - {% if tmdb_context.overview %} - <p class="detail-overview">{{ tmdb_context.overview }}</p> - {% endif %} - {% if tmdb_context.cast %} - <div class="detail-cast"> - <span class="summary-label">Cast</span> - <p>{{ tmdb_context.cast|join(", ") }}</p> + {% if rewatch_history|length > 1 %} + <section class="detail-panel"> + <p class="eyebrow">Rewatches</p> + <div class="rewatch-list"> + {% for entry in rewatch_history %} + <div class="rewatch-row"> + <div> + <p class="rewatch-meta">{{ entry.date_watched }}</p> + <p class="rewatch-rating"> + <span class="rewatch-stars">{% for _ in range(entry.stars) %}✦{% endfor %}</span> + {% if entry.watched_with %}<span class="rewatch-companion">with {{ entry.watched_with }}</span>{% endif %} + </p> + </div> + {% if not loop.first %} + <span class="rewatch-delta"> + {% set prev_entry = rewatch_history[loop.index - 2] %} + {% if prev_entry.date_watched %} + {% set days = (entry.date_watched - prev_entry.date_watched).days %} + {{ days }}d + {% if entry.stars != prev_entry.stars %} + <span class="rewatch-delta-rating">({{ prev_entry.stars }}→{{ entry.stars }})</span> + {% endif %} + {% endif %} + </span> + {% endif %} + </div> + {% endfor %} </div> + </section> {% endif %} - </section> - {% endif %} - - <section class="detail-panel"> - <p class="eyebrow">Notes</p> - {% if film.notes %} - <div class="notes-body">{{ film.notes }}</div> - {% else %} - <p class="muted">No notes saved.</p> - {% endif %} + </div> </section> - - <div class="detail-actions"> - <a class="secondary-button" href="/films/{{ film.id }}/edit">Edit</a> - {% if film.shelf == 'queue' %} - <a class="button-link" href="/films/{{ film.id }}/edit?shelf=diary">Mark watched</a> - <form method="post" action="/films/{{ film.id }}/shelf/abandoned"> - <button class="secondary-button" type="submit">Abandon</button> - </form> - {% elif film.shelf == 'diary' %} - <form method="post" action="/films/{{ film.id }}/shelf/queue"> - <button class="secondary-button" type="submit">Move to queue</button> - </form> - <form method="post" action="/films/{{ film.id }}/shelf/abandoned"> - <button class="secondary-button" type="submit">Mark abandoned</button> - </form> - {% else %} - <a class="button-link" href="/films/{{ film.id }}/edit?shelf=diary">Mark watched</a> - <form method="post" action="/films/{{ film.id }}/shelf/queue"> - <button class="secondary-button" type="submit">Move to queue</button> - </form> - {% endif %} - <form method="post" action="/films/{{ film.id }}/delete"> - <button class="danger-button" type="submit">Delete</button> - </form> - </div> </section> </article> + {% if film.tmdb_id %} + <div id="poster-picker-modal" class="poster-picker-modal" hidden> + <div class="poster-picker-backdrop" data-close-poster-picker></div> + <div class="poster-picker-dialog" role="dialog" aria-modal="true" aria-labelledby="poster-picker-title"> + <div class="poster-picker-head"> + <div> + <p class="eyebrow">Poster Archive</p> + <h2 id="poster-picker-title">Choose a poster for {{ film.title }}</h2> + </div> + <button type="button" class="secondary-button poster-picker-close" data-close-poster-picker>Close</button> + </div> + <p id="poster-picker-status" class="poster-picker-status">Loading posters…</p> + <div id="poster-grid" class="poster-grid"></div> + </div> + </div> + {% endif %} + {% if film.tmdb_id %} <script> (function () { const btn = document.getElementById("change-poster-btn"); - const picker = document.getElementById("poster-picker"); + const modal = document.getElementById("poster-picker-modal"); const grid = document.getElementById("poster-grid"); const status = document.getElementById("poster-picker-status"); const filmId = btn.dataset.filmId; const tmdbId = btn.dataset.tmdbId; + const closeControls = document.querySelectorAll("[data-close-poster-picker]"); + const posterImg = document.querySelector(".poster-large img"); let loaded = false; + let lastFocused = null; + let currentPosterUrl = posterImg ? posterImg.src : ""; - btn.addEventListener("click", async () => { - if (picker.style.display === "none") { - picker.style.display = "block"; - btn.textContent = "Close"; + function syncCurrentPosterOption(url) { + grid.querySelectorAll(".poster-option").forEach((button) => { + const isCurrent = button.dataset.url === url; + button.classList.toggle("is-current", isCurrent); + const badge = button.querySelector(".poster-option-badge"); + if (badge) { + badge.hidden = !isCurrent; + } + }); + } + + function openPicker() { + lastFocused = document.activeElement; + modal.hidden = false; + document.body.classList.add("modal-open"); + } + + function closePicker() { + modal.hidden = true; + document.body.classList.remove("modal-open"); + btn.textContent = "Change Poster"; + if (lastFocused instanceof HTMLElement) { + lastFocused.focus(); } else { - picker.style.display = "none"; - btn.textContent = "Change Poster"; - return; + btn.focus(); } + } + + btn.addEventListener("click", async () => { + openPicker(); if (loaded) return; status.textContent = "Loading posters…"; - status.style.display = "block"; + status.hidden = false; try { const resp = await fetch(`/tmdb/posters?tmdb_id=${tmdbId}`); if (!resp.ok) throw new Error("fetch failed"); const data = await resp.json(); - status.style.display = "none"; + status.hidden = true; if (!data.posters.length) { status.textContent = "No posters found."; - status.style.display = "block"; + status.hidden = false; return; } grid.innerHTML = data.posters.map((url) => ` - <button type="button" class="poster-option" data-url="${url}" style="padding: 0; border: 2px solid transparent; border-radius: 6px; overflow: hidden; cursor: pointer; background: none;"> - <img src="${url}" alt="Poster option" loading="lazy" style="width: 100%; display: block; aspect-ratio: 2/3; object-fit: cover;"> + <button type="button" class="poster-option" data-url="${url}"> + <img src="${url}" alt="Poster option" loading="lazy"> + <span class="poster-option-badge" ${currentPosterUrl === url ? "" : "hidden"}>Current</span> </button> `).join(""); + syncCurrentPosterOption(currentPosterUrl); + grid.querySelectorAll(".poster-option").forEach((optBtn) => { optBtn.addEventListener("click", async () => { const url = optBtn.dataset.url; - grid.querySelectorAll(".poster-option").forEach((b) => b.style.borderColor = "transparent"); - optBtn.style.borderColor = "var(--accent)"; - try { const saveResp = await fetch(`/films/${filmId}/poster`, { method: "POST", @@ -255,10 +354,10 @@ }); if (!saveResp.ok) return; - const posterImg = document.querySelector(".poster-large img"); if (posterImg) posterImg.src = url; - picker.style.display = "none"; - btn.textContent = "Change Poster"; + currentPosterUrl = url; + syncCurrentPosterOption(url); + closePicker(); } catch (err) { console.error("Failed to save poster", err); } @@ -271,6 +370,16 @@ console.error(err); } }); + + closeControls.forEach((control) => { + control.addEventListener("click", closePicker); + }); + + document.addEventListener("keydown", (event) => { + if (event.key === "Escape" && !modal.hidden) { + closePicker(); + } + }); })(); </script> {% endif %} |
