2026-09-27 19:55:43 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< title > Cookie Pop-ups< / title >
< style >
:root { color-scheme: light dark;
--bg:#0e131c; --panel:#141a24; --panel2:#191f2b; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#0ac18e; --warn:#f5a524; --danger:#ff5b5b; }
@media (prefers-color-scheme: light) {
:root { --bg:#f8faff; --panel:#ffffff; --panel2:#eff3fb; --line:rgba(0,0,0,.10);
--ink:#1a1f2b; --mut:#5c6577; --dim:#8a93a5; --warn:#d97706; }
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body { background: var(--bg); color: var(--ink); font: 13px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif; display: flex; flex-direction: column; }
header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--line); background: var(--panel); }
header h1 { margin: 0; font-size: 14px; font-weight: 600; }
header .pill { margin-left: auto; }
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border-radius: 999px; font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; background: rgba(139,152,169,.14); color: var(--mut); }
.pill.on { color: #0b0e14; background: var(--acid); }
.pill.off { color: #fff; background: var(--danger); }
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.body { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.card { border: 1px solid var(--line); background: var(--panel); border-radius: 14px; padding: 16px; }
.site { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.site .host { font: 600 13px/1.3 ui-monospace, "Cascadia Code", Consolas, monospace; color: var(--mut); overflow-wrap: anywhere; }
.site .num { font-size: 40px; font-weight: 700; line-height: 1.1; color: var(--warn); font-variant-numeric: tabular-nums; }
.site .num.muted { color: var(--dim); }
.site .lbl { color: var(--mut); }
.site .sub { color: var(--dim); font-size: 11.5px; }
.btn { border: 1px solid var(--line); background: var(--panel2); color: var(--ink); padding: 9px 16px; border-radius: 10px; font: inherit; font-weight: 600; cursor: pointer; }
.btn:hover { border-color: rgb(from var(--warn) r g b / .5); }
.btn.primary { background: var(--warn); color: #0b0e14; border-color: transparent; }
.btn.wide { margin-top: 10px; min-width: 200px; }
.row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.row + .row { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.row .k { font-weight: 600; }
.row .d { color: var(--dim); font-size: 11.5px; }
.row .v { color: var(--mut); font-variant-numeric: tabular-nums; }
.switch { position: relative; width: 40px; height: 22px; border-radius: 11px; background: var(--dim); border: none; cursor: pointer; flex: none; transition: background .15s; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; transition: left .15s; }
.switch.on { background: var(--acid); } .switch.on::after { left: 20px; }
.modes { display: grid; gap: 8px; margin-top: 10px; }
.mode { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel2); cursor: pointer; }
.mode.sel { border-color: rgb(from var(--warn) r g b / .6); }
.mode input { margin-top: 3px; accent-color: var(--warn); }
.mode .t { font-weight: 600; } .mode .d { color: var(--dim); font-size: 11.5px; }
.note { color: var(--dim); font-size: 11.5px; line-height: 1.45; }
h2 { margin: 0 0 8px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--dim); }
< / style >
< / head >
< body >
< header > < span > 🍪< / span > < h1 > Cookie Pop-ups< / h1 > < span class = "pill" id = "pill" > < span class = "dot" > < / span > < span id = "pillText" > …< / span > < / span > < / header >
< div class = "body" >
< div class = "card site" id = "siteCard" > < div class = "lbl" > Open a site to see what was handled there.< / div > < / div >
< div class = "card" >
< div class = "row" >
< div > < div class = "k" > Answer cookie pop-ups for me< / div > < div class = "d" > On every site, before the banner gets in the way.< / div > < / div >
< button class = "switch" id = "enabled" role = "switch" aria-checked = "true" title = "Turn on or off" > < / button >
< / div >
< div class = "modes" id = "modes" >
< label class = "mode" > < input type = "radio" name = "mode" value = "optOut" > < span > < div class = "t" > Reject all but essentials< / div > < div class = "d" > Declines tracking and marketing cookies wherever the pop-up allows it. Recommended.< / div > < / span > < / label >
< label class = "mode" > < input type = "radio" name = "mode" value = "optIn" > < span > < div class = "t" > Just make it go away< / div > < div class = "d" > Accepts the defaults. Fastest, but you keep whatever the site wants to set.< / div > < / span > < / label >
< / div >
< div class = "row" style = "margin-top:12px; padding-top:12px; border-top:1px solid var(--line)" >
< div > < div class = "k" > Pop-ups handled< / div > < div class = "d" > Since the add-on was installed.< / div > < / div >
< div class = "v" id = "total" > 0< / div >
< / div >
< / div >
< div class = "note" id = "rules" > < / div >
2026-09-27 20:37:30 +02:00
< div class = "note" > < a href = "#" id = "toSettings" style = "color:var(--warn)" > Manage in Settings< / a > · Built on DuckDuckGo's autoconsent rules for hundreds of consent dialogs, with a fallback that looks for reject buttons on unknown ones. Some banners still need a click; if one keeps reappearing, exclude the site here.< / div >
2026-09-27 19:55:43 +02:00
< / div >
< script >
const $ = (id) => document.getElementById(id);
const esc = (s) => String(s ?? "").replace(/[& < >"']/g, (c) => ({ "&":"& ","< ":"< ",">":"> ",'"':"" ","'":"' " })[c]);
let state = null;
function render(s) {
state = s;
$("pill").className = "pill " + (s.enabled ? "on" : "off");
$("pillText").textContent = s.enabled ? "On" : "Off";
$("enabled").classList.toggle("on", s.enabled); $("enabled").setAttribute("aria-checked", String(s.enabled));
for (const l of document.querySelectorAll(".mode")) { const on = l.querySelector("input").value === s.mode; l.classList.toggle("sel", on); l.querySelector("input").checked = on; }
$("total").textContent = Number(s.handledTotal || 0).toLocaleString();
$("rules").textContent = s.rulesVersion ? `Rules: autoconsent ${s.rulesVersion}.` : "";
const card = $("siteCard");
if (!s.site) card.innerHTML = `< div class = "lbl" > Open a site to see what was handled there.< / div > `;
else if (s.site.skipped) card.innerHTML = `< div class = "host" > ${esc(s.site.host)}< / div > < div class = "num muted" > —< / div > < div class = "lbl" > Excluded: pop-ups are left alone on this site.< / div > < button class = "btn primary wide" id = "siteBtn" > Handle pop-ups here again< / button > `;
else {
const n = s.site.handled;
card.innerHTML = `< div class = "host" > ${esc(s.site.host)}< / div > < div class = "num${n ? " " : " muted " } " > ${n}< / div >
< div class = "lbl" > ${n === 1 ? "pop-up answered on this site" : "pop-ups answered on this site"}${s.site.cmp ? ` · ${esc(s.site.cmp)}` : ""}< / div >
${s.site.failed ? `< div class = "sub" > ${s.site.failed} attempt(s) did not complete — the banner may need a click.< / div > ` : ""}
< button class = "btn wide" id = "siteBtn" > Exclude this site< / button > `;
}
const b = $("siteBtn"); if (b) b.onclick = () => window.silentmode.invoke("skip-site", { host: s.site.host, skipped: !s.site.skipped }).then(render);
}
2026-09-27 20:37:30 +02:00
$("toSettings").onclick = (e) => { e.preventDefault(); window.silentmode.invoke("open-settings"); };
2026-09-27 19:55:43 +02:00
$("enabled").onclick = () => window.silentmode.invoke("set-enabled", { enabled: !(state & & state.enabled) }).then(render);
$("modes").addEventListener("change", (e) => { if (e.target.name === "mode") window.silentmode.invoke("set-mode", { mode: e.target.value }).then(render); });
window.silentmode.on("state", render);
window.silentmode.invoke("state").then(render);
window.silentmode.onVisibility((v) => { if (v) window.silentmode.invoke("state").then(render); });
< / script >
< / body >
< / html >