From ff411c6e1eb708e434899f66d66bf242fb576336 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 20 Sep 2026 23:33:07 -0700 Subject: Settings → Nostr: make coinos the browser's handler for web+nostr: and bitcoin: links. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit njump's "Your default web app" is a web+nostr: link: it opens whichever site registered that scheme. A card offers to register this app (the browser asks), and ?u= now accepts the web+nostr: form. Co-Authored-By: Claude Fable 5.1 --- src/app.js | 26 ++++++++++++++++++++++++-- src/i18n.js | 6 ++++++ 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/app.js b/src/app.js index 3da5e77..58bc242 100644 --- a/src/app.js +++ b/src/app.js @@ -2548,11 +2548,31 @@ function settingsTab() { } // Everything nostr — identity, sync, wallet connect — on its own page. +// Ask the browser to send a URL scheme's links to this app (the ?u= path +// the Android intents already use). Chrome shows its own permission bar; +// a scheme it won't register throws and we say so. +function registerLinkHandler(scheme) { + try { + navigator.registerProtocolHandler(scheme, location.origin + '/?u=%s'); + toast(t('linkHandlerAsked')); + } catch (e) { toast(t('linkHandlerRefused')); } +} function nostrSettingsView() { return h( 'div', { class: 'col', style: 'gap:16px' }, ...featureAll('nostrSettingsCards'), + // The browser's own "open these links here" registry: njump's "Your + // default web app" is a web+nostr: link, and it opens whichever site + // asked for that scheme last. Needs a tap (the browser asks). + typeof navigator !== 'undefined' && navigator.registerProtocolHandler + ? h('div', { class: 'card col', style: 'gap:8px' }, + h('h3', {}, t('linkHandlerTitle')), + h('p', { class: 'small muted', style: 'margin:0' }, t('linkHandlerDesc')), + h('div', { class: 'row gap6', style: 'flex-wrap:wrap' }, + h('button', { class: 'btn-sm', onClick: () => registerLinkHandler('web+nostr') }, t('linkHandlerNostr')), + h('button', { class: 'btn-sm', onClick: () => registerLinkHandler('bitcoin') }, t('linkHandlerBitcoin')))) + : null, h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.settingsPage = null; render(); } }, t('back')) ); } @@ -5472,9 +5492,11 @@ const INTENT_URI = (() => { const u = new URLSearchParams(location.search).get('u'); if (!u) return null; history.replaceState(null, '', location.pathname || '/'); - const m = u.match(/^nostr:((npub|nprofile|note|nevent)1[a-z0-9]+)\/?$/i); + // web+nostr: is what a browser hands a registered protocol handler + // (njump's "Your default web app"); nostr: is the Android intent + const m = u.match(/^(?:web\+)?nostr:((npub|nprofile|note|nevent)1[a-z0-9]+)\/?$/i); if (m) { history.replaceState(null, '', '/' + m[1]); return null; } - return u; + return u.replace(/^web\+/i, ''); } catch { return null; } })(); const FEATURES = buildFeatures(ctx); diff --git a/src/i18n.js b/src/i18n.js index 68ff24e..5ce4a18 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -245,6 +245,12 @@ const STR = { feedSumFollowsPlus: 'Everyone you follow + {n} more', feedSumPeople: '{n} people', feedPacks: 'Follow packs', + linkHandlerTitle: 'Open links here', + linkHandlerDesc: 'Make this app the one your browser opens for nostr links (what njump calls "Your default web app") and bitcoin: links.', + linkHandlerNostr: 'nostr links', + linkHandlerBitcoin: 'bitcoin: links', + linkHandlerAsked: 'Your browser is asking — allow it to finish', + linkHandlerRefused: 'Your browser would not register this here', feedAddPack: 'Search packs, or paste a following.space link…', feedPacksHelp: 'A pack is a list someone curates. Its members are read live, so the feed follows the list as it changes.', feedPackMembers: '{n} members', -- cgit v1.2.3