返回 DeepSeek-Reasonix
ModelSettingHelp.tsx
根目录 / desktop / frontend / src / components / ModelSettingHelp.tsx
1 import { useEffect, useId, useRef, useState } from "react";
2 import { Info } from "lucide-react";
3 import { AnchoredPopover } from "./AnchoredPopover";
4 import { useProviderT } from "../lib/providerSettingsLocale";
5
6 export function ModelSettingHelp({ label, text }: { label: string; text: string }) {
7 const t = useProviderT();
8 const id = useId();
9 const anchor = useRef<HTMLButtonElement>(null);
10 const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
11 const pinned = useRef(false);
12 const [open, setOpen] = useState(false);
13 const clear = () => {
14 if (timer.current !== null) clearTimeout(timer.current);
15 timer.current = null;
16 };
17 const show = () => { clear(); setOpen(true); };
18 const close = () => { clear(); pinned.current = false; setOpen(false); };
19 const leave = () => {
20 clear();
21 if (!pinned.current) timer.current = setTimeout(() => setOpen(false), 150);
22 };
23 useEffect(() => () => { if (timer.current !== null) clearTimeout(timer.current); }, []);
24 return <span className="model-setting-label">
25 <span>{label}</span>
26 <button ref={anchor} type="button" className="model-setting-help"
27 aria-label={t("providerUI.modelHelpLabel", { name: label })}
28 aria-expanded={open} aria-controls={open ? id : undefined} aria-describedby={open ? id : undefined}
29 onMouseEnter={show} onMouseLeave={leave} onFocus={show} onBlur={leave}
30 onClick={() => { if (pinned.current) close(); else { pinned.current = true; show(); } }}>
31 <Info size={14} aria-hidden="true" />
32 </button>
33 <AnchoredPopover open={open} anchorRef={anchor} onClose={close} className="model-setting-help-popover" placement="bottom">
34 <div id={id} role="tooltip" onMouseEnter={show} onMouseLeave={leave}>
35 <strong>{label}</strong>
36 {text.split("\n\n").map((paragraph, index) => <p key={index}>{paragraph}</p>)}
37 </div>
38 </AnchoredPopover>
39 </span>;
40 }
41
41 lines Plain Text