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:
@@ -230,6 +230,19 @@ function showDetail(e){
|
||||
}
|
||||
// Nothing when there are no files: the pane that would say so is hidden above, and on a phone,
|
||||
// where the files sit over the text, a box saying "No files" only pushed the text down.
|
||||
const encs=e.enclosures.map(encBox).join('');
|
||||
const narrow=!!window.matchMedia?.('(max-width:820px)')?.matches;
|
||||
box.innerHTML=detailHtml(e);
|
||||
if(files) files.innerHTML=narrow?'':`<div class="fhd">Files</div>${encs}`;
|
||||
$('#dback').onclick=()=>showDetail(null);
|
||||
for(const root of [box,files]) if(root) $$('button[data-a]',root).forEach(b=>
|
||||
b.onclick=()=>epAction(b.dataset.a,e,null,b.dataset.enc?Number(b.dataset.enc):null));
|
||||
syncPlayButtons();
|
||||
}
|
||||
|
||||
/// What the reader shows for an item. Its own function because a phone also draws the next or
|
||||
/// previous item beside the reader while it is swiped (gestures.ts).
|
||||
function detailHtml(e){
|
||||
const encs=e.enclosures.map(encBox).join('');
|
||||
// A phone has no room for the files pane, so the files go above the text there instead.
|
||||
// Below it, a long set of show notes pushed play and delete screens down, and on an iPhone
|
||||
@@ -237,7 +250,8 @@ function showDetail(e){
|
||||
const narrow=!!window.matchMedia?.('(max-width:820px)')?.matches;
|
||||
const f=S.feeds.find(x=>x.id===e.feed_id);
|
||||
const num=[e.season?`S${e.season}`:'',e.episode?`E${e.episode}`:''].filter(Boolean).join('');
|
||||
box.innerHTML=`
|
||||
// description was sanitized server-side with ammonia before it ever reached here
|
||||
return `
|
||||
<button class="btn ico" id="dback" title="Back to the items" aria-label="Back to the items">${ICON.left}</button>
|
||||
<h3 class="dt">${esc(e.title||'(untitled)')}</h3>
|
||||
<div class="dmeta">
|
||||
@@ -254,12 +268,6 @@ function showDetail(e){
|
||||
</div>
|
||||
${narrow?encs:''}
|
||||
<div class="dbody">${(e.description&&e.description.trim())||'<em>No show notes.</em>'}</div>`;
|
||||
if(files) files.innerHTML=narrow?'':`<div class="fhd">Files</div>${encs}`;
|
||||
// description was sanitized server-side with ammonia before it ever reached here
|
||||
$('#dback').onclick=()=>showDetail(null);
|
||||
for(const root of [box,files]) if(root) $$('button[data-a]',root).forEach(b=>
|
||||
b.onclick=()=>epAction(b.dataset.a,e,null,b.dataset.enc?Number(b.dataset.enc):null));
|
||||
syncPlayButtons();
|
||||
}
|
||||
|
||||
/// One enclosure: a play button when the file is here, otherwise what it is and a way to get it.
|
||||
|
||||
Reference in New Issue
Block a user