summaryrefslogtreecommitdiff
path: root/static/app.js
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-06 14:34:01 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-06 14:34:01 -0700
commita3df69ff5218cee132a6def9d860cd0276cc0cd4 (patch)
tree2d8bf71b98a606b2f1194ce608c23a8e17d8cb6c /static/app.js
parente708bec6cd76c2686de4158dde4d04f72a3c300d (diff)
Add year review and inline diary ratings
Diffstat (limited to 'static/app.js')
-rw-r--r--static/app.js78
1 files changed, 78 insertions, 0 deletions
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)));
+ });
+});