PageSourceSearch

https://www.hamienet.com/assets/SearchSettings-BSlJndKx.js

js hamienet.com collected 2026-09-24 19:00:47 UTC 11,897 bytes, 210 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-D0Bmh-UX.js";
3import { D as DevDebugInfo } from "./AdminShared-P_hor2hS.js";
4import { bf as Search, cL as RefreshCw, cc as Save, df as SlidersVertical, bH as Hash, cT as Type, ce as Plus, aW as X } from "./vendor-dVNaLJx_.js";
5import "./vendor-i18n-R-bMoYp_.js";
6const DEFAULT_CONFIG = {
7  provider: "database",
8  weights: { title: 2, artist: 1.5, tags: 1, description: 0.5 },
9  boostedTerms: [],
10  ignoredTerms: [],
11  synonyms: {}
12};
13const SearchSettings = ({ activeRole }) => {
14  const [config, setConfig] = reactExports.useState(DEFAULT_CONFIG);
15  const [loading, setLoading] = reactExports.useState(true);
16  const [saving, setSaving] = reactExports.useState(false);
17  const [newSynonym, setNewSynonym] = reactExports.useState({ key: "", value: "" });
18  reactExports.useEffect(() => {
19    loadConfig();
20  }, []);
21  const loadConfig = async () => {
22    setLoading(true);
23    const saved = await api.getSystemSetting("search_config");
24    if (saved && saved.value) {
25      setConfig({ ...DEFAULT_CONFIG, ...saved.value });
26    }
27    setLoading(false);
28  };
29  const handleSave = async () => {
30    setSaving(true);
31    try {
32      await api.saveSystemSetting("search_config", config);
33      alert("Search configuration saved.");
34    } catch (e) {
35      alert("Failed to save configuration.");
36    } finally {
37      setSaving(false);
38    }
39  };
40  const handleWeightChange = (field, value) => {
41    setConfig((prev) => ({
42      ...prev,
43      weights: { ...prev.weights, [field]: value }
44    }));
45  };
46  const handleArrayChange = (field, value) => {
47    setConfig((prev) => ({
48      ...prev,
49      [field]: value.split(",").map((s) => s.trim()).filter(Boolean)
50    }));
51  };
52  const addSynonym = () => {
53    if (newSynonym.key && newSynonym.value) {
54      setConfig((prev) => ({
55        ...prev,
56        synonyms: { ...prev.synonyms, [newSynonym.key]: newSynonym.value }
57      }));
58      setNewSynonym({ key: "", value: "" });
59    }
60  };
61  const removeSynonym = (key) => {
62    const next = { ...config.synonyms };
63    delete next[key];
64    setConfig((prev) => ({ ...prev, synonyms: next }));
65  };
66  if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-10 text-center text-zinc-500", children: "Loading Configuration..." });
67  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-4xl mx-auto animate-in fade-in", children: [
68    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
69      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-6 pb-6 border-b border-zinc-100 dark:border-zinc-800", children: [
70        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
71          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-indigo-50 dark:bg-indigo-900/20 rounded-xl flex items-center justify-center text-indigo-600 dark:text-indigo-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { size: 24 }) }),
72          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
73            /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Search Intelligence" }),
74            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Configure search ranking, weights, and synonyms." })
75          ] })
76        ] }),
77        /* @__PURE__ */ jsxRuntimeExports.jsxs(
78          "button",
79          {
80            onClick: handleSave,
81            disabled: saving,
82            className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold text-sm flex items-center gap-2 shadow-lg shadow-indigo-500/20 disabled:opacity-50",
83            children: [
84              saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
85              "Save Changes"
86            ]
87          }
88        )
89      ] }),
90      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-8", children: [
91        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
92          /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-sm text-zinc-900 dark:text-white flex items-center gap-2", children: [
93            /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { size: 16, className: "text-indigo-500" }),
94            " Field Relevance Weights"
95          ] }),
96          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-zinc-50 dark:bg-zinc-800/50 p-4 rounded-xl border border-zinc-200 dark:border-zinc-800 space-y-4", children: Object.keys(config.weights).map((field) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
97            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-xs font-bold text-zinc-600 dark:text-zinc-400 mb-2 uppercase", children: [
98              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field }),
99              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-indigo-600 dark:text-indigo-400", children: [
100                config.weights[field],
101                "x"
102              ] })
103            ] }),
104            /* @__PURE__ */ jsxRuntimeExports.jsx(
105              "input",
106              {
107                type: "range",
108                min: "0",
109                max: "10",
110                step: "0.1",
111                value: config.weights[field],
112                onChange: (e) => handleWeightChange(field, parseFloat(e.target.value)),
113                className: "w-full accent-indigo-600 h-2 bg-zinc-200 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer"
114              }
115            )
116          ] }, field)) })
117        ] }),
118        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
119          /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-sm text-zinc-900 dark:text-white flex items-center gap-2", children: [
120            /* @__PURE__ */ jsxRuntimeExports.jsx(Hash, { size: 16, className: "text-emerald-500" }),
121            " Term Handling"
122          ] }),
123          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
124            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-2", children: "Boosted Terms (Higher Ranking)" }),
125            /* @__PURE__ */ jsxRuntimeExports.jsx(
126              "textarea",
127              {
128                value: config.boostedTerms.join(", "),
129                onChange: (e) => handleArrayChange("boostedTerms", e.target.value),
130                className: "w-full h-20 bg-white dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-lg p-3 text-sm focus:border-indigo-500 outline-none resize-none",
131                placeholder: "e.g. exclusive, featured, premium"
132              }
133            )
134          ] }),
135          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
136            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-2", children: "Ignored Terms (Stop Words)" }),
137            /* @__PURE__ */ jsxRuntimeExports.jsx(
138              "textarea",
139              {
140                value: config.ignoredTerms.join(", "),
141                onChange: (e) => handleArrayChange("ignoredTerms", e.target.value),
142                className: "w-full h-20 bg-white dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-lg p-3 text-sm focus:border-indigo-500 outline-none resize-none",
143                placeholder: "e.g. the, a, an, midi"
144              }
145            )
146          ] })
147        ] })
148      ] }),
149      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 pt-8 border-t border-zinc-100 dark:border-zinc-800", children: [
150        /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-sm text-zinc-900 dark:text-white flex items-center gap-2 mb-4", children: [
151          /* @__PURE__ */ jsxRuntimeExports.jsx(Type, { size: 16, className: "text-amber-500" }),
152          " Synonym Dictionary"
153        ] }),
154        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/50 p-4 rounded-xl border border-zinc-200 dark:border-zinc-800", children: [
155          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 mb-4", children: [
156            /* @__PURE__ */ jsxRuntimeExports.jsx(
157              "input",
158              {
159                value: newSynonym.key,
160                onChange: (e) => setNewSynonym({ ...newSynonym, key: e.target.value }),
161                placeholder: "Search Term (e.g. ff7)",
162                className: "flex-1 bg-white dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg px-3 py-2 text-sm outline-none focus:border-indigo-500"
163              }
164            ),
165            /* @__PURE__ */ jsxRuntimeExports.jsx(
166              "input",
167              {
168                value: newSynonym.value,
169                onChange: (e) => setNewSynonym({ ...newSynonym, value: e.target.value }),
170                placeholder: "Maps to (e.g. Final Fantasy VII)",
171                className: "flex-[2] bg-white dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg px-3 py-2 text-sm outline-none focus:border-indigo-500"
172              }
173            ),
174            /* @__PURE__ */ jsxRuntimeExports.jsx(
175              "button",
176              {
177                onClick: addSynonym,
178                disabled: !newSynonym.key || !newSynonym.value,
179                className: "px-4 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50",
180                children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 18 })
181              }
182            )
183          ] }),
184          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
185            Object.entries(config.synonyms).length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-center text-zinc-500 text-sm py-4", children: "No synonyms defined." }),
186            Object.entries(config.synonyms).map(([key, val]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg group", children: [
187              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
188                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-indigo-600 dark:text-indigo-400", children: key }),
189                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: "→" }),
190                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700 dark:text-zinc-300", children: val })
191              ] }),
192              /* @__PURE__ */ jsxRuntimeExports.jsx(
193                "button",
194                {
195                  onClick: () => removeSynonym(key),
196                  className: "text-zinc-400 hover:text-red-500 opacity-0 group-hover:opacity-100 transition-opacity",
197                  children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 16 })
198                }
199              )
200            ] }, key))
201          ] })
202        ] })
203      ] })
204    ] }),
205    /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "search_config", value: config, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin })
206  ] });
207};
208export {
209  SearchSettings as default
210};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.