From a3df69ff5218cee132a6def9d860cd0276cc0cd4 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Wed, 6 May 2026 14:34:01 -0700 Subject: Add year review and inline diary ratings --- static/app.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'static/app.js') diff --git a/static/app.js b/static/app.js index 01b1d79..e2213f3 100644 --- a/static/app.js +++ b/static/app.js @@ -2,6 +2,37 @@ const tmdbQuery = document.querySelector("#tmdb-query"); const tmdbButton = document.querySelector("#tmdb-search"); const tmdbResults = document.querySelector("#tmdb-results"); +const syncStarControl = (control, stars) => { + control.dataset.currentStars = String(stars); + control.dataset.previewStars = ""; + control.querySelectorAll(".star-button").forEach((button) => { + const value = Number(button.dataset.stars || 0); + const active = stars >= value; + button.classList.toggle("is-active", active); + button.classList.remove("is-preview"); + button.setAttribute("aria-pressed", active ? "true" : "false"); + }); +}; + +const previewStarControl = (control, stars) => { + control.dataset.previewStars = String(stars); + control.querySelectorAll(".star-button").forEach((button) => { + const value = Number(button.dataset.stars || 0); + const previewed = stars >= value; + button.classList.toggle("is-preview", previewed); + }); +}; + +const clearStarPreview = (control) => { + control.dataset.previewStars = ""; + const stars = Number(control.dataset.currentStars || 0); + control.querySelectorAll(".star-button").forEach((button) => { + const value = Number(button.dataset.stars || 0); + button.classList.toggle("is-preview", false); + button.classList.toggle("is-active", stars >= value); + }); +}; + const setValue = (selector, value) => { const element = document.querySelector(selector); if (element && value !== null && value !== undefined) { @@ -129,3 +160,50 @@ document.querySelectorAll("form[data-confirm]").forEach((form) => { } }); }); + +document.addEventListener("click", async (event) => { + const button = event.target.closest(".star-button"); + if (!button) return; + + const control = button.closest(".star-control"); + if (!control || !control.dataset.filmId) return; + + const stars = Number(button.dataset.stars || 0); + const filmId = control.dataset.filmId; + + button.disabled = true; + try { + const response = await fetch(`/films/${filmId}/stars`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ stars }), + }); + + const data = await response.json(); + if (!response.ok) { + return; + } + + syncStarControl(control, Number(data.stars || 0)); + } catch (error) { + console.error("Failed to update stars", error); + } finally { + button.disabled = false; + } +}); + +document.querySelectorAll(".star-control").forEach((control) => { + syncStarControl(control, Number(control.dataset.currentStars || 0)); + control.addEventListener("pointerleave", () => clearStarPreview(control)); + control.addEventListener("focusout", (event) => { + if (!control.contains(event.relatedTarget)) { + clearStarPreview(control); + } + }); + control.querySelectorAll(".star-button").forEach((button) => { + button.addEventListener("pointerenter", () => previewStarControl(control, Number(button.dataset.stars || 0))); + button.addEventListener("focus", () => previewStarControl(control, Number(button.dataset.stars || 0))); + }); +}); -- cgit v1.3-2-g0d8e