diff options
| author | Adam Soltys <[email protected]> | 2026-08-04 00:22:19 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-04 00:22:19 -0700 |
| commit | bba0b5f36841ef68950154fdbe278d6c249ca375 (patch) | |
| tree | f67b89e92bdc925c116967c718460466dc64be3c /src/app.js | |
| parent | ea4b6192f34562e38eeff3e5c246f90646f1b37d (diff) | |
| download | coinosv3-bba0b5f36841ef68950154fdbe278d6c249ca375.tar.gz coinosv3-bba0b5f36841ef68950154fdbe278d6c249ca375.zip | |
Paste lives in the field; the footer fits; claiming a name comes first
Paste, on the import and load-seed screens, was a bordered box floating
beside a small label — heavier than the label, detached from the field it
fills. It now sits inside the textarea, and only while that textarea is
empty: the only time it's wanted, and the only time it can't cover what
you typed. It's toggled on the node rather than through render(), since
re-rendering a textarea per keystroke rebuilds it under the caret. Beside
a one-line input (Send) the old placement was right and is untouched.
The footer measured 100dvh, which on a phone can resolve to the tall
viewport at first paint and leave the language picker just below the
fold. svh is the one that fits with the address bar showing. Short
screens also tighten their padding, which buys back the ~50px the
create/import screen was overflowing at 375x553.
And the wizard no longer asks every new user whether they have an old
coinos.io account before letting them have a name. Claiming the name is
the step; the people who do have an old account know it, and say so with
a link. That screen is a statement now, not a question they just
answered. The npub-shaped default address is no longer offered as a
button — a plain skip goes past without showing anyone that.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 49 |
1 files changed, 31 insertions, 18 deletions
@@ -510,6 +510,25 @@ function pasteBtn(apply) { }); } +// Paste, for a textarea. Beside a one-line input the button belongs in the +// input-group (see Send); above a textarea it floats next to the label as a +// box heavier than the label itself. So put it inside the field — and only +// while the field is empty, which is the only time it's wanted and the only +// time it can't cover what you typed. +function pasteInto(ta, apply) { + const btn = pasteBtn((text) => { apply(text); sync(); }); + if (!btn) return ta; + btn.classList.add('paste-in'); + btn.append(h('span', {}, t('paste'))); + const wrap = h('div', { class: 'paste-wrap' }, ta, btn); + // Toggled on the node rather than through render(): re-rendering a textarea + // on every keystroke rebuilds it under the caret. + const sync = () => wrap.classList.toggle('has-text', !!ta.value); + ta.addEventListener('input', sync); + sync(); + return wrap; +} + // ---------------------------------------------------------------- display unit // Global BTC/sats preference, persisted in localStorage across refreshes and // logouts. Every unit label on the site is clickable to toggle it. @@ -766,11 +785,8 @@ function importPane() { h( 'label', { class: 'field' }, - h('div', { class: 'row between' }, - h('span', { class: 'lab' }, t('importLabel')), - pasteBtn((text) => { ta.value = text; ui.importText = text; }) - ), - ta + h('span', { class: 'lab' }, t('importLabel')), + pasteInto(ta, (text) => { ta.value = text; ui.importText = text; }) ), optionsPanel(), h('button', { class: 'btn-primary btn-block', onClick: () => openWallet(ui.importText) }, t('openWallet')) @@ -2121,7 +2137,7 @@ function onboardScreen() { const o = ui.onb; // steps that were waiting on something advance the moment it exists if ((o.step === 'welcome' || o.step === 'signin') && ui.screen === 'wallet' && activeAccount()) { - o.step = 'legacy'; + o.step = 'username'; o.enterAddr = featureHook('namesAddress') || null; } if (o.step === 'username') { @@ -2163,10 +2179,8 @@ function onboardScreen() { disabled: !!o.legacyBusy, onClick: goLegacy, }, o.legacyBusy ? h('span', { class: 'spinner sm' }) : t('onbLegacyGo')), h('button', { class: 'btn-block', style: 'padding:14px', onClick: () => { o.step = 'username'; render(); } }, - o.wentToLegacy ? t('onbLegacyDone') : t('onbLegacyNo')), + o.wentToLegacy ? t('onbLegacyDone') : t('back')), ui.onbError ? h('div', { class: 'notice err' }, ui.onbError) : null, - // No Back: the wallet exists by now, so the nostr question behind us - // would just bounce straight back here. Both choices lead forward. ]); } if (o.step === 'welcome') { @@ -2207,10 +2221,12 @@ function onboardScreen() { title(t('onbNameTitle')), h('p', { class: 'muted', style: 'margin:0' }, t('onbNameBody')), featureHook('namesClaimForm') || h('div', { class: 'row gap6', style: 'align-items:center' }, h('span', { class: 'spinner sm' }), h('span', { class: 'small muted' }, t('onbNameWait'))), - addr - ? h('button', { class: 'btn-block', onClick: () => { o.step = 'avatar'; render(); } }, - t('onbKeepPre'), h('span', { class: 'onb-addr' }, addr), t('onbKeepPost')) - : null, + // A way past without naming yourself, but not one that shows the + // npub-shaped default address — nobody wants to be offered that. + addr ? h('button', { class: 'linklike small', onClick: () => { o.step = 'avatar'; render(); } }, t('onbSkipName')) : null, + // Most people are new. The ones who aren't know it, and can say so here + // rather than everyone being asked first. + h('button', { class: 'linklike small', onClick: () => { ui.onbError = ''; o.step = 'legacy'; render(); } }, t('onbHaveCoinos')), ]); } if (o.step === 'avatar') { @@ -2607,12 +2623,9 @@ function loadSeedCard() { return h( 'div', { class: 'card col' }, - h('div', { class: 'row between' }, - h('h3', { style: 'margin:0' }, t('loadSeedTitle')), - pasteBtn((text) => { seedTa.value = text; ls.value = text; }) - ), + h('h3', { style: 'margin:0' }, t('loadSeedTitle')), h('p', { class: 'small muted', style: 'margin:0' }, t('loadSeedDesc')), - seedTa, + pasteInto(seedTa, (text) => { seedTa.value = text; ls.value = text; }), h('input', { type: 'password', class: 'mono-input', placeholder: t('bip39PassphraseOpt'), autocapitalize: 'none', autocomplete: 'off', value: ls.passphrase, |
