From 29e89f2525eadae5874fc0ef1958278953b0b7f3 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:31:54 +0800 Subject: [PATCH] fix(app): Give the Settings window a plain loader and make the splash bar progress The Settings window loads the same page as project windows, so it showed the launch splash with the logo. It now shows only the bar, after 400 ms. The bar's sliding animation was switched off under reduced motion, leaving a static 40% fill. It is now a fake progress that eases towards ~90% and fills to 100% before the splash fades out. Claude-Session: https://claude.ai/code/session_01B65qLEKnkeYTGdbwhLpjCu --- index.html | 2 +- public/boot.js | 6 +++++- public/splash.css | 16 ++++++++++------ src/platform/splash.ts | 22 ++++++++++++++++++++-- 4 files changed, 36 insertions(+), 10 deletions(-) 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, + ); }), ), );