Swipe between items like turning pages (#52)

On a phone the reader is fixed over the item list, and the swipe from #49 moved it alone and
faded it to 40%, so the list showed through it and in the strip it uncovered, and again as the
next item slid in from the far side. Now a layer beside the reader, #dpeek, holds what is really
there: the next or previous item, drawn by the same detailHtml the reader uses, with 16px of the
page's background between them; "No more items" past the last; or, swiping right from the
first, a dimmer over the list that lifts as the reader, shadowed along its edge, is drawn off.
On release the swipe carries on from where the finger left it, over 120-250ms by how far is
left, and the neighbour becomes the reader in place; with reduced motion it switches at once.

A touch starting within 14px of the left edge is kept from Safari, which otherwise takes it as
Back and leaves the page mid-swipe. 14px because the back button starts at 16.

Offsets are rounded to whole pixels: at a fractional offset the seam between the reader and its
neighbour drew a stray light line.

The design had the list shift a third of the way across as it is uncovered, as iOS does. #detail
lives inside #shell, and a transform there makes it the containing block for the fixed reader,
so that part is left out; the dimmer and shadow carry it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 23:46:07 +00:00
parent a573a07ed5
commit f2fde8cc75
5 changed files with 113 additions and 28 deletions

View File

@@ -993,6 +993,18 @@ body:has(#player.on) #status{padding-bottom:3px}
#detail{position:fixed;inset:0;z-index:38;display:none;border-top:0;padding:12px 16px 90px}
body.reading #detail{display:block}
#dback{display:inline-block;margin-bottom:10px}
/* Beside the reader while it is swiped (gestures.ts): the item next to it, with a strip of the
page's own background between them, so the list under the reader never shows (#52). */
#dpeek{position:fixed;top:0;bottom:0;left:0;width:calc(100% + 16px);z-index:38;background:var(--bg);pointer-events:none}
#dpeek>div{width:calc(100% - 16px);height:100%;overflow:hidden;padding:12px 16px 90px;background:var(--panel)}
#dpeek.next>div{margin-left:16px}
#dpeek .encbox{margin:0 0 10px}
#dpeek.end{display:flex;align-items:center;padding-left:28px;color:var(--faint);font-size:13px}
#dpeek.end p{max-width:4.5em;margin:0}
/* Going back to the list from the first item: the list waits under a dimmer that lifts as the
reader, shadowed along its edge, is drawn off it. */
#dpeek.dim{width:100%;z-index:37;background:#000}
#detail.popping{box-shadow:-12px 0 32px rgba(0,0,0,.28)}
#content>.fhead,#content>.toolbar{padding-left:14px;padding-right:14px}
#content>.fhead{padding-top:12px}
@@ -1104,6 +1116,7 @@ body:has(#player.on) #status{padding-bottom:3px}
:root[data-theme="glass"] #status,
:root[data-theme="glass"] #files,
:root[data-theme="glass"] #detail,
:root[data-theme="glass"] #dpeek>div,
:root[data-theme="glass"] .card,
:root[data-theme="glass"] .toast{
/* A sheen from the top-left corner, where the light comes from. It is a background layer rather
@@ -1151,6 +1164,7 @@ body:has(#player.on) #status{padding-bottom:3px}
:root[data-theme="glass"] #status,
:root[data-theme="glass"] #files,
:root[data-theme="glass"] #detail,
:root[data-theme="glass"] #dpeek>div,
:root[data-theme="glass"] .card,
:root[data-theme="glass"] .toast,
:root[data-theme="glass"] .tgroup,