diff options
| author | Adam Soltys <[email protected]> | 2026-06-24 19:39:50 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-24 19:39:50 -0700 |
| commit | 9e2737e6736f9dd582d083c6d6fd669a28a99316 (patch) | |
| tree | 94e45183fdc14a165b2e442a7bdfaf4dded5b648 /src/app.js | |
| parent | 83e559684eed07d1a11fd0748ff571f8b8896921 (diff) | |
| download | coinosv3-9e2737e6736f9dd582d083c6d6fd669a28a99316.tar.gz coinosv3-9e2737e6736f9dd582d083c6d6fd669a28a99316.zip | |
Add dark mode; gift amount unit toggle; multi-input gifts
- Dark mode: theme variables + a footer "Dark mode/Light mode" toggle,
persisted and applied pre-paint via a small head script (defaults to the
OS preference). Hardcoded surfaces moved to CSS variables.
- Gift amount: the unit label is now the clickable sats/BTC toggle, and the
amount is parsed in the selected unit.
- Gifts can now span multiple coins: createGift selects several confirmed
coins (first input SIGHASH_SINGLE to lock the change, the rest
SIGHASH_NONE), so a gift larger than any single coin works. Claim/preview
sum all inputs and size the fee by input count. Verified end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 28 |
1 files changed, 24 insertions, 4 deletions
@@ -123,12 +123,32 @@ function footer() { installPrompt ? h('span', {}, h('span', { class: 'faint' }, ' · '), h('button', { class: 'linklike', style: 'font-weight:400', onClick: triggerInstall }, t('installApp'))) - : null + : null, + h('span', { class: 'faint' }, ' · '), + h('button', { class: 'linklike', style: 'font-weight:400', onClick: toggleTheme }, resolvedTheme() === 'dark' ? t('lightMode') : t('darkMode')) ), h('div', { style: 'margin-top:8px' }, languagePicker()) ); } +const THEME_KEY = 'btc-wallet-theme'; +function resolvedTheme() { + try { + const s = localStorage.getItem(THEME_KEY); + if (s === 'dark' || s === 'light') return s; + } catch {} + try { return matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } catch {} + return 'light'; +} +function applyTheme() { + try { document.documentElement.dataset.theme = resolvedTheme(); } catch {} +} +function toggleTheme() { + try { localStorage.setItem(THEME_KEY, resolvedTheme() === 'dark' ? 'light' : 'dark'); } catch {} + applyTheme(); + render(); +} + // PWA install. Chrome fires beforeinstallprompt when the app qualifies; we stash // the event and reveal an "Install app" link, then replay it on a user tap (the // browser requires a gesture). beforeinstallprompt only fires when not already @@ -958,7 +978,7 @@ function giftRate() { function createGiftLink() { const rate = giftRate(); const min = giftMinimum(rate); - const amt = Math.round(Number(ui.giftAmount)); + const amt = parseAmount(ui.giftAmount, unit); // entered in the current display unit if (!amt || amt < min) { ui.giftError = t('giftAmountInvalid', { n: fmtAmount(min) + ' ' + unitLabel() }); render(); return; } try { ui.giftCode = wallet.createGift(amt, rate).code; @@ -987,9 +1007,9 @@ function giftCard() { ) : h('div', { class: 'col gap6' }, h('div', { class: 'input-group' }, - h('input', { type: 'number', min: String(giftMinimum(giftRate())), inputmode: 'numeric', placeholder: t('giftAmountLabel'), + h('input', { type: 'number', step: unit === 'sats' ? '1' : '0.00000001', min: '0', inputmode: 'decimal', placeholder: t('giftAmountLabel'), value: ui.giftAmount, onInput: (e) => (ui.giftAmount = e.target.value) }), - h('span', { class: 'small muted', style: 'align-self:center' }, unitLabel()) + h('div', { style: 'display:flex;align-items:center' }, unitTag()) ), h('div', { class: 'small faint' }, t('giftMinNote', { n: fmtAmount(giftMinimum(giftRate())) + ' ' + unitLabel() })), ui.giftError && h('div', { class: 'notice err' }, ui.giftError), |
