theseus/collision.html
Local Dev 75e468ae39 Theseus UX polish: BCDN/BCNR terminology + soft-mode prompt redesign
Terminology (user-facing labels now match the product/registry distinction):
- BCDN = Bitcoin Cash Domain Names (the product — what you view)
- BCNR = Bitcoin Cash Name Registry (the on-chain system that backs it)
Chrome badge, popover, Settings section and 'Open with…' prompt all show BCDN
for a resolved name. BCNR stays only where the registry itself is the subject.

'Open with…' prompt (collision.html):
- Larger window (640x520, was 480x340)
- Radio-select pattern with explicit Open / Cancel buttons (was auto-fire on click)
- Enter = Open, Esc = Cancel, keyboard-first
- Body copy per operator spec (no product-name-in-parens; blockchain-generic)
- Card titles kept short: 'BCNR / BCDN' + 'ICANN / IANA'

Address-bar chip:
- Says BCDN (not BCNR) for on-chain names; ICANN for web
- Dropped the '·.tld' suffix — TLD is already in the URL bar
- On collision candidates: shows BOTH chips (BCDN | ICANN) with active
  highlighted; clicking the inactive one flips the tab (via collision-switch)

Settings section renamed Naming → Registries. Copy rewritten in the same
BCDN/BCNR frame; policy labels are now 'BCDN first' / 'ICANN first' / 'Ask
each time'.

Passive 'also on BCNR' bar copy updated to BCDN.

Verified: all preload/settings/main/chrome JS + HTML parse; no secrets in
staging.
2026-08-02 13:02:47 +02:00

116 lines
6.7 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Open with…</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
:root {
color-scheme: dark light;
--bg:#0f1116; --fg:#e5e7eb; --muted:#9ca3af; --border:#2a2f3a;
--btn:#1f2430; --btn-hover:#2a3040; --accent:#f5c518; --icann:#4c9eff;
}
@media (prefers-color-scheme: light) {
:root { --bg:#f7f7f8; --fg:#111827; --muted:#6b7280; --border:#e5e7eb; --btn:#fff; --btn-hover:#f0f2f5; }
}
* { box-sizing: border-box; }
html, body { margin:0; height:100%; overflow:hidden; }
body { background:var(--bg); color:var(--fg); font:15px/1.45 system-ui,-apple-system,Segoe UI,Roboto,sans-serif; display:flex; flex-direction:column; padding:26px 34px; }
h1 { margin:0 0 6px; font-size:18px; font-weight:600; }
.sub { color:var(--muted); font-size:13.5px; margin-bottom:22px; }
.host { color:var(--fg); font-weight:600; }
.choices { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:22px; }
.choice { border:2px solid var(--border); border-radius:10px; padding:18px; background:var(--btn); text-align:left; color:var(--fg); cursor:pointer; transition: border-color .12s, background .12s; }
.choice:hover { background:var(--btn-hover); }
.choice.sel.bcdn { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--btn)); }
.choice.sel.icann { border-color: var(--icann); background: color-mix(in srgb, var(--icann) 12%, var(--btn)); }
.choice .head { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.choice .radio { flex:none; width:16px; height:16px; border-radius:50%; border:2px solid var(--border); position:relative; }
.choice.sel.bcdn .radio { border-color: var(--accent); background: radial-gradient(circle, var(--accent) 40%, transparent 42%); }
.choice.sel.icann .radio { border-color: var(--icann); background: radial-gradient(circle, var(--icann) 40%, transparent 42%); }
.choice .icon { font-size:20px; line-height:1; }
.choice .title { font-weight:600; font-size:15px; }
.choice.bcdn .title { color: var(--accent); }
.choice.icann .title { color: var(--icann); }
.choice .desc { font-size:13px; color:var(--muted); }
fieldset { border:0; padding:0; margin:0 0 22px; display:flex; flex-direction:column; gap:8px; }
fieldset legend { color:var(--muted); font-size:12.5px; padding:0; margin-bottom:6px; text-transform:uppercase; letter-spacing:.03em; }
fieldset .row { display:flex; align-items:center; gap:9px; font-size:13.5px; padding:2px 0; }
fieldset .row input { accent-color:var(--accent); width:15px; height:15px; }
fieldset .row label { color:var(--fg); cursor:pointer; }
.actions { display:flex; justify-content:flex-end; gap:10px; margin-top:auto; }
button.act { border:1px solid var(--border); background:var(--btn); color:var(--fg); padding:10px 20px; border-radius:8px; font-size:14px; cursor:pointer; }
button.act:hover { background: var(--btn-hover); }
button.act.primary { background:var(--accent); color:#111; border-color:var(--accent); font-weight:600; }
button.act.primary:hover { filter:brightness(1.05); }
kbd { border:1px solid var(--border); border-radius:3px; padding:0 5px; font:11px monospace; color:var(--muted); margin-left:6px; }
</style>
</head>
<body>
<h1><span class="host" id="host"></span> exists in two registries</h1>
<div class="sub">Choose which one to open. You can change this later in Settings.</div>
<div class="choices" id="choices">
<div class="choice bcdn sel" data-choice="bcdn" tabindex="0">
<div class="head">
<span class="radio"></span><span class="icon"></span>
<span class="title">BCNR / BCDN</span>
</div>
<div class="desc">On-chain registration. Owned by the holder of a digital name certificate. The registry served by the blockchain root.</div>
</div>
<div class="choice icann" data-choice="icann" tabindex="0">
<div class="head">
<span class="radio"></span><span class="icon">🌐</span>
<span class="title">ICANN / IANA</span>
</div>
<div class="desc">DNS service coordinated by the ICANN. The registry served by the incumbent root.</div>
</div>
</div>
<fieldset>
<legend>Remember this choice</legend>
<div class="row"><input type="radio" name="remember" id="rem-no" value="no" checked><label for="rem-no">Ask again next time</label></div>
<div class="row"><input type="radio" name="remember" id="rem-name" value="name"><label for="rem-name">Always use for <span class="host" id="host2"></span></label></div>
<div class="row"><input type="radio" name="remember" id="rem-tld" value="tld"><label for="rem-tld">Always use for all <span id="tld"></span> names</label></div>
</fieldset>
<div class="actions">
<button class="act" id="cancel">Cancel<kbd>Esc</kbd></button>
<button class="act primary" id="confirm">Open<kbd>Enter</kbd></button>
</div>
<script>
const qs = new URLSearchParams(location.search);
const host = qs.get("host") || ""; const tld = qs.get("tld") || "";
document.getElementById("host").textContent = host;
document.getElementById("host2").textContent = host;
document.getElementById("tld").textContent = "." + tld;
document.title = "Open " + host + " with…";
let choice = "bcdn"; // default preselected
const bcdnEl = document.querySelector('.choice[data-choice="bcdn"]');
const icannEl = document.querySelector('.choice[data-choice="icann"]');
function select(c) {
choice = c;
bcdnEl.classList.toggle("sel", c === "bcdn");
icannEl.classList.toggle("sel", c === "icann");
}
for (const el of [bcdnEl, icannEl]) {
el.addEventListener("click", () => select(el.dataset.choice));
el.addEventListener("keydown", (e) => { if (e.key === " " || e.key === "Enter") { e.preventDefault(); select(el.dataset.choice); } });
}
function remember() { return document.querySelector('input[name="remember"]:checked')?.value || "no"; }
function confirm() {
// Map "bcdn" (user-facing) -> "bcnr" (internal key used by main.js/collisions.json)
window.collisionApi.choose(host, { choice: choice === "bcdn" ? "bcnr" : "icann", remember: remember() });
}
function cancel() { window.collisionApi.choose(host, { choice: "cancel", remember: "no" }); }
document.getElementById("confirm").addEventListener("click", confirm);
document.getElementById("cancel").addEventListener("click", cancel);
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") cancel();
if (e.key === "Enter" && e.target.tagName !== "BUTTON") confirm();
});
</script>
</body>
</html>