diff options
| author | Adam Soltys <[email protected]> | 2026-10-13 05:19:47 +0000 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-13 05:19:47 +0000 |
| commit | 6488a0a687144e217f71ab1c7a768613b0f17e58 (patch) | |
| tree | 3bff8ea8f4f350bb1bfa4793ac1fc94ef95cca5c /src/style.css | |
| parent | 6fdca50f17b1e814bbf6ba1fc1ffcb18001c54fd (diff) | |
| download | coinosv3-6488a0a687144e217f71ab1c7a768613b0f17e58.tar.gz coinosv3-6488a0a687144e217f71ab1c7a768613b0f17e58.zip | |
Media pager: past the last slide, a "fetching the next video" screen — and the next one, when it comes, is moved onto. Adam reached the last clip before the next was in, and a swipe only nudged the clip and sprang back. Now the pager ends in a screen of its own: a ring sweeping round, three sparks orbiting the other way, the play mark (a picture mark in a pictures pager) breathing in the middle, and "Fetching the next video…" (or "Fetching more pictures…") with a sheen running through it, all still under prefers-reduced-motion. Landing there stops the clip left behind and asks for more at once (the feed pages on; the media grid's pager crawls); slides that arrive go in above it, and one arriving while the reader waits is moved onto and plays. With nothing older to be had (the feed at its end, or the media index), it says "That's everything for now" and goes still. The scroller no longer anchors (overflow-anchor: none), so a slide put in above the screen doesn't hold the screen in view. Strings in all 20 languages. tools/pager-tail-test.js (relays that take 3 s for anything older: the screen at the end, the clip behind stopped, the next clip moved onto and playing, the end saying that's everything, Escape onto the last clip's post); feed-pager-ahead and feed-media-views count slides without it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
Diffstat (limited to 'src/style.css')
| -rw-r--r-- | src/style.css | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/style.css b/src/style.css index 448f702..e66d756 100644 --- a/src/style.css +++ b/src/style.css @@ -1472,6 +1472,8 @@ body::after { .mp-scroll { position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain; scroll-snap-type: y mandatory; scrollbar-width: none; + /* slides go in above the loading one at the end: no anchoring to hold it in view */ + overflow-anchor: none; } .mp-scroll::-webkit-scrollbar { display: none; } .mp-slide { @@ -1528,6 +1530,58 @@ body::after { .media-pager.quiet .mp-top .mp-x { opacity: 0; pointer-events: none; } .media-pager.quiet .mp-top .mp-sound { pointer-events: auto; } .media-pager.quiet.show .mp-top .mp-x { opacity: 1; pointer-events: auto; } +/* the end of the pager, while more is fetched: a ring sweeping round, three + sparks orbiting the other way, the play mark breathing in the middle, the + words with a sheen running through them. Caught up, it all goes still. */ +.mp-tail { + position: relative; height: 100vh; height: 100dvh; width: 100%; box-sizing: border-box; + scroll-snap-align: start; scroll-snap-stop: always; overflow: hidden; + display: flex; align-items: center; justify-content: center; + flex-direction: column; gap: 26px; text-align: center; padding: 0 32px; + background: radial-gradient(circle at 50% 46%, rgba(247, 147, 26, .16), rgba(124, 92, 255, .06) 38%, transparent 62%); +} +.mp-loader { position: relative; width: 116px; height: 116px; display: block; } +.mp-loader::before { + content: ''; position: absolute; inset: 0; border-radius: 50%; + background: conic-gradient(from 0deg, transparent 0 50%, rgba(247, 147, 26, .2) 58%, #f7931a 76%, #ff4d6d 88%, #a78bfa 100%); + -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px)); + mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px)); + animation: mp-spin 1.15s linear infinite; +} +.mp-orbit { position: absolute; inset: -14px; display: block; animation: mp-spin 3.2s linear infinite reverse; } +.mp-orbit i { + position: absolute; top: 50%; left: 50%; width: 8px; height: 8px; margin: -4px; border-radius: 50%; + animation: mp-spark 1.6s ease-in-out infinite; +} +.mp-orbit i:nth-child(1) { transform: rotate(0deg) translateX(72px); background: #f7931a; box-shadow: 0 0 12px 2px rgba(247, 147, 26, .8); } +.mp-orbit i:nth-child(2) { transform: rotate(120deg) translateX(72px); background: #ff4d6d; box-shadow: 0 0 12px 2px rgba(255, 77, 109, .8); animation-delay: -.53s; } +.mp-orbit i:nth-child(3) { transform: rotate(240deg) translateX(72px); background: #a78bfa; box-shadow: 0 0 12px 2px rgba(167, 139, 250, .8); animation-delay: -1.06s; } +.mp-core { + position: absolute; inset: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; + color: #fff; background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, .22), rgba(255, 255, 255, .06)); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12); + animation: mp-breathe 1.5s ease-in-out infinite; +} +.mp-core svg { margin-left: 3px; } +.mp-tail-text { + font-size: 16px; font-weight: 500; letter-spacing: .01em; color: rgba(255, 255, 255, .7); + background: linear-gradient(100deg, rgba(255, 255, 255, .55) 30%, #fff 50%, rgba(255, 255, 255, .55) 70%); + background-size: 250% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; + animation: mp-sheen 2s linear infinite; +} +@keyframes mp-spin { to { transform: rotate(360deg); } } +@keyframes mp-breathe { 0%, 100% { transform: scale(.9); opacity: .7; } 50% { transform: scale(1); opacity: 1; } } +@keyframes mp-spark { 0%, 100% { opacity: .35; } 50% { opacity: 1; } } +@keyframes mp-sheen { from { background-position: 125% 0; } to { background-position: -125% 0; } } +.mp-tail.done { background: none; } +.mp-tail.done .mp-loader::before, .mp-tail.done .mp-orbit, .mp-tail.done .mp-orbit i, .mp-tail.done .mp-core, .mp-tail.done .mp-tail-text { animation: none; } +.mp-tail.done .mp-loader { opacity: .3; } +.mp-tail.done .mp-tail-text { background: none; -webkit-text-fill-color: currentColor; color: rgba(255, 255, 255, .8); } +@media (prefers-reduced-motion: reduce) { + .mp-loader::before, .mp-orbit, .mp-orbit i, .mp-core, .mp-tail-text { animation: none; } + .mp-tail-text { background: none; -webkit-text-fill-color: currentColor; } +} + /* a clip's seek bar: a thin line along the bottom, thicker with the details up or under a finger; the strip above it is the finger's (no swipe there). Lifted clear of the phone's own gesture strip along the bottom edge (which |
