theseus/bundled-addons/consent/panel.html

106 lines
7.8 KiB
HTML
Raw Normal View History

<!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>
<div class="note">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>
</div>
<script>
const $ = (id) => document.getElementById(id);
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;" })[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);
}
$("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>