more fluent texts
This commit is contained in:
+45
-14
@@ -1,24 +1,55 @@
|
||||
import { tick } from 'svelte';
|
||||
|
||||
const prefersReducedMotion = () =>
|
||||
typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
/**
|
||||
* Fades a block back in whenever the value passed to it changes - used to make
|
||||
* a day switch visible in the hourly table, the written forecast and the
|
||||
* meteograms.
|
||||
* Runs a day change inside a view transition, so the outgoing day is still on
|
||||
* screen while the incoming one fades in - a real cross-fade rather than the
|
||||
* old content vanishing and the new one fading up from nothing.
|
||||
*
|
||||
* It animates the existing node instead of remounting it: the meteograms hold
|
||||
* canvas charts with their own zoom state, and rebuilding those on every day
|
||||
* change would be both expensive and lossy.
|
||||
* Only the regions that actually change carry a `view-transition-name` (see
|
||||
* `.day-region-*` in routes/layout.css); everything else - the strip, the
|
||||
* header, the page chrome - is pinned by the `day-switch` class so it stays
|
||||
* completely still.
|
||||
*/
|
||||
export async function runDayTransition(update: () => void): Promise<void> {
|
||||
if (prefersReducedMotion() || !document.startViewTransition) {
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
const root = document.documentElement;
|
||||
root.classList.add('day-switch');
|
||||
try {
|
||||
// Svelte applies the change on the next tick; the transition has to wait
|
||||
// for that before it snapshots the new state.
|
||||
await document.startViewTransition(async () => {
|
||||
update();
|
||||
await tick();
|
||||
}).finished;
|
||||
} catch {
|
||||
/* a superseded transition is fine - the DOM is already up to date */
|
||||
} finally {
|
||||
root.classList.remove('day-switch');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback for browsers without view transitions: fade the block back in when
|
||||
* the value passed to it changes. Animates the existing node rather than
|
||||
* remounting it, so the canvas charts keep their zoom state.
|
||||
*/
|
||||
export function daySwap(node: HTMLElement, key: unknown) {
|
||||
let current = key;
|
||||
|
||||
const play = () => {
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||
node.animate(
|
||||
[
|
||||
{ opacity: 0.15, transform: 'translateY(4px)' },
|
||||
{ opacity: 1, transform: 'translateY(0)' }
|
||||
],
|
||||
{ duration: 280, easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)' }
|
||||
);
|
||||
// view transitions handle it properly where they exist
|
||||
if (typeof document.startViewTransition === 'function' || prefersReducedMotion()) return;
|
||||
node.animate([{ opacity: 0.1 }, { opacity: 1 }], {
|
||||
duration: 460,
|
||||
easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)'
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user