/* Utility condivise tra le pagine (galassia e classifiche) */
"use strict";
/* ---------------- utility base ---------------- */
function esc(s) {
return String(s ?? "").replace(/[&<>"']/g, (c) =>
({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
}
function num(v) { return (v === null || v === undefined) ? "—" : Number(v).toLocaleString("it"); }
function hashStr(s) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return Math.abs(h); }
async function api(path, opts) {
const r = await fetch(path, opts);
let data = null;
try { data = await r.json(); } catch (_) { /* noop */ }
if (!r.ok) throw new Error((data && data.error) || ("Errore HTTP " + r.status));
return data;
}
/* ---------------- icone SVG (window.ICONS da icons.js) ---------------- */
function icon(name, size = 16) {
const it = (window.ICONS || {})[name];
if (!it) return "";
return ``;
}
/* ---------------- avatar pianeti/lune (SVG) ---------------- */
let _svgSeq = 0;
const PLANET_PAL = [
["#ffd9a0", "#e0762c"], ["#f2b3a0", "#b3422f"], ["#ffb1c0", "#a0275a"],
["#9fd8ff", "#2a6fc4"], ["#8fe8c0", "#1e7a5f"], ["#d3b8ff", "#6d3fc4"],
["#f5e3a0", "#c2a22e"], ["#c3d0e2", "#5c6f8c"],
];
const LUNA_PAL = [["#e6e6e6", "#9a9a9a"]];
function artSVG(seedKey, size, moon = false) {
const seed = hashStr(seedKey) || 1;
const r = 15; // viewBox 32
const pal = (moon ? LUNA_PAL : PLANET_PAL)[seed % (moon ? 1 : PLANET_PAL.length)];
const id = "g" + (++_svgSeq);
let extras = "";
if (moon) {
for (let i = 0; i < 4; i++) {
const cx = 7 + ((seed >> (i * 3)) % 18);
const cy = 7 + ((seed >> (i * 5 + 2)) % 18);
const cr = 2 + ((seed >> (i * 2 + 1)) % 3);
extras += `` +
``;
}
} else {
for (let i = 0; i < 3; i++) {
const cx = 8 + ((seed >> (i * 4)) % 14);
const cy = 6 + ((seed >> (i * 3 + 1)) % 14);
extras += ``;
}
}
return ``;
}
/* ---------------- sfondo stellare ---------------- */
function initStars() {
const cv = document.getElementById("space");
if (!cv) return;
let ctx = null;
try { ctx = cv.getContext("2d"); } catch (_) { /* noop */ }
if (!ctx) return; // mai bloccare il resto dell'app
let stars = [], tw = [];
function resize() {
cv.width = innerWidth; cv.height = innerHeight;
stars = []; tw = [];
const n = Math.floor((cv.width * cv.height) / 6500);
for (let i = 0; i < n; i++) {
stars.push({ x: Math.random() * cv.width, y: Math.random() * cv.height,
r: Math.random() * 1.1 + .25, a: Math.random() * .5 + .2 });
}
for (let i = 0; i < 26; i++) {
tw.push({ x: Math.random() * cv.width, y: Math.random() * cv.height,
r: Math.random() * 1.2 + .4, p: Math.random() * Math.PI * 2, s: .8 + Math.random() });
}
}
resize();
addEventListener("resize", resize);
(function draw(t) {
ctx.clearRect(0, 0, cv.width, cv.height);
for (const s of stars) {
ctx.globalAlpha = s.a; ctx.fillStyle = "#cfe0ff";
ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, 7); ctx.fill();
}
const k = t / 1000;
for (const s of tw) {
ctx.globalAlpha = .25 + .6 * Math.abs(Math.sin(k * s.s + s.p));
ctx.fillStyle = "#fff";
ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, 7); ctx.fill();
}
ctx.globalAlpha = 1;
requestAnimationFrame(draw);
})(performance.now());
}