diff options
Diffstat (limited to 'docs/site')
| -rw-r--r-- | docs/site/casts/casts.toml | 2 | ||||
| -rw-r--r-- | docs/site/site.typ | 28 |
2 files changed, 24 insertions, 6 deletions
diff --git a/docs/site/casts/casts.toml b/docs/site/casts/casts.toml index 67553089..5771e6be 100644 --- a/docs/site/casts/casts.toml +++ b/docs/site/casts/casts.toml @@ -1,5 +1,5 @@ # The landing page's terminal recordings (asciicast v2), in the order -# shown: casts/<name>.cast for each. The first plays by itself; all loop +# shown: casts/<name>.cast for each. Each plays by itself while on screen; all loop # and fit the page's width. While `ready` is false the cast shows # placeholder.svg, so the site builds before a recording exists. # test/record_casts.py writes the casts and this file. diff --git a/docs/site/site.typ b/docs/site/site.typ index b308853d..e0cd9d4d 100644 --- a/docs/site/site.typ +++ b/docs/site/site.typ @@ -128,15 +128,17 @@ #doc-links.update(true) -#let video(c) = el("video", (poster: "media/" + c.name + ".png", muted: "", loop: "", playsinline: "", - controls: "", preload: "none"))[ +// Every recording plays by itself; the script below plays each only while +// it is on screen. Without the script, `autoplay` still plays them. +#let video(c) = el("video", (poster: "media/" + c.name + ".png", autoplay: "", muted: "", loop: "", playsinline: "", + controls: ""))[ #el("source", (src: "media/" + c.name + ".webm", type: "video/webm"))[] #el("source", (src: "media/" + c.name + ".mp4", type: "video/mp4"))[] ] #let placeholder = el("img", (src: "media/placeholder.svg", alt: "", width: "640", height: "400"))[] /// A terminal recording: a box the player fills, its data inline (so it -/// plays from file://), its caption under it. The first ready one plays. +/// plays from file://), its caption under it. #let ready-casts = casts.filter(c => c.ready) #let cast(c, i) = el("figure", (class: if i == 0 { "clip cast first" } else { "clip cast" }))[ #if c.ready { el("div", (class: "player", id: "cast-" + c.name, "aria-label": c.title))[] } else { placeholder } @@ -145,14 +147,29 @@ #let player-script = { let list = ready-casts.enumerate().map(((i, c)) => ( id: "cast-" + c.name, data: read("casts/" + c.name + ".cast"), - cols: c.cols, rows: c.rows, autoPlay: i == 0, + cols: c.cols, rows: c.rows, )) // "</" may not appear inside a script element let data = json.encode(list, pretty: false).replace("</", "<\\/") el("script", (src: "player/asciinema-player.min.js"))[] - el("script")[#("for (const c of " + data + ") AsciinemaPlayer.create({data: c.data}, document.getElementById(c.id), {cols: c.cols, rows: c.rows, autoPlay: c.autoPlay, loop: true, fit: 'width'});")] + el("script")[#("for (const c of " + data + ") { const el = document.getElementById(c.id); el.player = AsciinemaPlayer.create({data: c.data}, el, {cols: c.cols, rows: c.rows, autoPlay: true, loop: true, fit: 'width'}); }")] } +/// Plays a recording while it is on screen and pauses it once it leaves. +#let in-view-script = el("script")[#( + "(() => { if (!('IntersectionObserver' in window)) return; +" + + " const p = el => el.player || (el.tagName === 'VIDEO' ? el : null); +" + + " const io = new IntersectionObserver(es => { for (const e of es) { const r = p(e.target); if (!r) continue; +" + + " if (e.isIntersecting) Promise.resolve(r.play()).catch(() => {}); else r.pause(); } }, {threshold: 0.25}); +" + + " for (const el of document.querySelectorAll('.clip video, .cast .player')) io.observe(el); +" + + "})();" +)] + #document(href("index"), title: "pardes", shell("index", "pardes")[ #el("h1", (class: "masthead"))[pardes] #el("p", (class: "lead"))[#landing.lead] @@ -185,6 +202,7 @@ el("link", (rel: "stylesheet", href: "player/asciinema-player.css"))[] player-script } + #in-view-script ]) #for p in pages.slice(1, -1) { |
