summaryrefslogtreecommitdiff
path: root/templates/detail.html
diff options
context:
space:
mode:
Diffstat (limited to 'templates/detail.html')
-rw-r--r--templates/detail.html455
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 %}