Transitions

This commit is contained in:
binwiederhier
2026-06-24 17:08:32 -04:00
parent 2b1f2d6b9a
commit 047a1258f1
8 changed files with 42 additions and 188 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ export const isImage = (attachment) => {
};
export const icon = "/static/images/ntfy.png";
export const badge = "/static/images/mask-icon.svg";
export const badge = "/static/images/ntfy-mask.svg";
/**
* Computes a unique notification tag scoped by baseUrl, topic, and sequence ID.
+1 -1
View File
@@ -35,7 +35,7 @@ const fadeOutAndRemove = () => {
// Phase 2: once the logo is gone, lift the background to fade the app in, then remove the node.
setTimeout(() => {
splash.classList.add("ntfy-splash-hidden");
splash.classList.add("splash-hidden");
const remove = () => splash.remove();
// Only react to the background's own opacity transition -- the logo's transitionend bubbles up
// here too, and would otherwise remove the splash before the app has finished fading in.
+18 -6
View File
@@ -14,20 +14,32 @@ const fadeOutRoot = () => {
return node;
};
// Fade #root back in, then remove the inline styles we added so nothing is left behind on the
// element -- otherwise the lingering `transition` would silently animate any future opacity change
// to #root. Uses setTimeout (not requestAnimationFrame) so a backgrounded tab can't strand #root
// at opacity 0; rAF can be paused entirely in background tabs, while timers still fire.
const fadeInRoot = () => {
const node = document.getElementById("root");
if (!node) {
return;
}
node.style.opacity = "1";
setTimeout(() => {
node.style.transition = "";
node.style.opacity = "";
}, FADE_MS);
};
// Fade the app out, run a client-side navigation, then fade the new page back in. Used for
// app -> login/signup, which stay within the same document (no reload).
export const fadeNavigate = (navigate, to) => {
const node = fadeOutRoot();
if (!node) {
if (!fadeOutRoot()) {
navigate(to);
return;
}
setTimeout(() => {
navigate(to);
// Fade back in on the next frame, once the new page has rendered.
requestAnimationFrame(() => {
node.style.opacity = "1";
});
fadeInRoot();
}, FADE_MS);
};
+1 -1
View File
@@ -54,7 +54,7 @@ const App = () => {
if (themePreference === undefined) {
return;
}
document.documentElement.classList.toggle("ntfy-dark", isDark);
document.documentElement.classList.toggle("dark", isDark);
}, [isDark, themePreference]);
// Safety net: never let the splash trap the UI if no route hides it (e.g. an unmatched path).