diff --git a/index.html b/index.html index 93777f8a2..4ccd1bda5 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,7 @@ OpenIDEA -
+
diff --git a/public/boot.js b/public/boot.js index acb74b89a..60076f180 100644 --- a/public/boot.js +++ b/public/boot.js @@ -1,4 +1,4 @@ -/* global document, localStorage */ +/* global document, localStorage, window */ // Runs before the app's CSS loads: restores the last theme (theme.ts stores it) // so a new window starts in it instead of flashing the light default. // An external file because the CSP forbids inline scripts. @@ -9,3 +9,7 @@ try { } catch { /* storage unavailable */ } +// Settings windows (`settings-`) load this page too: splash.css drops the logo for them. +if (window.__TAURI_INTERNALS__?.metadata?.currentWindow?.label?.startsWith("settings-")) { + document.documentElement.dataset.window = "settings"; +} diff --git a/public/splash.css b/public/splash.css index 721d23c04..0a8e561e7 100644 --- a/public/splash.css +++ b/public/splash.css @@ -29,16 +29,20 @@ body, .splash { background: #e9eaee; } :root[data-theme^="dark"] .splash { color: #8c8f95; } .splash svg { width: 56px; height: 56px; } .splash-bar { width: 120px; height: 2px; border-radius: 1px; overflow: hidden; background: rgb(127 127 127 / 0.18); } -.splash-bar::after { - content: ""; +/* Fake progress: eases towards ~90% over the 4 s cap; hideSplash() fills it before fading out. */ +.splash-bar > i { display: block; - width: 40%; height: 100%; background: #3871e1; - animation: splash-bar 1.1s ease-in-out infinite; + transform-origin: left; + animation: splash-fill 4s cubic-bezier(0.1, 0.7, 0.3, 1) both; } +/* Settings window: a dialog, not a launch. Only the bar, and only if loading takes a while. */ +:root[data-window="settings"] .splash { animation-delay: 400ms; } +:root[data-window="settings"] .splash > :not(.splash-bar) { display: none; } @keyframes splash-in { from { opacity: 0; } } -@keyframes splash-bar { from { transform: translateX(-100%); } to { transform: translateX(250%); } } +@keyframes splash-fill { from { transform: scaleX(0.04); } to { transform: scaleX(0.92); } } +/* The fill stays: it grows in place, which reduced motion allows. */ @media (prefers-reduced-motion: reduce) { - .splash, .splash-bar::after { animation: none; } + .splash { animation: none; } } diff --git a/src/platform/splash.ts b/src/platform/splash.ts index d879d1599..6a5b50fbe 100644 --- a/src/platform/splash.ts +++ b/src/platform/splash.ts @@ -6,6 +6,19 @@ const holds: Promise[] = []; /** Never keep the splash longer than this; a slow open shows its own progress. */ const MAX_WAIT_MS = 4000; +const FILL_MS = 120; + +/** Runs the fake progress bar to 100% from wherever its animation has got to; false if nothing shows yet. */ +function completeBar(el: HTMLElement): boolean { + const fill = el.querySelector(".splash-bar > i"); + if (!fill || getComputedStyle(el).opacity === "0") return false; + fill.style.transform = getComputedStyle(fill).transform; + fill.style.animation = "none"; + void fill.offsetWidth; + fill.style.transition = `transform ${FILL_MS}ms ease-out`; + fill.style.transform = "scaleX(1)"; + return true; +} /** Keeps the splash up until `work` settles. Call before `hideSplash()`. */ export function holdSplash(work: Promise): void { @@ -21,8 +34,13 @@ export function hideSplash(): void { // Two frames: let React commit the state the holds produced before uncovering it. requestAnimationFrame(() => requestAnimationFrame(() => { - el.classList.add("splash-out"); - setTimeout(() => el.remove(), 200); + setTimeout( + () => { + el.classList.add("splash-out"); + setTimeout(() => el.remove(), 200); + }, + completeBar(el) ? FILL_MS : 0, + ); }), ), );