dirk-cfx-react 1.1.58 → 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.
@@ -1,4 +1,4 @@
1
- import { Flex, Text, Image, TextInput, Select, Box, useMantineTheme, alpha, Progress, RingProgress, Portal, Button, Loader, Group, JsonInput } from '@mantine/core';
1
+ import { Flex, Text, Image, TextInput, Select, Box, useMantineTheme, alpha, Progress, RingProgress, Portal, Button, Loader, ActionIcon, Stack, Group, JsonInput } from '@mantine/core';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { createContext, useContext, useRef, useState, useEffect, useMemo } from 'react';
4
4
  import { create, useStore, createStore } from 'zustand';
@@ -6,7 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
6
6
  import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
7
7
  import clickSoundUrl from '../click_sound-PNCRRTM4.mp3';
8
8
  import hoverSoundUrl from '../hover_sound-NBUA222C.mp3';
9
- import { X, AlertTriangle, Trash2, Check, Undo2, Redo2, Save, History, XCircle, Code2, RotateCcw, Search, Filter, User, ChevronDown } from 'lucide-react';
9
+ import { X, AlertTriangle, Trash2, Check, FlaskConical, ChevronUp, ChevronDown, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, RotateCcw, Search, Filter, User } from 'lucide-react';
10
10
  import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
11
11
 
12
12
  // src/components/BlipSelect.tsx
@@ -1292,6 +1292,7 @@ var localeStore = create((set, get) => {
1292
1292
  var locale = localeStore.getState().locale;
1293
1293
  registerInitialFetch("GET_LOCALES", void 0).then((data) => {
1294
1294
  localeStore.setState({ locales: data });
1295
+ }).catch(() => {
1295
1296
  });
1296
1297
  var useItems = create(() => ({}));
1297
1298
  var useItemsList = (excludeItemNames = []) => {
@@ -1305,6 +1306,7 @@ registerInitialFetch("FETCH_ALL_ITEMS", null, {
1305
1306
  }).then((fetchedItems) => {
1306
1307
  if (!fetchedItems) return;
1307
1308
  useItems.setState(fetchedItems);
1309
+ }).catch(() => {
1308
1310
  });
1309
1311
 
1310
1312
  // src/utils/inputMapper.ts
@@ -2668,7 +2670,7 @@ function Modal({
2668
2670
  children: description
2669
2671
  }
2670
2672
  ) }),
2671
- children
2673
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children })
2672
2674
  ]
2673
2675
  }
2674
2676
  )
@@ -3291,10 +3293,10 @@ function useFormActions() {
3291
3293
  }
3292
3294
  return store.getState();
3293
3295
  }
3294
- function getScriptSettingsInstance() {
3295
- throw new Error("[dirk-cfx-react] createScriptSettings must be called before using SettingsPanel");
3296
+ function getScriptConfigInstance() {
3297
+ throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
3296
3298
  }
3297
- var settingsPanelQueryClient = new QueryClient({
3299
+ var configPanelQueryClient = new QueryClient({
3298
3300
  defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
3299
3301
  });
3300
3302
  function NavItemButton({
@@ -3338,7 +3340,7 @@ function NavItemButton({
3338
3340
  }
3339
3341
  );
3340
3342
  }
3341
- function SettingsJsonModal({
3343
+ function ConfigJsonModal({
3342
3344
  onClose,
3343
3345
  schema
3344
3346
  }) {
@@ -3375,7 +3377,7 @@ function SettingsJsonModal({
3375
3377
  setError(e.message);
3376
3378
  }
3377
3379
  };
3378
- return /* @__PURE__ */ jsxs(Modal, { title: "Settings JSON", icon: Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
3380
+ return /* @__PURE__ */ jsxs(Modal, { title: "Config JSON", icon: Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
3379
3381
  /* @__PURE__ */ jsxs(Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
3380
3382
  /* @__PURE__ */ jsx(
3381
3383
  JsonInput,
@@ -3517,10 +3519,10 @@ function HistoryTableHeader() {
3517
3519
  /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "Version" })
3518
3520
  ] });
3519
3521
  }
3520
- function SettingsHistoryModal({
3522
+ function ConfigHistoryModal({
3521
3523
  onClose
3522
3524
  }) {
3523
- const { getHistory } = getScriptSettingsInstance();
3525
+ const { getHistory } = getScriptConfigInstance();
3524
3526
  const theme = useMantineTheme();
3525
3527
  const color = theme.colors[theme.primaryColor][5];
3526
3528
  const [queryInput, setQueryInput] = useState("");
@@ -3532,7 +3534,7 @@ function SettingsHistoryModal({
3532
3534
  const [expandedKey, setExpandedKey] = useState(null);
3533
3535
  const filters = useMemo(() => ({ query, path, admin }), [query, path, admin]);
3534
3536
  const historyQuery = useInfiniteQuery({
3535
- queryKey: ["scriptSettingsHistory", filters],
3537
+ queryKey: ["scriptConfigHistory", filters],
3536
3538
  initialPageParam: 0,
3537
3539
  queryFn: async ({ pageParam }) => {
3538
3540
  const response = await getHistory({
@@ -3543,7 +3545,7 @@ function SettingsHistoryModal({
3543
3545
  admin: filters.admin || void 0
3544
3546
  });
3545
3547
  if (!response?.success || !response.data) {
3546
- throw new Error(response?._error || "Failed to load settings history");
3548
+ throw new Error(response?._error || "Failed to load config history");
3547
3549
  }
3548
3550
  return response.data;
3549
3551
  },
@@ -3557,7 +3559,7 @@ function SettingsHistoryModal({
3557
3559
  historyQuery.fetchNextPage();
3558
3560
  }
3559
3561
  };
3560
- return /* @__PURE__ */ jsxs(Modal, { title: "Settings History", icon: History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
3562
+ return /* @__PURE__ */ jsxs(Modal, { title: "Config History", icon: History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
3561
3563
  /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
3562
3564
  /* @__PURE__ */ jsxs(Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[7], 0.8)}` }, children: [
3563
3565
  /* @__PURE__ */ jsx(TextInput, { leftSection: /* @__PURE__ */ jsx(Search, { size: "1.4vh" }), placeholder: "Search path/admin/value", value: queryInput, onChange: (e) => setQueryInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
@@ -3606,7 +3608,7 @@ function SettingsHistoryModal({
3606
3608
  ) })
3607
3609
  ] });
3608
3610
  }
3609
- function SettingsPanelInner({
3611
+ function ConfigPanelInner({
3610
3612
  navItems,
3611
3613
  title,
3612
3614
  subtitle,
@@ -3615,28 +3617,37 @@ function SettingsPanelInner({
3615
3617
  onClose,
3616
3618
  schema,
3617
3619
  resetConfirmText,
3618
- defaultSettings,
3620
+ defaultConfig,
3619
3621
  width,
3620
3622
  height
3621
3623
  }) {
3622
- const { updateSettings, getHistory } = getScriptSettingsInstance();
3624
+ const { updateConfig, resetConfig, getHistory } = getScriptConfigInstance();
3623
3625
  const form = useForm();
3624
3626
  const theme = useMantineTheme();
3625
3627
  const color = theme.colors[theme.primaryColor][5];
3626
3628
  const version = useSettings((s) => s.resourceVersion);
3627
3629
  const [activeTab, setActiveTab] = useState(navItems[0]?.id ?? "");
3630
+ const firstMountRef = useRef(true);
3628
3631
  const [jsonOpen, setJsonOpen] = useState(false);
3629
3632
  const [historyOpen, setHistoryOpen] = useState(false);
3630
3633
  const [resetOpen, setResetOpen] = useState(false);
3631
- const [closeConfirmOpen, setCloseConfirmOpen] = useState(false);
3634
+ const [pendingAction, setPendingAction] = useState(null);
3632
3635
  const changedCount = form.changedCount ?? 0;
3633
3636
  const isDirty = changedCount > 0;
3637
+ const goBack = () => fetchNui("CONFIG_PANEL_BACK");
3638
+ const handleBack = () => {
3639
+ if (isDirty) {
3640
+ setPendingAction("back");
3641
+ return;
3642
+ }
3643
+ goBack();
3644
+ };
3634
3645
  useEffect(() => {
3635
3646
  function handleKeyDown(e) {
3636
3647
  if (e.key !== "Escape") return;
3637
3648
  if (isDirty) {
3638
3649
  e.preventDefault();
3639
- setCloseConfirmOpen(true);
3650
+ setPendingAction("close");
3640
3651
  return;
3641
3652
  }
3642
3653
  onClose();
@@ -3645,34 +3656,40 @@ function SettingsPanelInner({
3645
3656
  return () => window.removeEventListener("keydown", handleKeyDown);
3646
3657
  }, [isDirty, onClose]);
3647
3658
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3648
- /* @__PURE__ */ jsx(AnimatePresence, { children: jsonOpen && /* @__PURE__ */ jsx(SettingsJsonModal, { onClose: () => setJsonOpen(false), schema }) }),
3649
- /* @__PURE__ */ jsx(AnimatePresence, { children: historyOpen && /* @__PURE__ */ jsx(SettingsHistoryModal, { onClose: () => setHistoryOpen(false) }) }),
3659
+ /* @__PURE__ */ jsx(AnimatePresence, { children: jsonOpen && /* @__PURE__ */ jsx(ConfigJsonModal, { onClose: () => setJsonOpen(false), schema }) }),
3660
+ /* @__PURE__ */ jsx(AnimatePresence, { children: historyOpen && /* @__PURE__ */ jsx(ConfigHistoryModal, { onClose: () => setHistoryOpen(false) }) }),
3650
3661
  /* @__PURE__ */ jsx(AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsx(
3651
3662
  ConfirmModal,
3652
3663
  {
3653
3664
  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",
3665
+ description: "This will permanently reset ALL config back to the defaults. Every value you have configured will be overwritten. This cannot be undone.",
3666
+ confirmLabel: "Reset Config",
3656
3667
  confirmText: resetConfirmText,
3657
- onConfirm: () => {
3658
- updateSettings(defaultSettings).then(() => form.reinitialize(cloneSettings(defaultSettings)));
3668
+ onConfirm: async () => {
3659
3669
  setResetOpen(false);
3670
+ const result = await resetConfig();
3671
+ if (result?.success) {
3672
+ const { store } = getScriptConfigInstance();
3673
+ form.reinitialize(cloneConfig(store.getState()));
3674
+ }
3660
3675
  },
3661
3676
  onClose: () => setResetOpen(false),
3662
3677
  zIndex: 300
3663
3678
  }
3664
3679
  ) }),
3665
- /* @__PURE__ */ jsx(AnimatePresence, { children: closeConfirmOpen && /* @__PURE__ */ jsx(
3680
+ /* @__PURE__ */ jsx(AnimatePresence, { children: pendingAction !== null && /* @__PURE__ */ jsx(
3666
3681
  ConfirmModal,
3667
3682
  {
3668
3683
  title: "Discard Unsaved Changes?",
3669
- description: "You have unsaved changes. Closing now will discard them.",
3670
- confirmLabel: "Close Without Saving",
3684
+ description: pendingAction === "back" ? "You have unsaved changes. Going back now will discard them." : "You have unsaved changes. Closing now will discard them.",
3685
+ confirmLabel: pendingAction === "back" ? "Go Back Without Saving" : "Close Without Saving",
3671
3686
  onConfirm: () => {
3672
- setCloseConfirmOpen(false);
3673
- onClose();
3687
+ const action = pendingAction;
3688
+ setPendingAction(null);
3689
+ if (action === "back") goBack();
3690
+ else onClose();
3674
3691
  },
3675
- onClose: () => setCloseConfirmOpen(false),
3692
+ onClose: () => setPendingAction(null),
3676
3693
  zIndex: 300
3677
3694
  }
3678
3695
  ) }),
@@ -3699,9 +3716,33 @@ function SettingsPanelInner({
3699
3716
  exit: { scale: 0.3, opacity: 0, transform: "translate(-50%, -50%)" },
3700
3717
  children: [
3701
3718
  /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { width: "18vh", flexShrink: 0, borderRight: `0.1vh solid ${alpha(theme.colors.dark[6], 0.8)}`, background: alpha(theme.colors.dark[8], 0.6), overflow: "hidden" }, children: [
3702
- /* @__PURE__ */ jsxs(Flex, { align: "baseline", gap: "0.3vh", px: "sm", py: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3703
- /* @__PURE__ */ jsx(Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", children: title }),
3704
- subtitle && /* @__PURE__ */ jsx(Text, { tt: "uppercase", fw: 600, c: color, children: subtitle })
3719
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "0.6vh", px: "sm", py: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3720
+ /* @__PURE__ */ jsx(
3721
+ motion.button,
3722
+ {
3723
+ title: "Back to script list",
3724
+ onClick: handleBack,
3725
+ whileHover: { background: alpha(color, 0.16), borderColor: alpha(color, 0.45) },
3726
+ whileTap: { scale: 0.95 },
3727
+ style: {
3728
+ aspectRatio: "1 / 1",
3729
+ height: "2.4vh",
3730
+ background: alpha(color, 0.08),
3731
+ border: `0.1vh solid ${alpha(color, 0.3)}`,
3732
+ borderRadius: theme.radius.xs,
3733
+ cursor: "pointer",
3734
+ display: "flex",
3735
+ alignItems: "center",
3736
+ justifyContent: "center",
3737
+ flexShrink: 0
3738
+ },
3739
+ children: /* @__PURE__ */ jsx(ArrowLeft, { size: "1.4vh", color })
3740
+ }
3741
+ ),
3742
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { minWidth: 0, lineHeight: 1 }, children: [
3743
+ /* @__PURE__ */ jsx(Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", lts: "0.04em", truncate: true, children: title }),
3744
+ subtitle && /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.08em", c: color, truncate: true, children: subtitle })
3745
+ ] })
3705
3746
  ] }),
3706
3747
  /* @__PURE__ */ jsxs(Flex, { gap: "xxs", px: "xs", py: "xs", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[6], 0.4)}`, flexShrink: 0 }, children: [
3707
3748
  /* @__PURE__ */ jsx(
@@ -3804,7 +3845,7 @@ function SettingsPanelInner({
3804
3845
  /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
3805
3846
  motion.div,
3806
3847
  {
3807
- initial: { opacity: 0, y: 4 },
3848
+ initial: firstMountRef.current ? (firstMountRef.current = false, false) : { opacity: 0, y: 4 },
3808
3849
  animate: { opacity: 1, y: 0 },
3809
3850
  exit: { opacity: 0, y: -4 },
3810
3851
  transition: { duration: 0.15 },
@@ -3818,15 +3859,15 @@ function SettingsPanelInner({
3818
3859
  )
3819
3860
  ] });
3820
3861
  }
3821
- function cloneSettings(value) {
3862
+ function cloneConfig(value) {
3822
3863
  return JSON.parse(JSON.stringify(value));
3823
3864
  }
3824
3865
  function ServerOnlyFetcher() {
3825
- const { fetchSettings } = getScriptSettingsInstance();
3866
+ const { fetchConfig } = getScriptConfigInstance();
3826
3867
  const { reinitialize } = useFormActions();
3827
3868
  useEffect(() => {
3828
3869
  let cancelled = false;
3829
- fetchSettings().then((full) => {
3870
+ fetchConfig().then((full) => {
3830
3871
  if (!cancelled && full) reinitialize(full);
3831
3872
  }).catch(() => {
3832
3873
  });
@@ -3837,28 +3878,28 @@ function ServerOnlyFetcher() {
3837
3878
  return null;
3838
3879
  }
3839
3880
  var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
3840
- function SettingsPanel(props) {
3881
+ function ConfigPanel(props) {
3841
3882
  const { open, onClose = defaultOnClose } = props;
3842
- const { store, updateSettings, fetchSettings } = getScriptSettingsInstance();
3883
+ const { store, updateConfig } = getScriptConfigInstance();
3843
3884
  const [isSaving, setIsSaving] = useState(false);
3844
3885
  if (!open) return null;
3845
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: settingsPanelQueryClient, children: /* @__PURE__ */ jsxs(
3886
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: configPanelQueryClient, children: /* @__PURE__ */ jsxs(
3846
3887
  FormProvider,
3847
3888
  {
3848
- initialValues: cloneSettings(store.getState()),
3889
+ initialValues: cloneConfig(store.getState()),
3849
3890
  onSubmit: async (form) => {
3850
3891
  if (isSaving) return;
3851
3892
  setIsSaving(true);
3852
3893
  try {
3853
- const result = await updateSettings(form.values);
3894
+ const result = await updateConfig(form.values);
3854
3895
  if (result?.success) {
3855
- form.reinitialize(cloneSettings(form.values));
3856
- settingsPanelQueryClient.invalidateQueries({ queryKey: ["scriptSettingsHistory"] });
3896
+ form.reinitialize(cloneConfig(form.values));
3897
+ configPanelQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
3857
3898
  return;
3858
3899
  }
3859
- form.reinitialize(cloneSettings(store.getState()));
3900
+ form.reinitialize(cloneConfig(store.getState()));
3860
3901
  if (result?._error) {
3861
- console.warn(`[SettingsPanel] settings save failed: ${result._error}`);
3902
+ console.warn(`[ConfigPanel] config save failed: ${result._error}`);
3862
3903
  }
3863
3904
  } finally {
3864
3905
  setIsSaving(false);
@@ -3867,7 +3908,7 @@ function SettingsPanel(props) {
3867
3908
  children: [
3868
3909
  /* @__PURE__ */ jsx(ServerOnlyFetcher, {}),
3869
3910
  /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(
3870
- SettingsPanelInner,
3911
+ ConfigPanelInner,
3871
3912
  {
3872
3913
  ...props,
3873
3914
  onClose,
@@ -4075,7 +4116,161 @@ function AdminPageTitle(props) {
4075
4116
  /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", tt: "uppercase", lts: "0.1em", size: "sm", c: "rgba(255,255,255,0.6)", children: locale(props.title) })
4076
4117
  ] });
4077
4118
  }
4119
+ var loadPersistedState = (storageKey) => {
4120
+ try {
4121
+ const raw = localStorage.getItem(storageKey);
4122
+ return raw ? JSON.parse(raw) : {};
4123
+ } catch {
4124
+ return {};
4125
+ }
4126
+ };
4127
+ var savePersistedState = (storageKey, state) => {
4128
+ try {
4129
+ localStorage.setItem(storageKey, JSON.stringify(state));
4130
+ } catch {
4131
+ }
4132
+ };
4133
+ function TestBed({
4134
+ items,
4135
+ storageKey = "testbed:open-state",
4136
+ disablePersistence = false,
4137
+ title = "TestBed"
4138
+ }) {
4139
+ const [open, setOpen] = useState(false);
4140
+ const itemsRef = useRef(items);
4141
+ itemsRef.current = items;
4142
+ useEffect(() => {
4143
+ if (!isEnvBrowser() || disablePersistence) return;
4144
+ const persisted = loadPersistedState(storageKey);
4145
+ itemsRef.current.forEach((item) => {
4146
+ const persistedValue = persisted[item.key];
4147
+ if (typeof persistedValue === "boolean" && persistedValue !== item.active) {
4148
+ item.onToggle(persistedValue);
4149
+ }
4150
+ });
4151
+ }, []);
4152
+ if (!isEnvBrowser()) return null;
4153
+ const toggle = (item) => {
4154
+ const next = !item.active;
4155
+ item.onToggle(next);
4156
+ if (!disablePersistence) {
4157
+ const persisted = loadPersistedState(storageKey);
4158
+ persisted[item.key] = next;
4159
+ savePersistedState(storageKey, persisted);
4160
+ }
4161
+ };
4162
+ return /* @__PURE__ */ jsxs(
4163
+ "div",
4164
+ {
4165
+ style: {
4166
+ position: "fixed",
4167
+ top: "1vh",
4168
+ left: "1vh",
4169
+ zIndex: 2147483647,
4170
+ pointerEvents: "auto",
4171
+ fontSize: "1.4vh"
4172
+ },
4173
+ children: [
4174
+ /* @__PURE__ */ jsxs(
4175
+ Flex,
4176
+ {
4177
+ align: "center",
4178
+ gap: "xs",
4179
+ px: "sm",
4180
+ py: "xs",
4181
+ onClick: () => setOpen((v) => !v),
4182
+ style: {
4183
+ cursor: "pointer",
4184
+ background: "rgba(0,0,0,0.55)",
4185
+ backdropFilter: "blur(0.6vh)",
4186
+ WebkitBackdropFilter: "blur(0.6vh)",
4187
+ border: "0.1vh solid rgba(255,255,255,0.1)",
4188
+ borderRadius: "var(--mantine-radius-sm)",
4189
+ userSelect: "none",
4190
+ minWidth: "16vh"
4191
+ },
4192
+ children: [
4193
+ /* @__PURE__ */ jsx(FlaskConical, { size: 14, color: "rgba(255,255,255,0.7)" }),
4194
+ /* @__PURE__ */ jsx(
4195
+ Text,
4196
+ {
4197
+ size: "xs",
4198
+ ff: "Akrobat Bold",
4199
+ tt: "uppercase",
4200
+ lts: "0.08em",
4201
+ c: "rgba(255,255,255,0.85)",
4202
+ style: { flex: 1 },
4203
+ children: title
4204
+ }
4205
+ ),
4206
+ /* @__PURE__ */ jsx(ActionIcon, { size: "xs", variant: "transparent", c: "rgba(255,255,255,0.6)", children: open ? /* @__PURE__ */ jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsx(ChevronDown, { size: 14 }) })
4207
+ ]
4208
+ }
4209
+ ),
4210
+ open && /* @__PURE__ */ jsx(
4211
+ Stack,
4212
+ {
4213
+ gap: 4,
4214
+ mt: "xxs",
4215
+ p: "xs",
4216
+ style: {
4217
+ background: "rgba(0,0,0,0.55)",
4218
+ backdropFilter: "blur(0.6vh)",
4219
+ WebkitBackdropFilter: "blur(0.6vh)",
4220
+ border: "0.1vh solid rgba(255,255,255,0.1)",
4221
+ borderRadius: "var(--mantine-radius-sm)",
4222
+ minWidth: "16vh",
4223
+ maxHeight: "80vh",
4224
+ overflowY: "auto"
4225
+ },
4226
+ children: items.map((item) => /* @__PURE__ */ jsxs(
4227
+ Flex,
4228
+ {
4229
+ align: "center",
4230
+ justify: "space-between",
4231
+ gap: "xs",
4232
+ px: "xs",
4233
+ py: "xxs",
4234
+ onClick: () => toggle(item),
4235
+ style: {
4236
+ cursor: "pointer",
4237
+ borderRadius: "var(--mantine-radius-xs)",
4238
+ background: item.active ? "rgba(245,158,11,0.15)" : "rgba(255,255,255,0.03)",
4239
+ border: `0.1vh solid ${item.active ? "rgba(245,158,11,0.35)" : "rgba(255,255,255,0.05)"}`,
4240
+ userSelect: "none"
4241
+ },
4242
+ children: [
4243
+ /* @__PURE__ */ jsx(
4244
+ Text,
4245
+ {
4246
+ size: "xs",
4247
+ ff: "Akrobat Bold",
4248
+ c: item.active ? "#f59e0b" : "rgba(255,255,255,0.75)",
4249
+ children: item.label
4250
+ }
4251
+ ),
4252
+ /* @__PURE__ */ jsx(
4253
+ Text,
4254
+ {
4255
+ size: "xxs",
4256
+ ff: "Akrobat Bold",
4257
+ tt: "uppercase",
4258
+ lts: "0.06em",
4259
+ c: item.active ? "#f59e0b" : "rgba(255,255,255,0.35)",
4260
+ children: item.active ? "On" : "Off"
4261
+ }
4262
+ )
4263
+ ]
4264
+ },
4265
+ item.key
4266
+ ))
4267
+ }
4268
+ )
4269
+ ]
4270
+ }
4271
+ );
4272
+ }
4078
4273
 
4079
- export { AdminPageTitle, AsyncSaveButton, BlipColorSelect, BlipIconSelect, BorderedIcon, ConfirmModal, Counter, FiveMKeyBindInput, FloatingParticles, InfoBox, InputContainer, LevelBanner, LevelPanel, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PromptModal, SegmentedControl, SegmentedProgress, SelectItem, SettingsPanel, Title, useModal, useModalActions, useNavigation, useNavigationStore };
4274
+ export { AdminPageTitle, AsyncSaveButton, BlipColorSelect, BlipIconSelect, BorderedIcon, ConfigPanel, ConfirmModal, Counter, FiveMKeyBindInput, FloatingParticles, InfoBox, InputContainer, LevelBanner, LevelPanel, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PromptModal, SegmentedControl, SegmentedProgress, SelectItem, TestBed, Title, useModal, useModalActions, useNavigation, useNavigationStore };
4080
4275
  //# sourceMappingURL=index.js.map
4081
4276
  //# sourceMappingURL=index.js.map