diff options
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 32 |
1 files changed, 30 insertions, 2 deletions
@@ -648,12 +648,22 @@ function attachZoom(box, img, { wheel = true } = {}) { const mx = Math.max(0, (img.offsetWidth * s - window.innerWidth) / 2), my = Math.max(0, (img.offsetHeight * s - window.innerHeight) / 2); x = Math.min(mx, Math.max(-mx, x)); y = Math.min(my, Math.max(-my, y)); }; + // Chrome keeps a will-change: transform layer rastered at 1× and scales + // the bitmap: zoomed in, the raster's tiles show as a faint grid of + // seams across the picture ("very faint grid lines", Adam, 2026-11-02). + // The hint is on while a gesture moves the picture (no re-raster per + // frame) and off once it settles zoomed, so the picture is drawn again + // at its real scale: sharp, and seamless. + let settle = 0; const apply = (animate) => { + clearTimeout(settle); img.style.transition = animate ? 'transform .2s ease' : 'none'; img.style.transform = s === 1 && !x && !y ? '' : `translate(${x}px, ${y}px) scale(${s})`; img.style.cursor = s > 1 ? 'grab' : ''; // zoomed, the finger pans the picture; at 1× the touch is the page's (a pager's swipe) img.style.touchAction = s > 1 ? 'none' : ''; + img.style.willChange = 'transform'; + settle = setTimeout(() => { img.style.willChange = s > 1 ? 'auto' : ''; }, animate ? 250 : 120); }; // scale to ns keeping the picture point under (cx, cy) where it is const zoomAt = (ns, cx, cy) => { @@ -875,7 +885,12 @@ function renderInner() { const side = bottomNav && featScreen && !restorePending() && WIDE_MQ && WIDE_MQ.matches ? walletSide() : null; // a call, over whatever page is up (the messages feature's) const callOv = activeAccount() ? featureHook('callOverlay') : null; - morphChildren(root, [screen, footer(), ...(bottomNav ? [bottomNav] : []), ...(side ? [side] : []), ...(ui.lightbox ? [imageViewer()] : []), ...(callOv ? [callOv] : [])]); + // What a feature floats over its page (the feed's post button and + // new-posts pill): fixed-position nodes, so they live beside the page, + // not inside it — the page's entrance animation transforms it, and a + // transform makes fixed descendants position within the page. + const floaters = h('div', { class: 'page-floaters', style: 'display:contents' }, ...featureAll('pageFloaters')); + morphChildren(root, [screen, floaters, footer(), ...(bottomNav ? [bottomNav] : []), ...(side ? [side] : []), ...(ui.lightbox ? [imageViewer()] : []), ...(callOv ? [callOv] : [])]); promoteLazySrc(root); // sources on the nodes that actually made it into the page try { document.documentElement.classList.toggle('no-scroll', !!(ui.lightbox || ui.mediaPager)); } catch {} if (fpath) { @@ -4160,6 +4175,19 @@ function onboardScreen() { }, t('onbStart')), h('div', { class: 'onb-or' }, h('span', {}, t('onbOrSignIn'))), signinDoors(), + // Bringing a wallet from another device: its twelve words, typed in. + // This used to hide as a line under the freshly minted words behind + // "Create a new wallet", where a person signing in on their second + // phone found it only by chance (user feedback, 2026-11-02). Its own + // door, straight to the import pane. + h('button', { id: 'onb-restore', class: 'btn-block', style: 'padding:14px', onClick: () => { + clearSeedDrafts(); + ui.unlockTab = 'import'; + ui.unlockError = ''; + ui.onbError = ''; + o.step = 'seed'; + render(); + } }, t('onbRestoreDoor')), // The move from the original coinos.io used to wait behind the // Spending offer, where nobody looking for it found it. Its own door // on the front page: it stashes the intent the /migrate link stashes @@ -4234,7 +4262,7 @@ function onboardScreen() { // means seeing (or bringing) your seed phrase, not a wallet minted // behind your back. Opening one ends the wizard into the wallet + tour. return page([ - title(t('onbSeedTitle')), + title(t(ui.unlockTab === 'import' ? 'onbRestoreTitle' : 'onbSeedTitle')), unlockCard(), // the entropy page brings its own Back — one is enough ui.entropyPage ? null : h('button', { class: 'linklike small', onClick: () => { ui.unlockError = ''; o.step = 'welcome'; render(); } }, t('back')), |
