dirk-cfx-react 1.1.56 → 1.1.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1299,6 +1299,7 @@ var localeStore = zustand.create((set, get) => {
1299
1299
  var locale = localeStore.getState().locale;
1300
1300
  registerInitialFetch("GET_LOCALES", void 0).then((data) => {
1301
1301
  localeStore.setState({ locales: data });
1302
+ }).catch(() => {
1302
1303
  });
1303
1304
  var useItems = zustand.create(() => ({}));
1304
1305
  var useItemsList = (excludeItemNames = []) => {
@@ -1312,6 +1313,7 @@ registerInitialFetch("FETCH_ALL_ITEMS", null, {
1312
1313
  }).then((fetchedItems) => {
1313
1314
  if (!fetchedItems) return;
1314
1315
  useItems.setState(fetchedItems);
1316
+ }).catch(() => {
1315
1317
  });
1316
1318
 
1317
1319
  // src/utils/inputMapper.ts
@@ -2548,6 +2550,7 @@ function Modal({
2548
2550
  children
2549
2551
  }) {
2550
2552
  const theme = core.useMantineTheme();
2553
+ const pointerDownOnOverlay = react.useRef(false);
2551
2554
  return /* @__PURE__ */ jsxRuntime.jsx(core.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2552
2555
  framerMotion.motion.div,
2553
2556
  {
@@ -2563,7 +2566,14 @@ function Modal({
2563
2566
  justifyContent: "center",
2564
2567
  background: "rgba(0,0,0,0.65)"
2565
2568
  },
2566
- onClick: clickOutside ? onClose : void 0,
2569
+ onPointerDown: (e) => {
2570
+ pointerDownOnOverlay.current = e.target === e.currentTarget;
2571
+ },
2572
+ onClick: (e) => {
2573
+ if (clickOutside && e.target === e.currentTarget && pointerDownOnOverlay.current) {
2574
+ onClose();
2575
+ }
2576
+ },
2567
2577
  children: /* @__PURE__ */ jsxRuntime.jsxs(
2568
2578
  framerMotion.motion.div,
2569
2579
  {
@@ -2571,7 +2581,6 @@ function Modal({
2571
2581
  animate: { opacity: 1, scale: 1, y: 0 },
2572
2582
  exit: { opacity: 0, scale: 0.96, y: 8 },
2573
2583
  transition: { duration: 0.18, ease: "easeOut" },
2574
- onClick: (e) => e.stopPropagation(),
2575
2584
  style: {
2576
2585
  background: core.alpha(theme.colors.dark[9], 0.98),
2577
2586
  border: `0.1vh solid ${theme.colors.dark[7]}`,
@@ -2668,7 +2677,7 @@ function Modal({
2668
2677
  children: description
2669
2678
  }
2670
2679
  ) }),
2671
- children
2680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children })
2672
2681
  ]
2673
2682
  }
2674
2683
  )
@@ -3291,10 +3300,10 @@ function useFormActions() {
3291
3300
  }
3292
3301
  return store.getState();
3293
3302
  }
3294
- function getScriptSettingsInstance() {
3295
- throw new Error("[dirk-cfx-react] createScriptSettings must be called before using SettingsPanel");
3303
+ function getScriptConfigInstance() {
3304
+ throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
3296
3305
  }
3297
- var settingsPanelQueryClient = new reactQuery.QueryClient({
3306
+ var configPanelQueryClient = new reactQuery.QueryClient({
3298
3307
  defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
3299
3308
  });
3300
3309
  function NavItemButton({
@@ -3338,7 +3347,7 @@ function NavItemButton({
3338
3347
  }
3339
3348
  );
3340
3349
  }
3341
- function SettingsJsonModal({
3350
+ function ConfigJsonModal({
3342
3351
  onClose,
3343
3352
  schema
3344
3353
  }) {
@@ -3375,7 +3384,7 @@ function SettingsJsonModal({
3375
3384
  setError(e.message);
3376
3385
  }
3377
3386
  };
3378
- return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "Settings JSON", icon: lucideReact.Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
3387
+ return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "Config JSON", icon: lucideReact.Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
3379
3388
  /* @__PURE__ */ jsxRuntime.jsxs(core.Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
3380
3389
  /* @__PURE__ */ jsxRuntime.jsx(
3381
3390
  core.JsonInput,
@@ -3517,10 +3526,10 @@ function HistoryTableHeader() {
3517
3526
  /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "Version" })
3518
3527
  ] });
3519
3528
  }
3520
- function SettingsHistoryModal({
3529
+ function ConfigHistoryModal({
3521
3530
  onClose
3522
3531
  }) {
3523
- const { getHistory } = getScriptSettingsInstance();
3532
+ const { getHistory } = getScriptConfigInstance();
3524
3533
  const theme = core.useMantineTheme();
3525
3534
  const color = theme.colors[theme.primaryColor][5];
3526
3535
  const [queryInput, setQueryInput] = react.useState("");
@@ -3532,7 +3541,7 @@ function SettingsHistoryModal({
3532
3541
  const [expandedKey, setExpandedKey] = react.useState(null);
3533
3542
  const filters = react.useMemo(() => ({ query, path, admin }), [query, path, admin]);
3534
3543
  const historyQuery = reactQuery.useInfiniteQuery({
3535
- queryKey: ["scriptSettingsHistory", filters],
3544
+ queryKey: ["scriptConfigHistory", filters],
3536
3545
  initialPageParam: 0,
3537
3546
  queryFn: async ({ pageParam }) => {
3538
3547
  const response = await getHistory({
@@ -3543,7 +3552,7 @@ function SettingsHistoryModal({
3543
3552
  admin: filters.admin || void 0
3544
3553
  });
3545
3554
  if (!response?.success || !response.data) {
3546
- throw new Error(response?._error || "Failed to load settings history");
3555
+ throw new Error(response?._error || "Failed to load config history");
3547
3556
  }
3548
3557
  return response.data;
3549
3558
  },
@@ -3557,7 +3566,7 @@ function SettingsHistoryModal({
3557
3566
  historyQuery.fetchNextPage();
3558
3567
  }
3559
3568
  };
3560
- return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "Settings History", icon: lucideReact.History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
3569
+ return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "Config History", icon: lucideReact.History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
3561
3570
  /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
3562
3571
  /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${core.alpha(theme.colors.dark[7], 0.8)}` }, children: [
3563
3572
  /* @__PURE__ */ jsxRuntime.jsx(core.TextInput, { leftSection: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: "1.4vh" }), placeholder: "Search path/admin/value", value: queryInput, onChange: (e) => setQueryInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
@@ -3606,7 +3615,7 @@ function SettingsHistoryModal({
3606
3615
  ) })
3607
3616
  ] });
3608
3617
  }
3609
- function SettingsPanelInner({
3618
+ function ConfigPanelInner({
3610
3619
  navItems,
3611
3620
  title,
3612
3621
  subtitle,
@@ -3615,28 +3624,37 @@ function SettingsPanelInner({
3615
3624
  onClose,
3616
3625
  schema,
3617
3626
  resetConfirmText,
3618
- defaultSettings,
3627
+ defaultConfig,
3619
3628
  width,
3620
3629
  height
3621
3630
  }) {
3622
- const { updateSettings, getHistory } = getScriptSettingsInstance();
3631
+ const { updateConfig, resetConfig, getHistory } = getScriptConfigInstance();
3623
3632
  const form = useForm();
3624
3633
  const theme = core.useMantineTheme();
3625
3634
  const color = theme.colors[theme.primaryColor][5];
3626
3635
  const version = useSettings((s) => s.resourceVersion);
3627
3636
  const [activeTab, setActiveTab] = react.useState(navItems[0]?.id ?? "");
3637
+ const firstMountRef = react.useRef(true);
3628
3638
  const [jsonOpen, setJsonOpen] = react.useState(false);
3629
3639
  const [historyOpen, setHistoryOpen] = react.useState(false);
3630
3640
  const [resetOpen, setResetOpen] = react.useState(false);
3631
- const [closeConfirmOpen, setCloseConfirmOpen] = react.useState(false);
3641
+ const [pendingAction, setPendingAction] = react.useState(null);
3632
3642
  const changedCount = form.changedCount ?? 0;
3633
3643
  const isDirty = changedCount > 0;
3644
+ const goBack = () => fetchNui("CONFIG_PANEL_BACK");
3645
+ const handleBack = () => {
3646
+ if (isDirty) {
3647
+ setPendingAction("back");
3648
+ return;
3649
+ }
3650
+ goBack();
3651
+ };
3634
3652
  react.useEffect(() => {
3635
3653
  function handleKeyDown(e) {
3636
3654
  if (e.key !== "Escape") return;
3637
3655
  if (isDirty) {
3638
3656
  e.preventDefault();
3639
- setCloseConfirmOpen(true);
3657
+ setPendingAction("close");
3640
3658
  return;
3641
3659
  }
3642
3660
  onClose();
@@ -3645,34 +3663,40 @@ function SettingsPanelInner({
3645
3663
  return () => window.removeEventListener("keydown", handleKeyDown);
3646
3664
  }, [isDirty, onClose]);
3647
3665
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3648
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: jsonOpen && /* @__PURE__ */ jsxRuntime.jsx(SettingsJsonModal, { onClose: () => setJsonOpen(false), schema }) }),
3649
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: historyOpen && /* @__PURE__ */ jsxRuntime.jsx(SettingsHistoryModal, { onClose: () => setHistoryOpen(false) }) }),
3666
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: jsonOpen && /* @__PURE__ */ jsxRuntime.jsx(ConfigJsonModal, { onClose: () => setJsonOpen(false), schema }) }),
3667
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: historyOpen && /* @__PURE__ */ jsxRuntime.jsx(ConfigHistoryModal, { onClose: () => setHistoryOpen(false) }) }),
3650
3668
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsxRuntime.jsx(
3651
3669
  ConfirmModal,
3652
3670
  {
3653
3671
  title: "Reset to Defaults",
3654
- description: "This will permanently reset ALL settings back to their defaults. Every setting you have configured will be overwritten. This cannot be undone.",
3655
- confirmLabel: "Reset Settings",
3672
+ description: "This will permanently reset ALL config back to the defaults. Every value you have configured will be overwritten. This cannot be undone.",
3673
+ confirmLabel: "Reset Config",
3656
3674
  confirmText: resetConfirmText,
3657
- onConfirm: () => {
3658
- updateSettings(defaultSettings).then(() => form.reinitialize(cloneSettings(defaultSettings)));
3675
+ onConfirm: async () => {
3659
3676
  setResetOpen(false);
3677
+ const result = await resetConfig();
3678
+ if (result?.success) {
3679
+ const { store } = getScriptConfigInstance();
3680
+ form.reinitialize(cloneConfig(store.getState()));
3681
+ }
3660
3682
  },
3661
3683
  onClose: () => setResetOpen(false),
3662
3684
  zIndex: 300
3663
3685
  }
3664
3686
  ) }),
3665
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: closeConfirmOpen && /* @__PURE__ */ jsxRuntime.jsx(
3687
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: pendingAction !== null && /* @__PURE__ */ jsxRuntime.jsx(
3666
3688
  ConfirmModal,
3667
3689
  {
3668
3690
  title: "Discard Unsaved Changes?",
3669
- description: "You have unsaved changes. Closing now will discard them.",
3670
- confirmLabel: "Close Without Saving",
3691
+ description: pendingAction === "back" ? "You have unsaved changes. Going back now will discard them." : "You have unsaved changes. Closing now will discard them.",
3692
+ confirmLabel: pendingAction === "back" ? "Go Back Without Saving" : "Close Without Saving",
3671
3693
  onConfirm: () => {
3672
- setCloseConfirmOpen(false);
3673
- onClose();
3694
+ const action = pendingAction;
3695
+ setPendingAction(null);
3696
+ if (action === "back") goBack();
3697
+ else onClose();
3674
3698
  },
3675
- onClose: () => setCloseConfirmOpen(false),
3699
+ onClose: () => setPendingAction(null),
3676
3700
  zIndex: 300
3677
3701
  }
3678
3702
  ) }),
@@ -3699,9 +3723,33 @@ function SettingsPanelInner({
3699
3723
  exit: { scale: 0.3, opacity: 0, transform: "translate(-50%, -50%)" },
3700
3724
  children: [
3701
3725
  /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", style: { width: "18vh", flexShrink: 0, borderRight: `0.1vh solid ${core.alpha(theme.colors.dark[6], 0.8)}`, background: core.alpha(theme.colors.dark[8], 0.6), overflow: "hidden" }, children: [
3702
- /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "baseline", gap: "0.3vh", px: "sm", py: "sm", style: { borderBottom: `0.1vh solid ${core.alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3703
- /* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", children: title }),
3704
- subtitle && /* @__PURE__ */ jsxRuntime.jsx(core.Text, { tt: "uppercase", fw: 600, c: color, children: subtitle })
3726
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", px: "sm", py: "sm", style: { borderBottom: `0.1vh solid ${core.alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3727
+ /* @__PURE__ */ jsxRuntime.jsx(
3728
+ framerMotion.motion.button,
3729
+ {
3730
+ title: "Back to script list",
3731
+ onClick: handleBack,
3732
+ whileHover: { background: core.alpha(color, 0.16), borderColor: core.alpha(color, 0.45) },
3733
+ whileTap: { scale: 0.95 },
3734
+ style: {
3735
+ aspectRatio: "1 / 1",
3736
+ height: "2.4vh",
3737
+ background: core.alpha(color, 0.08),
3738
+ border: `0.1vh solid ${core.alpha(color, 0.3)}`,
3739
+ borderRadius: theme.radius.xs,
3740
+ cursor: "pointer",
3741
+ display: "flex",
3742
+ alignItems: "center",
3743
+ justifyContent: "center",
3744
+ flexShrink: 0
3745
+ },
3746
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { size: "1.4vh", color })
3747
+ }
3748
+ ),
3749
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", style: { minWidth: 0, lineHeight: 1 }, children: [
3750
+ /* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", lts: "0.04em", truncate: true, children: title }),
3751
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.08em", c: color, truncate: true, children: subtitle })
3752
+ ] })
3705
3753
  ] }),
3706
3754
  /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xxs", px: "xs", py: "xs", style: { borderBottom: `0.1vh solid ${core.alpha(theme.colors.dark[6], 0.4)}`, flexShrink: 0 }, children: [
3707
3755
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3804,7 +3852,7 @@ function SettingsPanelInner({
3804
3852
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
3805
3853
  framerMotion.motion.div,
3806
3854
  {
3807
- initial: { opacity: 0, y: 4 },
3855
+ initial: firstMountRef.current ? (firstMountRef.current = false, false) : { opacity: 0, y: 4 },
3808
3856
  animate: { opacity: 1, y: 0 },
3809
3857
  exit: { opacity: 0, y: -4 },
3810
3858
  transition: { duration: 0.15 },
@@ -3818,15 +3866,15 @@ function SettingsPanelInner({
3818
3866
  )
3819
3867
  ] });
3820
3868
  }
3821
- function cloneSettings(value) {
3869
+ function cloneConfig(value) {
3822
3870
  return JSON.parse(JSON.stringify(value));
3823
3871
  }
3824
3872
  function ServerOnlyFetcher() {
3825
- const { fetchSettings } = getScriptSettingsInstance();
3873
+ const { fetchConfig } = getScriptConfigInstance();
3826
3874
  const { reinitialize } = useFormActions();
3827
3875
  react.useEffect(() => {
3828
3876
  let cancelled = false;
3829
- fetchSettings().then((full) => {
3877
+ fetchConfig().then((full) => {
3830
3878
  if (!cancelled && full) reinitialize(full);
3831
3879
  }).catch(() => {
3832
3880
  });
@@ -3837,28 +3885,28 @@ function ServerOnlyFetcher() {
3837
3885
  return null;
3838
3886
  }
3839
3887
  var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
3840
- function SettingsPanel(props) {
3888
+ function ConfigPanel(props) {
3841
3889
  const { open, onClose = defaultOnClose } = props;
3842
- const { store, updateSettings, fetchSettings } = getScriptSettingsInstance();
3890
+ const { store, updateConfig } = getScriptConfigInstance();
3843
3891
  const [isSaving, setIsSaving] = react.useState(false);
3844
3892
  if (!open) return null;
3845
- return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: settingsPanelQueryClient, children: /* @__PURE__ */ jsxRuntime.jsxs(
3893
+ return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: configPanelQueryClient, children: /* @__PURE__ */ jsxRuntime.jsxs(
3846
3894
  FormProvider,
3847
3895
  {
3848
- initialValues: cloneSettings(store.getState()),
3896
+ initialValues: cloneConfig(store.getState()),
3849
3897
  onSubmit: async (form) => {
3850
3898
  if (isSaving) return;
3851
3899
  setIsSaving(true);
3852
3900
  try {
3853
- const result = await updateSettings(form.values);
3901
+ const result = await updateConfig(form.values);
3854
3902
  if (result?.success) {
3855
- form.reinitialize(cloneSettings(form.values));
3856
- settingsPanelQueryClient.invalidateQueries({ queryKey: ["scriptSettingsHistory"] });
3903
+ form.reinitialize(cloneConfig(form.values));
3904
+ configPanelQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
3857
3905
  return;
3858
3906
  }
3859
- form.reinitialize(cloneSettings(store.getState()));
3907
+ form.reinitialize(cloneConfig(store.getState()));
3860
3908
  if (result?._error) {
3861
- console.warn(`[SettingsPanel] settings save failed: ${result._error}`);
3909
+ console.warn(`[ConfigPanel] config save failed: ${result._error}`);
3862
3910
  }
3863
3911
  } finally {
3864
3912
  setIsSaving(false);
@@ -3867,7 +3915,7 @@ function SettingsPanel(props) {
3867
3915
  children: [
3868
3916
  /* @__PURE__ */ jsxRuntime.jsx(ServerOnlyFetcher, {}),
3869
3917
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(
3870
- SettingsPanelInner,
3918
+ ConfigPanelInner,
3871
3919
  {
3872
3920
  ...props,
3873
3921
  onClose,
@@ -4075,12 +4123,167 @@ function AdminPageTitle(props) {
4075
4123
  /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", tt: "uppercase", lts: "0.1em", size: "sm", c: "rgba(255,255,255,0.6)", children: locale(props.title) })
4076
4124
  ] });
4077
4125
  }
4126
+ var loadPersistedState = (storageKey) => {
4127
+ try {
4128
+ const raw = localStorage.getItem(storageKey);
4129
+ return raw ? JSON.parse(raw) : {};
4130
+ } catch {
4131
+ return {};
4132
+ }
4133
+ };
4134
+ var savePersistedState = (storageKey, state) => {
4135
+ try {
4136
+ localStorage.setItem(storageKey, JSON.stringify(state));
4137
+ } catch {
4138
+ }
4139
+ };
4140
+ function TestBed({
4141
+ items,
4142
+ storageKey = "testbed:open-state",
4143
+ disablePersistence = false,
4144
+ title = "TestBed"
4145
+ }) {
4146
+ const [open, setOpen] = react.useState(false);
4147
+ const itemsRef = react.useRef(items);
4148
+ itemsRef.current = items;
4149
+ react.useEffect(() => {
4150
+ if (!isEnvBrowser() || disablePersistence) return;
4151
+ const persisted = loadPersistedState(storageKey);
4152
+ itemsRef.current.forEach((item) => {
4153
+ const persistedValue = persisted[item.key];
4154
+ if (typeof persistedValue === "boolean" && persistedValue !== item.active) {
4155
+ item.onToggle(persistedValue);
4156
+ }
4157
+ });
4158
+ }, []);
4159
+ if (!isEnvBrowser()) return null;
4160
+ const toggle = (item) => {
4161
+ const next = !item.active;
4162
+ item.onToggle(next);
4163
+ if (!disablePersistence) {
4164
+ const persisted = loadPersistedState(storageKey);
4165
+ persisted[item.key] = next;
4166
+ savePersistedState(storageKey, persisted);
4167
+ }
4168
+ };
4169
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4170
+ "div",
4171
+ {
4172
+ style: {
4173
+ position: "fixed",
4174
+ top: "1vh",
4175
+ left: "1vh",
4176
+ zIndex: 2147483647,
4177
+ pointerEvents: "auto",
4178
+ fontSize: "1.4vh"
4179
+ },
4180
+ children: [
4181
+ /* @__PURE__ */ jsxRuntime.jsxs(
4182
+ core.Flex,
4183
+ {
4184
+ align: "center",
4185
+ gap: "xs",
4186
+ px: "sm",
4187
+ py: "xs",
4188
+ onClick: () => setOpen((v) => !v),
4189
+ style: {
4190
+ cursor: "pointer",
4191
+ background: "rgba(0,0,0,0.55)",
4192
+ backdropFilter: "blur(0.6vh)",
4193
+ WebkitBackdropFilter: "blur(0.6vh)",
4194
+ border: "0.1vh solid rgba(255,255,255,0.1)",
4195
+ borderRadius: "var(--mantine-radius-sm)",
4196
+ userSelect: "none",
4197
+ minWidth: "16vh"
4198
+ },
4199
+ children: [
4200
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlaskConical, { size: 14, color: "rgba(255,255,255,0.7)" }),
4201
+ /* @__PURE__ */ jsxRuntime.jsx(
4202
+ core.Text,
4203
+ {
4204
+ size: "xs",
4205
+ ff: "Akrobat Bold",
4206
+ tt: "uppercase",
4207
+ lts: "0.08em",
4208
+ c: "rgba(255,255,255,0.85)",
4209
+ style: { flex: 1 },
4210
+ children: title
4211
+ }
4212
+ ),
4213
+ /* @__PURE__ */ jsxRuntime.jsx(core.ActionIcon, { size: "xs", variant: "transparent", c: "rgba(255,255,255,0.6)", children: open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14 }) })
4214
+ ]
4215
+ }
4216
+ ),
4217
+ open && /* @__PURE__ */ jsxRuntime.jsx(
4218
+ core.Stack,
4219
+ {
4220
+ gap: 4,
4221
+ mt: "xxs",
4222
+ p: "xs",
4223
+ style: {
4224
+ background: "rgba(0,0,0,0.55)",
4225
+ backdropFilter: "blur(0.6vh)",
4226
+ WebkitBackdropFilter: "blur(0.6vh)",
4227
+ border: "0.1vh solid rgba(255,255,255,0.1)",
4228
+ borderRadius: "var(--mantine-radius-sm)",
4229
+ minWidth: "16vh",
4230
+ maxHeight: "80vh",
4231
+ overflowY: "auto"
4232
+ },
4233
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
4234
+ core.Flex,
4235
+ {
4236
+ align: "center",
4237
+ justify: "space-between",
4238
+ gap: "xs",
4239
+ px: "xs",
4240
+ py: "xxs",
4241
+ onClick: () => toggle(item),
4242
+ style: {
4243
+ cursor: "pointer",
4244
+ borderRadius: "var(--mantine-radius-xs)",
4245
+ background: item.active ? "rgba(245,158,11,0.15)" : "rgba(255,255,255,0.03)",
4246
+ border: `0.1vh solid ${item.active ? "rgba(245,158,11,0.35)" : "rgba(255,255,255,0.05)"}`,
4247
+ userSelect: "none"
4248
+ },
4249
+ children: [
4250
+ /* @__PURE__ */ jsxRuntime.jsx(
4251
+ core.Text,
4252
+ {
4253
+ size: "xs",
4254
+ ff: "Akrobat Bold",
4255
+ c: item.active ? "#f59e0b" : "rgba(255,255,255,0.75)",
4256
+ children: item.label
4257
+ }
4258
+ ),
4259
+ /* @__PURE__ */ jsxRuntime.jsx(
4260
+ core.Text,
4261
+ {
4262
+ size: "xxs",
4263
+ ff: "Akrobat Bold",
4264
+ tt: "uppercase",
4265
+ lts: "0.06em",
4266
+ c: item.active ? "#f59e0b" : "rgba(255,255,255,0.35)",
4267
+ children: item.active ? "On" : "Off"
4268
+ }
4269
+ )
4270
+ ]
4271
+ },
4272
+ item.key
4273
+ ))
4274
+ }
4275
+ )
4276
+ ]
4277
+ }
4278
+ );
4279
+ }
4078
4280
 
4079
4281
  exports.AdminPageTitle = AdminPageTitle;
4080
4282
  exports.AsyncSaveButton = AsyncSaveButton;
4081
4283
  exports.BlipColorSelect = BlipColorSelect;
4082
4284
  exports.BlipIconSelect = BlipIconSelect;
4083
4285
  exports.BorderedIcon = BorderedIcon;
4286
+ exports.ConfigPanel = ConfigPanel;
4084
4287
  exports.ConfirmModal = ConfirmModal;
4085
4288
  exports.Counter = Counter;
4086
4289
  exports.FiveMKeyBindInput = FiveMKeyBindInput;
@@ -4103,7 +4306,7 @@ exports.PromptModal = PromptModal;
4103
4306
  exports.SegmentedControl = SegmentedControl;
4104
4307
  exports.SegmentedProgress = SegmentedProgress;
4105
4308
  exports.SelectItem = SelectItem;
4106
- exports.SettingsPanel = SettingsPanel;
4309
+ exports.TestBed = TestBed;
4107
4310
  exports.Title = Title;
4108
4311
  exports.useModal = useModal;
4109
4312
  exports.useModalActions = useModalActions;