source: Klonkt/src/views/partials/read-article.ejs@ a505f31

main
Last change on this file since a505f31 was a505f31, checked in by Robin <roboburr@…>, 3 weeks ago

Lezen: Lenis voor het snappen op desktop, plus twee kleine dingen

WAAROM LENIS, en dat is niet het vloeiende scrollen: de DUUR van een snap is
met native scroll-snap niet in te stellen -- die zit in de browser. Robin
vroeg om een snellere snap, en dat was declaratief onmogelijk. Lenis' snap-
pakket geeft ons duration, easing, distanceThreshold en debounce.

distanceThreshold 12% de vangzone (native: browsereigen, ~200-300px)
duration 0.4s in totaal onder de halve seconde
easing easeOutQuart -- op de helft van de tijd is 94% van de

weg af, daarna zacht uitdempen. Bewust niet
Lenis' standaard easeOutExpo: die schiet weg
en kruipt zo lang na dat het lijkt of hij niet
afmaakt.

debounce 60ms niet de standaard 500; dat voelt als te laat

ALLEEN OP DESKTOP (hover: hover en pointer: fine). Op touch doet Lenis van
zichzelf niets -- syncTouch staat uit -- en is het systeem-scrollen al
soepel. Daar blijft de native CSS-snap staan die er nu is, inclusief het
anker van nul hoog en de richtingsschakelaar. Robins keuze: "enkel voor
desktop, dat is prima, logisch dat het niet op mobiel kan".

Omhoog niet snappen gaat met Lenis via snap.stop()/start(), een stuk
schoner dan de CSS-eigenschap omzetten. Beide wegen delen dezelfde
richtingsdetectie uit wiel, vinger en toets.

NOG NIET UIT: smoothWheel. Dat kwam er na het snappen bij, en het is de kant
die oppassen vraagt -- een Mac-trackpad heeft zijn EIGEN momentum en Lenis'
demping komt daar bovenop. Vandaar lerp 0.2 in plaats van de standaard 0.1.
Robin vond dat op 20-8 nog steeds te zweverig, dus dat getal moet nog omhoog
of smoothWheel moet terug naar false. Die tweede stand werkte ook; dan doet
Lenis alleen de snap. Dat staat zo in het commentaar bij de instellingen,
zodat de volgende sessie niet hoeft te raden waar de knop zit.

Gevendored in src/assets/js/vendor (Lenis 1.3.26, MIT, 43KB samen), want de
CSP staat geen CDN toe. Dynamisch geimporteerd, dus mobiel haalt het niet
op. VENDOR_V ophogen als die bestanden wijzigen. De CSP hoefde niet aan:
strict-dynamic staat een import vanuit een vertrouwde module toe.

TWEE KLEINE DINGEN uit dezelfde ronde:

  • De terug-naar-boven-knop wijkt voor de mini-speler. Die kwam er anders bovenop te liggen (schermafbeelding). body.has-audio-player bestond al en wordt door audio-player.js gezet, dus dit volgt vanzelf.
  • Vastgepind is nu zichtbaar in de leestitel, met hetzelfde pin-icoon als in de tijdlijn. In de leesstroom staat een gepind bericht bovenaan zonder dat je ziet waarom. Nagekeken met een echte pin op dev.

style.css naar v82, MOD_V naar 19.

Suite 1169/1169.

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 5.8 KB
Line 
1<%
2// Eén bericht in de leesstroom.
3//
4// Dit is het stuk dat de client AANVULT: bij de onderrand komt de oudere buur
5// eronder, bij de bovenrand de nieuwere erboven. Geen sprongen, geen
6// scrollpositie die stiekem verzet wordt -- de stroom groeit gewoon in de
7// richting waarin je leest, en de browser snapt naar de grenzen.
8//
9// Elk artikel draagt zijn eigen buren, dus de client hoeft niets te onthouden:
10// wat er nog te halen valt staat op het stuk dat er al is.
11var _b = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
12var _newer = (typeof newerPost !== 'undefined' && newerPost) ? newerPost : null;
13var _older = (typeof olderPost !== 'undefined' && olderPost) ? olderPost : null;
14%>
15<article class="read-post"
16 data-slug="<%= post.slug %>"
17 data-newer="<%= _newer ? _newer.slug : '' %>"
18 data-older="<%= _older ? _older.slug : '' %>"
19 data-base="<%= _b %>"
20 data-title="<%= post.title || '' %>"
21 aria-label="<%= post.title || '' %>">
22 <%# Het SNAPPUNT, en met opzet een leeg element van nul hoog in plaats van het
23 artikel zelf. Een snapgebied dat GROTER is dan het scherm mag van de spec
24 overal blijven staan waar het het scherm nog vult -- dus bij een bericht
25 van 1009px op een scherm van 812 accepteert de browser elke positie tussen
26 de bovenkant en "onderkant op de onderrand". Die tweede stand zet de
27 bovenkant van het VOLGENDE bericht op de onderrand van het scherm, en dat
28 is wat Robin zag (20-8). Een anker van nul hoog heeft maar een geldige
29 positie: zijn bovenkant op de bovenrand. %>
30 <span class="read-anker" aria-hidden="true"></span>
31 <%# De titel is een echte link naar het bericht zelf. De leesstroom toont de
32 TEKST, maar reacties, waarderingen en boosts staan op de berichtpagina --
33 en een stroom waar je niet uit kunt naar het gesprek is een doodlopende weg.
34 Een <a> en niet alleen een tik-afhandelaar: dat werkt ook met een
35 toetsenbord, met een schermlezer, en met cmd-klik. %>
36 <%# De cover hoort hier net zo goed als op de berichtpagina: het is het beeld
37 van het stuk, en zonder hem begint elk bericht in de stroom met kale tekst.
38 Boven de titel, in dezelfde volgorde als post.ejs.
39
40 Twee dingen komen hier van post-card en NIET van post.ejs:
41
42 - De SLUIER. Op de berichtpagina hangt de waarschuwing als banner boven de
43 hele pagina, want daar staat een bericht. In een stroom kan dat niet: de
44 buren rollen gewoon voorbij, dus het beeld moet zijn eigen sluier dragen
45 of het is onderweg al te zien. De afhandelaar zit gedelegeerd op
46 document (shell.ejs), dus hij werkt ook op wat de client later aanschuift.
47 - thumb(). De bron kan het volle bestand zijn en hier staan er meerdere
48 onder elkaar in een stroom die dooraanvult.
49
50 cover_image_url en cover_video_url komen mee: beide voedingen van
51 readerItems() halen `SELECT p.*` op (routes/posts.js, de pinned- en de
52 gewone feed-query). Nagekeken, want een versmalde lijst zou hier niets
53 opleveren zonder ergens te klagen. %>
54 <% if (post.cover_image_url || post.cover_video_url) { %>
55 <figure class="read-cover<%= post.nsfw ? ' nsfw-media' : '' %>">
56 <% if (post.cover_image_url) { %>
57 <img src="<%= thumb(post.cover_image_url, 1280) %>"
58 srcset="<%= thumb(post.cover_image_url, 640) %> 640w, <%= thumb(post.cover_image_url, 1280) %> 1280w"
59 sizes="(min-width: 768px) 46rem, 100vw"
60 alt="<%= post.cover_alt || '' %>" loading="lazy" decoding="async"<% if (post.cover_video_url) { %> data-ios-mp4="<%= post.cover_video_url %>"<% } %>>
61 <% } else { %>
62 <video src="<%= post.cover_video_url %>" poster="<%= thumb(post.cover_video_url, 1280) %>"
63 controls loop muted playsinline preload="metadata"></video>
64 <% } %>
65 <% if (post.nsfw) { %><span class="nsfw-veil"><%- include('nsfw-veil', { cw: post.content_warning }) %></span><% } %>
66 </figure>
67 <% } %>
68
69 <header class="read-head">
70 <%# Vastgepind hoort zichtbaar te zijn in de titel: in de leesstroom staat een
71 gepind bericht bovenaan zonder dat je ziet WAAROM het daar staat. Zelfde
72 icoon als in de tijdlijn (post-card.ejs), zodat het hetzelfde ding is. %>
73 <h1 class="read-title">
74 <% if (post.pinned > 0) { %><span class="read-pin" title="<%= t('read.pinned') %>" aria-label="<%= t('read.pinned') %>"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="17" x2="12" y2="22"/><path d="M5 17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4h1v4.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24z"/></svg></span><% } %><a href="<%= _b %>/<%= post.slug %>"><%= post.title || '' %></a>
75 </h1>
76 <% if (post.published_at) { %><p class="read-when"><%= formatDateTime(post.published_at) %></p><% } %>
77 </header>
78
79 <%- include('post-body', {
80 post: post, access: entry.access, teaser: entry.teaser,
81 content_html: entry.content_html, _base: _b,
82 }) %>
83
84 <%# Zegt waar je heen gaat, in plaats van te vertrouwen op een tik die niemand
85 ziet. De tik-afhandelaar in mod/read.js is het gemak; dit is de aankondiging.
86
87 #fediverse is de sectie op de berichtpagina met de ⭐/🔁/💬-tellers en de
88 reacties (post.ejs). Alleen DEZE link springt daarheen: de titel en de tik
89 openen het bericht bovenaan, want die zeggen "lees dit", niet "laat het
90 gesprek zien". Staat de sectie er niet -- AP uit, of een concept -- dan
91 negeert de browser de anker en beland je gewoon bovenaan. %>
92 <footer class="read-foot">
93 <a class="read-open" href="<%= _b %>/<%= post.slug %>#fediverse"><%= t('read.open') %> &rarr;</a>
94 </footer>
95</article>
Note: See TracBrowser for help on using the repository browser.