1
Fork 0
star-rating/app.js
Leonardo Devai d2a275c5b6 Review and modernize all 42 projects to the updated standard
Pinned 2026 toolchains (Go 1.26, Rust 1.98/edition 2024, Python 3.14 + uv, Node 24,
Zig 0.16, NixOS 26.05), postgres 18 / mongo 8, lockfiles built from, non-root
runtimes, .dockerignore, per-project LICENSE, READMEs with the git.devai.io clone
line, checkout@v7 CI. Security fixes in the legacy Rust APIs (any-password login,
self-assigned admin, hard-coded JWT secret), JWT alg/exp/sub enforcement across the
blog series, safe markdown links in the frontends, and many smaller bugs — every
project was built, run and exercised end to end.

Adds scripts/publish.sh + a CI publish job that splits every folder into its own
repo at git.devai.io/templates/<folder>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01128fhuZbgivaSJvtMf4s1G
2026-09-27 21:10:38 +02:00

40 lines
1.5 KiB
JavaScript

const row = document.getElementById("stars");
const stars = [...row.querySelectorAll(".star")];
const output = document.getElementById("output");
// Two values, two jobs. `selected` is the COMMITTED rating: set by a click,
// saved in localStorage. Hovering only PREVIEWS: it repaints the stars but
// never touches `selected`, so leaving the row snaps back to the real rating.
let selected = Number(localStorage.getItem("rating")) || 0;
function paint(value) {
stars.forEach((star, index) => star.classList.toggle("on", index < value));
}
function commit(value) {
selected = value;
localStorage.setItem("rating", String(value));
output.textContent = value ? `You rated: ${value}/5` : "Click a star to rate.";
paint(value);
}
stars.forEach((star, index) => {
star.addEventListener("mouseenter", () => paint(index + 1)); // preview
star.addEventListener("click", () => commit(index + 1)); // commit
});
row.addEventListener("mouseleave", () => paint(selected));
// Each star is a real <button>, so Tab, Enter and Space already work. The arrow
// keys add a quicker way to move the rating up and down.
row.addEventListener("keydown", (event) => {
let next;
if (event.key === "ArrowRight" || event.key === "ArrowUp") next = Math.min(5, selected + 1);
else if (event.key === "ArrowLeft" || event.key === "ArrowDown") next = Math.max(1, selected - 1);
else return;
event.preventDefault(); // don't also scroll the page
commit(next);
stars[next - 1].focus();
});
commit(selected);