sirius/tld.html

574 lines
26 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Register a TLD — Sirius.X</title>
<meta name="description" content="Mint a top-level domain on Bitcoin Cash. Any wallet can register a TLD; second-level names can then be sold under it.">
<link rel="icon" href="./assets/favicon.svg" type="image/svg+xml">
<link rel="mask-icon" href="./assets/favicon.svg" color="#d6ff3d">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Sirius.X">
<meta property="og:title" content="Register a TLD on Bitcoin Cash">
<meta property="og:description" content="Mint a TLD certificate. One BCH transaction, no renewal, no registrar.">
<meta property="og:url" content="https://silentmode.st/sirius-x/tld.html">
<meta property="og:image" content="https://silentmode.st/sirius-x/brand/banner.svg">
<style>
:root{
--bg:#0b0e14; --panel:#141a24; --panel2:#18202c; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d;
--ok:#4fd1a5; --taken:#f6768a; --warn:#ffc75f;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:radial-gradient(1100px 560px at 50% -12%,#16202e,var(--bg));
color:var(--ink);font:16px/1.65 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;min-height:100vh}
a{color:var(--acid)}
.wrap{max-width:820px;margin:0 auto;padding:0 1.2rem}
.topnav{position:sticky;top:0;z-index:20;display:flex;gap:2px;align-items:center;flex-wrap:wrap;
padding:10px 1.2rem;background:rgba(11,14,20,.82);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.topnav .brand{font-weight:600;color:var(--ink);text-decoration:none;margin-right:14px;font-size:15px;letter-spacing:.2px}
.topnav .brand .g{color:var(--acid)}
.topnav a{color:var(--mut);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:14px}
.topnav a:hover{color:var(--ink);background:var(--panel)}
.topnav a.here{color:var(--acid);background:rgba(214,255,61,.08)}
.topnav a.portal{margin-left:auto;background:rgba(214,255,61,.10);color:var(--acid);font-weight:500}
.topnav a.portal:hover{background:rgba(214,255,61,.18)}
header.hero{text-align:center;padding:3.4rem 1.2rem 1rem}
.mark{font-size:44px;line-height:1}
h1{font-size:clamp(1.7rem,4.5vw,2.3rem);margin:.3rem 0 .3rem}
h1 .g{color:var(--acid)}
.tag{color:var(--mut);font-size:1rem;max-width:600px;margin:0 auto}
h2{font-size:1.25rem;margin:0 0 .4rem}
h3{font-size:1rem;margin:0 0 .35rem}
section{padding:2rem 0;border-top:1px solid var(--line);margin-top:2rem}
section:first-of-type{border-top:none;margin-top:1rem}
.card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:20px 22px;margin-top:1rem}
label{display:block;font-size:13px;color:var(--mut);margin:14px 0 5px}
.field-hint{color:var(--dim);font-size:11.5px;margin-left:8px}
textarea,input[type=text],input[type=password]{
width:100%;padding:11px 13px;border-radius:10px;border:1px solid #ffffff22;background:#0e131b;
color:var(--ink);font-size:14px;font-family:inherit;outline:none
}
textarea{min-height:74px;resize:vertical;font-family:ui-monospace,monospace;font-size:13px}
textarea:focus,input:focus{border-color:#4b7bec}
.btn{display:inline-block;text-decoration:none;padding:10px 18px;border-radius:10px;background:#4b7bec;color:#fff;font-size:14px;border:none;cursor:pointer;font-family:inherit}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--ink)}
.btn.acid{background:var(--acid);color:#0b0e14;font-weight:600}
.btn.small{padding:6px 12px;font-size:12.5px}
.btn:hover{filter:brightness(1.12)}
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
.row{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px;align-items:center}
.muted{color:var(--mut);font-size:13px}
.dim{color:var(--dim);font-size:12.5px}
code,.mono{background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:13px;word-break:break-all}
.badge{display:inline-block;font-size:11px;padding:2px 10px;border-radius:999px;font-weight:600}
.b-ok{background:rgba(79,209,165,.15);color:var(--ok)}
.b-taken{background:rgba(246,118,138,.15);color:var(--taken)}
.b-check{background:rgba(139,152,169,.14);color:var(--mut)}
.status{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:10px 14px;font-size:13px;color:var(--mut);margin-top:12px}
.status.ok{border-left:3px solid var(--ok)}
.status.err{border-left:3px solid var(--taken);color:var(--taken)}
.status.warn{border-left:3px solid var(--warn);color:var(--warn)}
.hidden{display:none}
.err{color:var(--taken);font-size:13.5px;margin-top:10px}
.authbox{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}
.authbox .card{margin:0}
.authbox h3{margin:0 0 .3rem;font-size:1rem}
.authbox p{margin:0;color:var(--mut);font-size:13px}
/* TLD search cell */
.search{max-width:600px;margin:1.5rem auto 0}
.searchrow{display:flex;gap:8px}
.searchrow input{flex:1;padding:14px 18px;font-size:17px;border-radius:12px;border:1px solid #ffffff22;background:#141a24;color:var(--ink)}
.searchrow input:focus{border-color:#4b7bec;outline:none}
.searchhint{font-size:12.5px;color:var(--mut);margin-top:8px;text-align:center}
.result-card{display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;
background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 18px;margin-top:12px}
.result-card .lbl{font-family:ui-monospace,monospace;font-size:18px;color:var(--ink)}
.result-card .lbl .dot{color:var(--acid)}
/* TLD registry table */
table.tlds{width:100%;border-collapse:collapse;margin-top:1rem;font-size:13px}
table.tlds th,table.tlds td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
table.tlds th{color:var(--mut);font-weight:500;font-size:11.5px;text-transform:uppercase;letter-spacing:.4px}
table.tlds .tld{font-family:ui-monospace,monospace;color:var(--acid);font-size:13.5px;font-weight:600}
table.tlds .cat{font-family:ui-monospace,monospace;color:var(--mut);font-size:11.5px;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Registration progress */
.steps-log{margin-top:12px;font-family:ui-monospace,monospace;font-size:12px;color:var(--mut);
background:#0e131b;border:1px solid var(--line);border-radius:8px;padding:10px 12px;max-height:140px;overflow-y:auto;display:none}
.steps-log.on{display:block}
.steps-log div::before{content:" ";color:var(--acid)}
.msg{font-size:13px;margin-top:12px}
.msg.ok{color:var(--ok)} .msg.err{color:var(--taken)}
footer{border-top:1px solid var(--line);padding:2rem 0 3rem;color:var(--dim);font-size:13px;text-align:center;margin-top:2.5rem}
</style>
</head>
<body>
<nav class="topnav">
<a class="brand" href="./"><span class="g">Sirius.X</span></a>
<a href="./#try">Try it</a>
feat(sirius-x): merge register.html into landing via shared mint flow Register.html and the landing were running duplicate name-search UIs. The register one was reported broken; the landing one already works inline. Merged both into the landing: - New js/register-flow.js — the full mint modal + wallet setup (Create / Import / Unlock / WizardConnect / Fund / Confirm / Register / Point it somewhere) extracted from register.html's <script type='module'> and turned into a shared module. Injects its own scoped modal HTML + CSS into the host page on load and exposes window.siriusRegisterName(fullName) as its public entry point. - Landing search results now have Register buttons that call the shared flow directly. The whole 'search -> pick name -> mint' journey stays on one page, no redirects, no duplicate search UI to maintain. - register.html reduced to a redirect stub: preserves ?q= if present, refreshes/JS-forwards to './' (landing), and shows a one-line 'Name search moved to the home page' fallback for JS-off users. Old links keep working; no /register.html deep links are broken. - All nav 'Register' entries now point at './#search-input' (or '../#search-input' on subpages), scrolling straight to the landing search box. Footer injector and every internal href updated the same way. Zero live href='.../register.html' left in the tree. Verified: register.html?q=hello redirects to /?q=hello; landing search 'fresh42abc' -> Register button -> modal opens with 'Register fresh42abc.bch' at the wallet-choice step.
2026-09-07 22:36:02 +02:00
<a href="./#search-input">🪪 Register</a>
<a href="./tld.html" class="here">🌐 TLD</a>
<a href="./theseus/"><svg width="14" height="14" viewBox="0 0 64 64" style="vertical-align:-2px;margin-right:4px" aria-hidden="true"><rect width="64" height="64" rx="12" fill="#0b0e14"/><path d="M32 6 L38 32 L26 32 Z" fill="#e04e4e"/><path d="M38 32 L32 58 L26 32 Z" fill="#d6ff3d"/><circle cx="32" cy="32" r="3" fill="#0b0e14"/></svg>Theseus</a>
<a href="./portal.html" class="portal">🔑 Sign in</a>
</nav>
<header class="hero">
<div class="mark">🌐</div>
<h1>Register a <span class="g">TLD</span></h1>
<p class="tag">A TLD is a certificate on the Bitcoin Cash chain. You mint it, you own it — any
second-level name registered under it lives in your TLD's registry. One BCH transaction,
no renewal, no ICANN.</p>
</header>
<div class="wrap">
<section id="search-section">
<h2>Search a TLD</h2>
<p class="muted">Type a label (az, 09, hyphen; up to 16 chars). We check the on-chain TLD
registry live and, if the label is free, show a register button.</p>
<div class="search">
<div class="searchrow">
<input id="q" placeholder="your-tld" spellcheck="false" autocomplete="off" autofocus maxlength="16">
</div>
<div class="searchhint">Available TLDs appear with a register button. Taken labels show which category holds them.</div>
</div>
<div id="result"></div>
</section>
<section id="signin-section" class="hidden">
<h2>Sign in to mint</h2>
<p class="muted">The TLD certificate lands in the token address of the wallet that signs the mint —
that wallet becomes the registry operator.</p>
<div class="authbox" style="margin-top:14px">
<div class="card" id="card-new">
<h3>🆕 New wallet</h3>
<p>Generate a fresh 12-word phrase in this tab. Nothing is saved — write it down before continuing.</p>
<div class="row">
<button class="btn acid" id="new-btn">Generate a phrase</button>
</div>
<div id="new-phrase" class="hidden" style="margin-top:14px">
<label>Your new recovery phrase</label>
<textarea id="new-seed" readonly></textarea>
<label style="margin-top:10px;display:flex;gap:9px;align-items:flex-start;font-size:13.5px">
<input type="checkbox" id="new-ack" style="margin-top:3px">
<span>I have written this phrase down. There is no reset if I lose it.</span>
</label>
<div class="row">
<button class="btn acid" id="new-signin-btn" disabled>Continue →</button>
<button class="btn ghost" id="new-copy-btn">Copy phrase</button>
</div>
</div>
<div id="new-err" class="err hidden"></div>
</div>
<div class="card" id="card-import">
<h3>📥 Import a seed phrase</h3>
<p>Paste your 12- or 24-word phrase. It stays in memory only.</p>
<label for="seed">Recovery phrase</label>
<textarea id="seed" placeholder="word1 word2 … word12" spellcheck="false" autocomplete="off"></textarea>
<div class="row">
<button class="btn acid" id="signin-btn">Continue →</button>
</div>
<div id="signin-err" class="err hidden"></div>
</div>
<div class="card" id="card-wc">
<h3>🔗 WizardConnect</h3>
<p>Cashonize 0.9+ or Paytaca. The wallet signs the mint on your device.</p>
<div class="row">
<button class="btn acid" id="wc-btn">Connect wallet</button>
</div>
<div id="wc-uri-box" class="hidden" style="margin-top:14px">
<label>Paste this into your WC-capable wallet:</label>
<div style="display:flex;gap:8px;align-items:center;margin-top:6px">
<code id="wc-uri" style="flex:1;font-size:12px"></code>
<button class="btn ghost small" id="wc-copy" type="button">Copy</button>
</div>
<p class="dim" style="margin-top:8px">Waiting for your wallet…</p>
<div class="row"><button class="btn ghost small" id="wc-cancel" type="button">Cancel</button></div>
</div>
<div id="wc-err" class="err hidden"></div>
</div>
</div>
</section>
<section id="mint-section" class="hidden">
<h2>Mint <span id="mint-label" class="mono" style="color:var(--acid)"></span></h2>
<div class="card">
<div class="status" id="mint-wallet">Signed in as <code id="mint-addr"></code></div>
<label>Service fee (USD) <span class="field-hint">chipnet placeholder rate; mainnet will use an oracle</span></label>
<input type="text" id="mint-usd" value="5" style="max-width:200px">
<div class="status" id="mint-price">= <b>0</b> sats · rate <b>0</b> sats/USD</div>
<div class="row">
<button class="btn acid" id="mint-submit" disabled>Register</button>
<button class="btn ghost small" id="mint-back">← Back to search</button>
<button class="btn ghost small" id="mint-signout">Sign out</button>
</div>
<div class="steps-log" id="mint-log"></div>
<div id="mint-msg" class="msg"></div>
</div>
</section>
<section id="listing">
<h2>Registered TLDs</h2>
<p class="muted">Fetched from the on-chain TLD registry via the public gateway. Refresh the page for the latest.</p>
<div id="tlds-status" class="status">Loading…</div>
<table class="tlds" id="tlds-table" style="display:none">
<thead><tr><th>TLD</th><th>Category</th></tr></thead>
<tbody></tbody>
</table>
</section>
</div>
feat(sirius-x): footer everywhere, redesigned wallet button, dropdown auto-acts Three UX fixes: 1. Beautiful footer on every page. Extracted the 4-column landing footer into js/site-footer.js — reads the nav brand link to derive per-page base ('./' at root, '../' in subdirs) so links resolve from any depth without duplicating the HTML across 8 pages. Every page now ships an empty <footer id="site-footer"></footer> and includes the injector; inline footer + its CSS block removed from landing too so the source stays in one place. 2. Wallet button redesign. Pill now shows a state dot (dim when not signed in, green with subtle glow when signed in), a monospace short address label when signed in ('qra6rs…7yl2') OR 'Wallet' when not, a WC/seed badge on signed-in state, and a subtle caret. Full border and hover states, proper aria-expanded/aria-label wiring. Dropdown menu itself upgraded: grid layout per item (icon column + title + hint), heavier backdrop blur, larger min-width, clearer typography. 3. Dropdown options actually do something. Removed the redundant 'Open sign-in page →' item — the other three all land on portal too, so listing 'open the page' as a fourth option was noise. On portal arrival, the ?mode= handler now AUTO-TRIGGERS the primary action for each mode: new -> click Generate a phrase (12 words appear immediately) import -> focus the seed textarea (cursor ready to paste) wc -> click Connect wallet (WC session starts, URI shown) No extra clicks between dropdown choice and the flow it names. Cache-buster on the profile-menu.js include bumped to ?v=20260907wallet so cached copies pick up the new design; footer injector at ?v=20260907rel.
2026-09-07 22:00:21 +02:00
<footer id="site-footer"></footer>
<script type="importmap">
{ "imports": { "@bitauth/libauth": "https://silentmode.st/js/libauth.js" } }
</script>
<script type="module">
import * as BNS from "https://silentmode.st/js/bns-register.js?v=20260907tldext";
const $ = (id) => document.getElementById(id);
const esc = (s) => String(s).replace(/[&<>"']/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
// ---------- oracle stub ----------
// Same chipnet-only static rate as the portal. Mainnet swaps this for a real
// price feed; the sats output is what actually gets locked into the mint tx.
const CHIPNET_SATS_PER_USD = 250_000; // ~$400/BCH test rate
const usdToSats = (u) => {
const n = Number(String(u).replace(/[^\d.]/g, "")) || 0;
return Math.max(0, Math.round(n * CHIPNET_SATS_PER_USD));
};
// ---------- state ----------
let wallet = null; // built-in wallet or WC wrapper
let candidateLabel = null; // TLD label the user chose to register
// ---------- TLD list (live) ----------
async function loadTldList() {
const status = $("tlds-status"), tbody = $("tlds-table").querySelector("tbody");
try {
const r = await fetch("https://navigate.st/api/tlds");
if (!r.ok) throw new Error("api " + r.status);
const j = await r.json();
const tlds = (j.tlds || []).map((t) => (typeof t === "string" ? { tld: t } : t));
tlds.sort((a, b) => a.tld.localeCompare(b.tld));
tbody.innerHTML = tlds.map((t) =>
`<tr><td class="tld">.${esc(t.tld)}</td><td class="cat">${esc(t.certificate || t.category || "")}</td></tr>`
).join("");
$("tlds-table").style.display = "";
status.className = "status ok";
status.textContent = `${tlds.length} TLDs registered on chipnet.`;
return tlds.map((t) => t.tld);
} catch (e) {
status.className = "status err";
status.textContent = "Could not load TLD list: " + (e.message || e);
return null;
}
}
let registeredTlds = null;
loadTldList().then((list) => { registeredTlds = list; refreshSearch(); });
// ---------- search + result ----------
function validLabel(s) { return /^[a-z0-9-]{1,16}$/.test(s); }
function normLabel(s) { return String(s).toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 16); }
function renderResult(label, state) {
const res = $("result");
if (!label) { res.innerHTML = ""; return; }
if (state === "checking") {
res.innerHTML = `<div class="result-card">
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
<span class="badge b-check">checking…</span>
<span></span>
</div>`;
return;
}
if (state === "taken") {
res.innerHTML = `<div class="result-card">
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
<span class="badge b-taken">taken</span>
<span></span>
</div>
<p class="dim" style="margin-top:8px">Someone already minted <code>.${esc(label)}</code>. Try a different label — TLDs are first-come, first-served.</p>`;
return;
}
// available
res.innerHTML = `<div class="result-card">
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
<span class="badge b-ok">available</span>
<button class="btn acid" id="go-register">Register .${esc(label)} →</button>
</div>`;
$("go-register").onclick = () => beginRegister(label);
}
let currentLabel = "";
function refreshSearch() {
const raw = normLabel($("q").value);
currentLabel = raw;
if (!raw) { renderResult("", null); return; }
if (!validLabel(raw)) { renderResult(raw, "invalid"); return; }
// If we already have the registry snapshot, decide locally — no API round-trip.
if (registeredTlds !== null) {
renderResult(raw, registeredTlds.includes(raw) ? "taken" : "ok");
return;
}
renderResult(raw, "checking");
}
$("q").addEventListener("input", () => {
$("q").value = normLabel($("q").value);
refreshSearch();
});
$("q").addEventListener("keydown", (e) => {
if (e.key === "Enter" && currentLabel && registeredTlds && !registeredTlds.includes(currentLabel)) {
beginRegister(currentLabel);
}
});
// ---------- flow: search → wallet → mint ----------
function beginRegister(label) {
candidateLabel = label;
$("mint-label").textContent = "." + label;
// Show the sign-in section if not signed in; otherwise straight to mint.
if (!wallet) {
$("signin-section").classList.remove("hidden");
$("signin-section").scrollIntoView({ behavior: "smooth", block: "start" });
} else {
showMintSection();
}
}
function showMintSection() {
$("signin-section").classList.add("hidden");
$("mint-section").classList.remove("hidden");
$("mint-addr").textContent = wallet.address;
updateMintPrice();
updateMintButton();
$("mint-section").scrollIntoView({ behavior: "smooth", block: "start" });
}
function backToSearch() {
$("mint-section").classList.add("hidden");
$("search-section").scrollIntoView({ behavior: "smooth", block: "start" });
}
$("mint-back").addEventListener("click", backToSearch);
// ---------- wallet: import ----------
$("signin-btn").addEventListener("click", async () => {
const raw = $("seed").value.trim();
const errBox = $("signin-err");
errBox.classList.add("hidden");
if (!raw) { errBox.textContent = "Paste your seed phrase to continue."; errBox.classList.remove("hidden"); return; }
const btn = $("signin-btn");
btn.disabled = true; btn.textContent = "Unlocking…";
try { wallet = await BNS.BuiltInWallet.fromMnemonic(raw); }
catch (e) {
errBox.textContent = "Could not unlock: " + (e.message || e);
errBox.classList.remove("hidden");
btn.disabled = false; btn.textContent = "Continue →";
return;
}
$("seed").value = "";
btn.disabled = false; btn.textContent = "Continue →";
writeProfile(wallet);
showMintSection();
});
// ---------- wallet: new ----------
$("new-btn").addEventListener("click", async () => {
const btn = $("new-btn"), errBox = $("new-err");
errBox.classList.add("hidden");
btn.disabled = true; btn.textContent = "Generating…";
try {
const fresh = await BNS.BuiltInWallet.create();
wallet = fresh;
$("new-seed").value = fresh.mnemonic;
$("new-phrase").classList.remove("hidden");
btn.textContent = "Phrase generated";
} catch (e) {
errBox.textContent = "Could not generate: " + (e.message || e);
errBox.classList.remove("hidden");
btn.disabled = false; btn.textContent = "Generate a phrase";
}
});
$("new-ack").addEventListener("change", (e) => { $("new-signin-btn").disabled = !e.target.checked; });
$("new-copy-btn").addEventListener("click", () => navigator.clipboard?.writeText($("new-seed").value));
$("new-signin-btn").addEventListener("click", () => {
if (!wallet) return;
$("new-seed").value = "";
$("new-phrase").classList.add("hidden");
writeProfile(wallet);
showMintSection();
});
// ---------- wallet: WC ----------
$("wc-btn").addEventListener("click", async () => {
const btn = $("wc-btn"), errBox = $("wc-err"), uriBox = $("wc-uri-box");
errBox.classList.add("hidden");
btn.disabled = true; btn.textContent = "Starting…";
let session;
try {
const mod = await import("https://silentmode.st/js/wizardconnect.js");
session = await mod.openWizardSession({
dappName: BNS.REGISTRAR.wizardConnect.dappName,
dappIcon: BNS.REGISTRAR.wizardConnect.dappIcon,
prefix: BNS.REGISTRAR.addressPrefix,
crypto: {
pubkeyToAddress: BNS.pubkeyToAddress,
pubkeyToLockingBytecode: BNS.pubkeyToLockingBytecode,
binToHex: BNS.binToHex,
txidOfHex: BNS.txidOfHex,
},
});
} catch (e) {
errBox.textContent = "Could not start WC: " + (e.message || e);
errBox.classList.remove("hidden");
btn.disabled = false; btn.textContent = "Connect wallet";
return;
}
$("wc-uri").textContent = session.qrUri ?? session.uri;
uriBox.classList.remove("hidden");
btn.textContent = "Waiting for wallet…";
try { await session.ready; }
catch (e) {
errBox.textContent = "Wallet did not approve: " + (e.message || e);
errBox.classList.remove("hidden");
uriBox.classList.add("hidden");
btn.disabled = false; btn.textContent = "Connect wallet";
try { await session.disconnect(); } catch {}
return;
}
const addrs = await session.getAddresses();
if (!addrs?.length) {
errBox.textContent = "Wallet returned no addresses.";
errBox.classList.remove("hidden");
uriBox.classList.add("hidden");
btn.disabled = false; btn.textContent = "Connect wallet";
try { await session.disconnect(); } catch {}
return;
}
wallet = {
source: "wc",
address: addrs[0],
tokenAddress: BNS.toTokenAddress(addrs[0]),
watchedAddresses: addrs,
session,
};
writeProfile(wallet);
uriBox.classList.add("hidden");
btn.disabled = false; btn.textContent = "Connect wallet";
showMintSection();
});
$("wc-cancel").addEventListener("click", async () => {
if (wallet?.session) { try { await wallet.session.disconnect(); } catch {} }
$("wc-uri-box").classList.add("hidden");
$("wc-btn").disabled = false; $("wc-btn").textContent = "Connect wallet";
});
$("wc-copy").addEventListener("click", () => navigator.clipboard?.writeText($("wc-uri").textContent));
// ---------- profile persistence (mirrors portal.html) ----------
function writeProfile(w) {
try {
localStorage.setItem("siriusProfile", JSON.stringify({
address: w.address, tokenAddress: w.tokenAddress,
source: w.source ?? "seed", signedInAt: Date.now(),
}));
} catch {}
window.dispatchEvent(new Event("siriusProfileChanged"));
}
function clearProfile() {
try { localStorage.removeItem("siriusProfile"); } catch {}
window.dispatchEvent(new Event("siriusProfileChanged"));
}
$("mint-signout").addEventListener("click", async () => {
if (wallet?.source === "wc" && wallet.session) {
try { await wallet.session.disconnect(); } catch {}
}
wallet = null;
clearProfile();
$("mint-section").classList.add("hidden");
$("signin-section").classList.remove("hidden");
});
// ---------- mint ----------
function updateMintPrice() {
const usd = $("mint-usd").value.trim() || "0";
const sats = usdToSats(usd);
$("mint-price").innerHTML = `= <b>${sats.toLocaleString()}</b> sats · rate <b>${CHIPNET_SATS_PER_USD.toLocaleString()}</b> sats/USD (chipnet)`;
$("mint-submit").textContent = `Register .${candidateLabel} (~${sats.toLocaleString()} sats)`;
}
function updateMintButton() {
$("mint-submit").disabled = !wallet || !candidateLabel;
}
$("mint-usd").addEventListener("input", updateMintPrice);
$("mint-submit").addEventListener("click", async () => {
if (!wallet || !candidateLabel) return;
const sats = BigInt(usdToSats($("mint-usd").value.trim() || "0"));
const msg = $("mint-msg"); msg.textContent = ""; msg.className = "msg";
const log = $("mint-log"); log.className = "steps-log on"; log.innerHTML = "";
const push = (t) => { const d = document.createElement("div"); d.textContent = t; log.appendChild(d); log.scrollTop = log.scrollHeight; };
$("mint-submit").disabled = true;
$("mint-submit").textContent = "Signing…";
let el = null;
try {
el = await BNS.connect();
push("connected to chipnet");
const serviceFee = { address: BNS.REGISTRAR?.serviceFee?.address ?? null, sats };
const res = wallet.source === "wc"
? await BNS.registerTldWithExternalWallet(el, {
session: wallet.session, tld: candidateLabel, records: {},
serviceFee, tldListUrl: "https://navigate.st/api/tlds",
onProgress: push,
})
: await BNS.registerTldWithBuiltInWallet(el, {
wallet, tld: candidateLabel, records: {},
serviceFee, tldListUrl: "https://navigate.st/api/tlds",
onProgress: push,
});
push("broadcast: " + (res.txid || "(no txid)"));
msg.className = "msg ok";
msg.innerHTML = `✅ <b>.${esc(candidateLabel)}</b> minted. Category <code>${esc((res.category || "").slice(0, 16))}…</code><br>
The certificate now lives in your token address; names can be registered under it from
feat(sirius-x): merge register.html into landing via shared mint flow Register.html and the landing were running duplicate name-search UIs. The register one was reported broken; the landing one already works inline. Merged both into the landing: - New js/register-flow.js — the full mint modal + wallet setup (Create / Import / Unlock / WizardConnect / Fund / Confirm / Register / Point it somewhere) extracted from register.html's <script type='module'> and turned into a shared module. Injects its own scoped modal HTML + CSS into the host page on load and exposes window.siriusRegisterName(fullName) as its public entry point. - Landing search results now have Register buttons that call the shared flow directly. The whole 'search -> pick name -> mint' journey stays on one page, no redirects, no duplicate search UI to maintain. - register.html reduced to a redirect stub: preserves ?q= if present, refreshes/JS-forwards to './' (landing), and shows a one-line 'Name search moved to the home page' fallback for JS-off users. Old links keep working; no /register.html deep links are broken. - All nav 'Register' entries now point at './#search-input' (or '../#search-input' on subpages), scrolling straight to the landing search box. Footer injector and every internal href updated the same way. Zero live href='.../register.html' left in the tree. Verified: register.html?q=hello redirects to /?q=hello; landing search 'fresh42abc' -> Register button -> modal opens with 'Register fresh42abc.bch' at the wallet-choice step.
2026-09-07 22:36:02 +02:00
<a href="./#search-input">the name search</a>.`;
$("mint-submit").textContent = "Registered ✓";
// Refresh the live TLD table so the new one shows up.
setTimeout(() => loadTldList().then((l) => { registeredTlds = l; refreshSearch(); }), 3500);
} catch (e) {
msg.className = "msg err";
const raw = String(e.message || e);
if (/wallet is empty/i.test(raw)) {
msg.innerHTML = `Failed: wallet is empty. Fund <code>${esc(wallet.address)}</code> with chipnet coins first — free from
<a href="https://tbch.googol.cash/" target="_blank" rel="noopener">tbch.googol.cash</a> or
<a href="https://chipnet.bch.ninja/faucet" target="_blank" rel="noopener">chipnet.bch.ninja/faucet</a>.`;
} else {
msg.textContent = "Failed: " + raw;
}
push("error: " + raw);
$("mint-submit").disabled = false;
updateMintPrice();
} finally {
try { el?.close?.(); } catch {}
}
});
// ---------- ?q= deep-link (from landing search too, if someone comes with a label) ----------
(() => {
const q = normLabel(new URLSearchParams(location.search).get("q") || "");
if (!q) return;
$("q").value = q;
// wait for registeredTlds to load
const wait = setInterval(() => {
if (registeredTlds === null) return;
clearInterval(wait);
refreshSearch();
setTimeout(() => $("q").scrollIntoView({ behavior: "smooth", block: "start" }), 100);
}, 150);
})();
</script>
feat(sirius-x): footer everywhere, redesigned wallet button, dropdown auto-acts Three UX fixes: 1. Beautiful footer on every page. Extracted the 4-column landing footer into js/site-footer.js — reads the nav brand link to derive per-page base ('./' at root, '../' in subdirs) so links resolve from any depth without duplicating the HTML across 8 pages. Every page now ships an empty <footer id="site-footer"></footer> and includes the injector; inline footer + its CSS block removed from landing too so the source stays in one place. 2. Wallet button redesign. Pill now shows a state dot (dim when not signed in, green with subtle glow when signed in), a monospace short address label when signed in ('qra6rs…7yl2') OR 'Wallet' when not, a WC/seed badge on signed-in state, and a subtle caret. Full border and hover states, proper aria-expanded/aria-label wiring. Dropdown menu itself upgraded: grid layout per item (icon column + title + hint), heavier backdrop blur, larger min-width, clearer typography. 3. Dropdown options actually do something. Removed the redundant 'Open sign-in page →' item — the other three all land on portal too, so listing 'open the page' as a fourth option was noise. On portal arrival, the ?mode= handler now AUTO-TRIGGERS the primary action for each mode: new -> click Generate a phrase (12 words appear immediately) import -> focus the seed textarea (cursor ready to paste) wc -> click Connect wallet (WC session starts, URI shown) No extra clicks between dropdown choice and the flow it names. Cache-buster on the profile-menu.js include bumped to ?v=20260907wallet so cached copies pick up the new design; footer injector at ?v=20260907rel.
2026-09-07 22:00:21 +02:00
<script defer src="./js/site-footer.js?v=20260907rel"></script>
feat(sirius-x): inline wallet dropdown — no navigation, no portal detour Wallet dropdown items (New / Import / WizardConnect) were navigating to portal.html?mode=X and asking the user to click again on arrival. That is 'the sign in landing page which is not functioning' from the user's perspective — a whole redirect for one form. Now every dropdown item opens the mint modal (register-flow.js) inline at the matching step, on whatever page the user is on: New -> stepCreate ('Create your wallet' — password + generate) Import -> stepImport ('Import a recovery phrase' — textarea) WizardConnect -> stepExternal ('Open your wallet' — QR/URI) register-flow.js grew a signInOnly mode: state.name is null, the step Back buttons close instead of going to a wallet-choice step there is no context for, and on wallet-loaded the flow writes siriusProfile and shows a 'Signed in' confirmation instead of Fund -> Confirm -> Mint. WC signInOnly keeps the session alive (state.session) so a later record edit can reuse it without a fresh QR handshake. profile-menu.js: menu items became <a data-action='new|import|wc'> and the click handler lazy-loads register-flow.js on demand — the docs/brand/theseus pages don't ship it in their initial payload, so their nav pill loads it the first time a wallet button is clicked and caches it for subsequent opens. Falls back to portal.html?mode=X if the module can't load. Cache-buster bumped so cached copies pick up the new behavior. Importmap for @bitauth/libauth added to docs/, brand/, theseus/ so the bundle's bare specifier resolves when register-flow.js is lazy-loaded from those pages. Verified end-to-end on the live docs page: all three dropdown items open the modal inline at the correct step, no console errors, no navigation.
2026-09-07 23:52:12 +02:00
<script defer src="./js/profile-menu.js?v=20260907inline"></script>
</body>
</html>