import type { SearchSiteMode, Site } from "@umt/contracts"; import { PackageSearch } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { Link } from "react-router"; import { useSiteOptions } from "~/api/instances.ts"; import { useSettings } from "~/api/settings.ts"; import { consolePath } from "~/components/console/nav.ts"; import { ChipToggleGroup } from "~/components/library/parts.tsx"; import { Button } from "~/components/ui/button.tsx"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "~/components/ui/dialog.tsx"; import { cn } from "~/lib/utils.ts"; // 搜资源前选站点:默认(站点页勾了「默认参与搜索」的)/ 全部启用站点 / 指定站点。 // 初始值 = 本机上次的选择,没有就用 settings.search.defaultSiteMode。 export type SitePick = { mode: SearchSiteMode; siteIds: string[] }; const STORE_KEY = "umt.search.sitePick"; export function loadSitePick(): SitePick | null { try { const raw = globalThis.localStorage?.getItem(STORE_KEY); if (!raw) return null; const v = JSON.parse(raw) as Partial; if (v.mode !== "default" && v.mode !== "all" && v.mode !== "custom") return null; return { mode: v.mode, siteIds: Array.isArray(v.siteIds) ? v.siteIds.filter((x) => typeof x === "string") : [] }; } catch { return null; } } function saveSitePick(p: SitePick) { try { globalThis.localStorage?.setItem(STORE_KEY, JSON.stringify(p)); } catch { // 隐私模式等存不了:只是下次不记得 } } /** 按模式解析出站点 ID(只含启用站点) */ export function resolvePick(pick: SitePick, sites: Pick[]): string[] { const on = sites.filter((s) => s.enabled); if (pick.mode === "all") return on.map((s) => s.id); if (pick.mode === "custom") { const set = new Set(pick.siteIds); return on.filter((s) => set.has(s.id)).map((s) => s.id); } return on.filter((s) => s.searchDefault !== false).map((s) => s.id); } const MODES: { value: SearchSiteMode; label: string }[] = [ { value: "default", label: "默认站点" }, { value: "all", label: "全部站点" }, { value: "custom", label: "指定站点" }, ]; export function SitePickerDialog({ open, onOpenChange, title, onConfirm, }: { open: boolean; onOpenChange: (o: boolean) => void; /** 作品名,显示在说明里 */ title: string; onConfirm: (siteIds: string[]) => void; }) { const sitesQ = useSiteOptions(); const settings = useSettings(); const sites = useMemo( () => (sitesQ.data?.items ?? []).filter((s) => s.enabled && s.capabilities.includes("search")), [sitesQ.data], ); const [pick, setPick] = useState(null); // 打开时取初始值:本机上次 > 全局设置 > 默认 useEffect(() => { if (!open) return; const cfg = settings.data?.search; setPick( loadSitePick() ?? (cfg ? { mode: cfg.defaultSiteMode, siteIds: cfg.siteIds } : { mode: "default", siteIds: [] }), ); }, [open, settings.data]); const cur = pick ?? { mode: "default" as const, siteIds: [] }; const ids = resolvePick(cur, sites); const count = (m: SearchSiteMode) => resolvePick({ mode: m, siteIds: cur.siteIds }, sites).length; const confirm = () => { saveSitePick(cur); onConfirm(ids); onOpenChange(false); }; return ( 搜索资源 在所选站点搜「{title}」。每个站点按作品原名和译名各查一次。
{MODES.map((m) => ( ))}
{sitesQ.isPending ? (

加载站点…

) : sites.length === 0 ? (

还没有启用的站点。 去站点页

) : cur.mode === "custom" ? ( ({ value: s.id, label: s.name }))} value={cur.siteIds.filter((id) => sites.some((s) => s.id === id))} onChange={(v) => setPick({ mode: "custom", siteIds: v })} /> ) : (

{ids.length ? sites .filter((s) => ids.includes(s.id)) .map((s) => s.name) .join("、") : "没有站点勾选「默认参与搜索」。在站点页打开,或改选全部站点。"}

)}
); }