返回 DeepSeek-Reasonix
StartupSplash.tsx
根目录 / desktop / frontend / src / components / StartupSplash.tsx
1 import { useEffect, useRef, useState } from "react";
2 import logoSymbol from "../assets/logo-symbol.svg";
3 import { useT } from "../lib/i18n";
4 import { markSplashShown } from "../lib/startupSplashState";
5
6 const MIN_VISIBLE_MS = 1400;
7 const FADE_OUT_MS = 420;
8 const MAX_HOLD_MS = 6000;
9
10 export function StartupSplash({ hold, onDone }: { hold: boolean; onDone: () => void }) {
11 const t = useT();
12 const [minElapsed, setMinElapsed] = useState(false);
13 const [forceRelease, setForceRelease] = useState(false);
14 const [leaving, setLeaving] = useState(false);
15 const finishedRef = useRef(false);
16 const onDoneRef = useRef(onDone);
17 onDoneRef.current = onDone;
18
19 const finish = (skipHold = false) => {
20 if (finishedRef.current) return;
21 if (!skipHold && (!minElapsed || hold) && !forceRelease) return;
22 finishedRef.current = true;
23 setLeaving(true);
24 window.setTimeout(() => {
25 markSplashShown();
26 onDoneRef.current();
27 }, FADE_OUT_MS);
28 };
29
30 useEffect(() => {
31 const minTimer = window.setTimeout(() => setMinElapsed(true), MIN_VISIBLE_MS);
32 const maxTimer = window.setTimeout(() => setForceRelease(true), MAX_HOLD_MS);
33 return () => {
34 window.clearTimeout(minTimer);
35 window.clearTimeout(maxTimer);
36 };
37 }, []);
38
39 useEffect(() => {
40 finish();
41 }, [minElapsed, hold, forceRelease]);
42
43 useEffect(() => {
44 const skip = (event: KeyboardEvent) => {
45 if (event.key !== "Escape" && event.key !== "Enter" && event.key !== " ") return;
46 finish(true);
47 };
48 window.addEventListener("keydown", skip);
49 return () => window.removeEventListener("keydown", skip);
50 }, []);
51
52 return (
53 <div className="startup-splash" data-leaving={leaving} onClick={() => finish(true)}>
54 <div className="startup-splash__card">
55 <div className="startup-splash__mark" aria-hidden="true">
56 <img src={logoSymbol} alt="" draggable={false} />
57 </div>
58 <div className="startup-splash__name">Reasonix</div>
59 <div className="startup-splash__sub">{t("app.splashSubtitle")}</div>
60 <div className="startup-splash__dots" aria-hidden="true">
61 <span />
62 <span />
63 <span />
64 </div>
65 </div>
66 </div>
67 );
68 }
69
69 lines Plain Text