2026-08-26 12:57:23 +02:00
|
|
|
// furtka.org logo poll — no cookies, no storage. The server tells us
|
|
|
|
|
// what this device already chose (salted hash of IP + user agent).
|
|
|
|
|
(function () {
|
|
|
|
|
var root = document.querySelector('.poll');
|
|
|
|
|
if (!root || !window.fetch) return;
|
|
|
|
|
var api = root.dataset.api;
|
|
|
|
|
var status = root.querySelector('.poll-status');
|
|
|
|
|
var t = status.dataset;
|
|
|
|
|
var buttons = root.querySelectorAll('[data-vote]');
|
|
|
|
|
var busy = false;
|
|
|
|
|
|
|
|
|
|
function pct(n, total) { return total ? Math.round((n / total) * 100) : 0; }
|
feat(website): logo showcase on /logo/, poll link + current feature list on the homepage
Both marks now appear everywhere they would have to work: five sizes
down to the real 16 px tab icon, horizontal and stacked lockups, browser
tab + site header, phone tiles, console banner + boot splash, social
card, and four colour grounds — generated from one geometry source by
website/tools/logo-assets.py (outputs committed under data/logo and
static/img/logo). The homepage links to the vote and its 'what works
today' list catches up with 26.8–26.17: password login, online app
catalog, app dependencies, opt-in HTTPS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MScAinbyMdeNc7H2BZdnnG
2026-08-26 13:30:10 +02:00
|
|
|
function each(sel, fn) { Array.prototype.forEach.call(root.querySelectorAll(sel), fn); }
|
2026-08-26 12:57:23 +02:00
|
|
|
|
|
|
|
|
function render(d) {
|
|
|
|
|
var total = d.total || 0;
|
|
|
|
|
root.classList.toggle('poll--voted', !!d.yours);
|
|
|
|
|
Object.keys(d.counts).forEach(function (k) {
|
feat(website): logo showcase on /logo/, poll link + current feature list on the homepage
Both marks now appear everywhere they would have to work: five sizes
down to the real 16 px tab icon, horizontal and stacked lockups, browser
tab + site header, phone tiles, console banner + boot splash, social
card, and four colour grounds — generated from one geometry source by
website/tools/logo-assets.py (outputs committed under data/logo and
static/img/logo). The homepage links to the vote and its 'what works
today' list catches up with 26.8–26.17: password login, online app
catalog, app dependencies, opt-in HTTPS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MScAinbyMdeNc7H2BZdnnG
2026-08-26 13:30:10 +02:00
|
|
|
var n = d.counts[k], p = pct(n, total), mine = d.yours === k;
|
|
|
|
|
each('[data-choice="' + k + '"]', function (card) {
|
|
|
|
|
card.classList.toggle('is-yours', mine);
|
|
|
|
|
var bar = card.querySelector('.poll-bar i'); if (bar) bar.style.width = p + '%';
|
|
|
|
|
var c = card.querySelector('[data-count]'); if (c) c.textContent = d.yours ? p + ' % · ' + n : '';
|
|
|
|
|
});
|
|
|
|
|
each('[data-vote="' + k + '"]', function (b) {
|
|
|
|
|
b.disabled = mine;
|
|
|
|
|
b.textContent = mine ? t.tVoted : (d.yours ? t.tChange : b.dataset.label);
|
|
|
|
|
});
|
2026-08-26 12:57:23 +02:00
|
|
|
});
|
|
|
|
|
status.textContent = d.yours ? t.tTotal.replace('{n}', total) : '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function load() {
|
|
|
|
|
fetch(api, { headers: { Accept: 'application/json' } })
|
|
|
|
|
.then(function (r) { if (!r.ok) throw r; return r.json(); })
|
|
|
|
|
.then(render)
|
|
|
|
|
.catch(function () { status.textContent = t.tError; });
|
|
|
|
|
}
|
|
|
|
|
|
feat(website): logo showcase on /logo/, poll link + current feature list on the homepage
Both marks now appear everywhere they would have to work: five sizes
down to the real 16 px tab icon, horizontal and stacked lockups, browser
tab + site header, phone tiles, console banner + boot splash, social
card, and four colour grounds — generated from one geometry source by
website/tools/logo-assets.py (outputs committed under data/logo and
static/img/logo). The homepage links to the vote and its 'what works
today' list catches up with 26.8–26.17: password login, online app
catalog, app dependencies, opt-in HTTPS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MScAinbyMdeNc7H2BZdnnG
2026-08-26 13:30:10 +02:00
|
|
|
Array.prototype.forEach.call(buttons, function (b) {
|
2026-08-26 12:57:23 +02:00
|
|
|
b.dataset.label = b.textContent;
|
|
|
|
|
b.addEventListener('click', function () {
|
|
|
|
|
if (busy) return;
|
|
|
|
|
busy = true; b.disabled = true;
|
|
|
|
|
fetch(api, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
|
|
|
body: JSON.stringify({ choice: b.dataset.vote })
|
|
|
|
|
})
|
|
|
|
|
.then(function (r) { if (!r.ok) throw r; return r.json(); })
|
feat(website): logo showcase on /logo/, poll link + current feature list on the homepage
Both marks now appear everywhere they would have to work: five sizes
down to the real 16 px tab icon, horizontal and stacked lockups, browser
tab + site header, phone tiles, console banner + boot splash, social
card, and four colour grounds — generated from one geometry source by
website/tools/logo-assets.py (outputs committed under data/logo and
static/img/logo). The homepage links to the vote and its 'what works
today' list catches up with 26.8–26.17: password login, online app
catalog, app dependencies, opt-in HTTPS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MScAinbyMdeNc7H2BZdnnG
2026-08-26 13:30:10 +02:00
|
|
|
.then(function (d) { render(d); status.scrollIntoView({ block: 'nearest' }); })
|
2026-08-26 12:57:23 +02:00
|
|
|
.catch(function () { status.textContent = t.tError; b.disabled = false; })
|
|
|
|
|
.then(function () { busy = false; });
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
status.textContent = '';
|
|
|
|
|
load();
|
|
|
|
|
})();
|