From 392e73b9d163f39555895e9652d3a80f41cce6f3 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 15 Nov 2026 14:27:20 -0700 Subject: The footer is just the language and currency; everything else moved to Settings → About. "Let's move all the footer stuff to an about page or something except for the language and currency toggles" (Adam, 2026-11-15). A new About tile (an info mark) on the Settings hub opens a page with the credits (made by Adam Soltys, source on git.coinos.io), How it works, Show your support (once a wallet is open), Install app (when the browser offers it), the Dark/Light mode switch and the running commit. footer-support-test now checks the footer holds only the two pickers and drives About (credits, theme switch, support → hat shop); onboard-backup, chat-layout, features-smoke and signup-quick pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VMan6SwkivduFDDkMmnXjZ --- src/app.js | 73 ++++++++++++++++++++++++++++--------------------------------- src/i18n.js | 2 ++ 2 files changed, 35 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/app.js b/src/app.js index e1a606a..60b0ac9 100644 --- a/src/app.js +++ b/src/app.js @@ -375,49 +375,39 @@ function setupFooter() { return h('div', { class: 'footer small muted center' }, h('div', { class: 'row gap6', style: 'justify-content:center' }, lang)); } +// The footer is the display preferences alone: the language this reads in, +// and the currency amounts are shown in. Everything else that used to sit +// here (credits, How it works, support, install, the theme, the commit) is +// on Settings → About (Adam, 2026-11-15). function footer() { - return h( - 'div', - { class: 'footer small muted center' }, - h( - 'div', - {}, - t('footerMadeBy') + ' ', - h('a', { href: 'https://adamsoltys.com', target: '_blank', rel: 'noopener' }, 'Adam Soltys'), - h('span', { class: 'faint' }, ' · '), - t('footerSourceOn') + ' ', - h('a', { href: 'https://git.coinos.io/coinosv3.git/', target: '_blank', rel: 'noopener' }, 'git.coinos.io') - ), - h( - 'div', - { style: 'margin-top:4px' }, - h('button', { class: 'linklike', style: 'font-weight:400', onClick: openHowItWorks }, t('howItWorks')), - // the hat shop: needs a wallet to pay from, so only once one is open + return h('div', { class: 'footer small muted center' }, + h('div', { class: 'row gap6', style: 'justify-content:center' }, languagePicker(), currencyPicker())); +} + +function aboutSettingsView() { + const row = (label, onClick, attrs = {}) => h('button', { class: 'btn-block', onClick, ...attrs }, label); + return h('div', { class: 'col', style: 'gap:16px' }, + h('div', { class: 'card col about-card', style: 'gap:10px' }, + h('h3', {}, t('aboutTitle')), + h('p', { class: 'small muted', style: 'margin:0' }, + t('footerMadeBy').replace(/^./, (c) => c.toUpperCase()) + ' ', + h('a', { href: 'https://adamsoltys.com', target: '_blank', rel: 'noopener' }, 'Adam Soltys'), + '. ' + t('footerSourceOn').replace(/^./, (c) => c.toUpperCase()) + ' ', + h('a', { href: 'https://git.coinos.io/coinosv3.git/', target: '_blank', rel: 'noopener' }, 'git.coinos.io'), '.'), + row(t('howItWorks'), openHowItWorks), + // the hat shop pays from the wallet, so only once one is open activeAccount() && FEATURES.some((f) => f.openHatShop) - ? h('span', {}, h('span', { class: 'faint' }, ' · '), - h('button', { class: 'linklike', style: 'font-weight:400', onClick: () => { clearFeatureNav(); ui.screen = 'wallet'; featureHook('openHatShop'); } }, t('footerSupport'))) - : null, - // Chrome no longer prompts to install on its own — surface our own link - // once it reports the app is installable. We render from a persisted flag - // (not the live event) so the link is present on the first paint after a - // refresh, avoiding a layout shift when beforeinstallprompt fires late. - installable() - ? h('span', {}, h('span', { class: 'faint' }, ' · '), - h('button', { class: 'linklike', style: 'font-weight:400', onClick: triggerInstall }, t('installApp'))) + ? row(t('footerSupport'), () => { clearFeatureNav(); ui.screen = 'wallet'; featureHook('openHatShop'); }, { id: 'about-support' }) : null, - h('span', { class: 'faint' }, ' · '), - h('button', { class: 'linklike', style: 'font-weight:400', onClick: toggleTheme }, resolvedTheme() === 'dark' ? t('lightMode') : t('darkMode')) - ), - // Display preferences live together: the language this reads in, and the - // money amounts are shown in. (The currency sat under Settings → Network - // for exactly one day, where nobody found it.) - h('div', { class: 'row gap6', style: 'margin-top:8px;justify-content:center' }, languagePicker(), currencyPicker()), - // The commit stamp settles "is my PWA fresh?" AND "what code is this?" in - // one glance — its own last line, so it never wraps the credits on mobile. - h('div', { class: 'faint', style: 'margin-top:6px' }, - 'Running git commit ', - h('a', { class: 'faint', href: 'https://git.coinos.io/coinosv3.git/commit/?id={{COMMIT}}', target: '_blank', rel: 'noopener' }, '{{COMMIT}}')) - ); + // Chrome no longer prompts to install by itself: our own button, once + // it has said the app is installable (a persisted flag, see installable) + installable() ? row(t('installApp'), triggerInstall) : null, + row(resolvedTheme() === 'dark' ? t('lightMode') : t('darkMode'), toggleTheme, { id: 'about-theme' }), + // "is my PWA fresh?" and "what code is this?" in one line + h('div', { class: 'small faint', style: 'margin-top:2px' }, + 'Running git commit ', + h('a', { class: 'faint', href: 'https://git.coinos.io/coinosv3.git/commit/?id={{COMMIT}}', target: '_blank', rel: 'noopener' }, '{{COMMIT}}'))), + h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.settingsPage = null; render(); } }, t('back'))); } const THEME_KEY = 'btc-wallet-theme'; @@ -3257,6 +3247,7 @@ function settingsTab() { case 'nostr': return nostrSettingsView(); case 'notifications': return page(featureAll('notifySettingsCards').reverse()); case 'advanced': return advancedSettingsView(); + case 'about': return aboutSettingsView(); } const I = (d) => '' + d + ''; const TILE_ICONS = { @@ -3267,6 +3258,7 @@ function settingsTab() { // a till receipt: paper with a torn foot and two lines of figures pos: I(''), notifications: I(''), + about: I(''), advanced: I(''), }; const tile = (id, label, desc) => @@ -3292,6 +3284,7 @@ function settingsTab() { tile('nostr', t('nostrSettings'), t('settingsNostrDesc')), tile('notifications', t('settingsNotifications'), t('settingsNotifDesc')), tile('advanced', t('advancedSettings'), t('settingsAdvancedDesc')), + tile('about', t('aboutTitle'), t('settingsAboutDesc')), ]), h('button', { class: 'btn-ghost btn-block', style: 'margin-top:6px', onClick: () => { ui.tab = wallet.offline ? 'settings' : 'history'; render(); } }, t('back')) ); diff --git a/src/i18n.js b/src/i18n.js index c901576..121c806 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -1676,6 +1676,8 @@ const STR = { settingsNostrDesc: 'Identity and connections', settingsNotifDesc: 'What buzzes this device', settingsAdvancedDesc: 'Network, rarities, rescues', + aboutTitle: 'About', + settingsAboutDesc: 'How it works, support, app, theme', settingsPosDesc: 'Till mode, tips and the /pos link', unlockForLabel: 'Stay unlocked', unlockFor5m: '5 minutes', -- cgit v1.2.3