dirk-cfx-react 1.1.90 → 1.1.91
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.
- package/dist/components/index.cjs +449 -222
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +39 -9
- package/dist/components/index.d.ts +39 -9
- package/dist/components/index.js +450 -224
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/index.cjs +22 -12
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +22 -12
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +452 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +450 -225
- package/dist/index.js.map +1 -1
- package/dist/providers/index.cjs +22 -12
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.js +22 -12
- package/dist/providers/index.js.map +1 -1
- package/dist/utils/index.cjs +22 -12
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +22 -12
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/components/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { Flex, Text, Image, TextInput, Select, Box, useMantineTheme, Tooltip, al
|
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { createContext, memo, useRef, useEffect, useContext, useState, useCallback, useMemo } from 'react';
|
|
4
4
|
import { create, useStore, createStore } from 'zustand';
|
|
5
|
+
import { z } from 'zod';
|
|
5
6
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
6
7
|
import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
|
|
7
|
-
import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, Palette,
|
|
8
|
+
import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, Palette, ShieldCheck, Users, UserRound, Plus, DoorOpen, Minus, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, Search, Filter, User } from 'lucide-react';
|
|
8
9
|
import clickSoundUrl from '../click_sound-PNCRRTM4.mp3';
|
|
9
10
|
import hoverSoundUrl from '../hover_sound-NBUA222C.mp3';
|
|
10
11
|
import { notifications } from '@mantine/notifications';
|
|
@@ -1282,6 +1283,32 @@ function colorWithAlpha(color, alpha17) {
|
|
|
1282
1283
|
|
|
1283
1284
|
// src/utils/misc.ts
|
|
1284
1285
|
var isEnvBrowser = () => !window.invokeNative;
|
|
1286
|
+
var DEFAULT_PALETTE = [
|
|
1287
|
+
"#f0f4ff",
|
|
1288
|
+
"#d9e3ff",
|
|
1289
|
+
"#bfcfff",
|
|
1290
|
+
"#a6bbff",
|
|
1291
|
+
"#8ca7ff",
|
|
1292
|
+
"#7393ff",
|
|
1293
|
+
"#5a7fff",
|
|
1294
|
+
"#406bff",
|
|
1295
|
+
"#2547ff",
|
|
1296
|
+
"#0b33ff"
|
|
1297
|
+
];
|
|
1298
|
+
z.object({
|
|
1299
|
+
useOverride: z.boolean(),
|
|
1300
|
+
primaryColor: z.string(),
|
|
1301
|
+
primaryShade: z.number(),
|
|
1302
|
+
customTheme: z.array(z.string())
|
|
1303
|
+
});
|
|
1304
|
+
var defaultThemeOverride = {
|
|
1305
|
+
useOverride: false,
|
|
1306
|
+
primaryColor: "dirk",
|
|
1307
|
+
primaryShade: 5,
|
|
1308
|
+
customTheme: DEFAULT_PALETTE
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
// src/utils/useSettings.ts
|
|
1285
1312
|
var useSettings = create(() => ({
|
|
1286
1313
|
currency: "$",
|
|
1287
1314
|
game: "fivem",
|
|
@@ -1289,18 +1316,7 @@ var useSettings = create(() => ({
|
|
|
1289
1316
|
primaryShade: 9,
|
|
1290
1317
|
itemImgPath: "",
|
|
1291
1318
|
resourceVersion: "dev",
|
|
1292
|
-
customTheme:
|
|
1293
|
-
"#f0f4ff",
|
|
1294
|
-
"#d9e3ff",
|
|
1295
|
-
"#bfcfff",
|
|
1296
|
-
"#a6bbff",
|
|
1297
|
-
"#8ca7ff",
|
|
1298
|
-
"#7393ff",
|
|
1299
|
-
"#5a7fff",
|
|
1300
|
-
"#406bff",
|
|
1301
|
-
"#2547ff",
|
|
1302
|
-
"#0b33ff"
|
|
1303
|
-
]
|
|
1319
|
+
customTheme: DEFAULT_PALETTE
|
|
1304
1320
|
}));
|
|
1305
1321
|
|
|
1306
1322
|
// src/utils/fetchNui.ts
|
|
@@ -3154,11 +3170,11 @@ function ConfirmModal({
|
|
|
3154
3170
|
placeholder: confirmText,
|
|
3155
3171
|
value: typed,
|
|
3156
3172
|
onChange: (e) => setTyped(e.currentTarget.value),
|
|
3157
|
-
styles: (
|
|
3173
|
+
styles: (t4) => ({
|
|
3158
3174
|
input: {
|
|
3159
|
-
backgroundColor: alpha(
|
|
3175
|
+
backgroundColor: alpha(t4.colors.dark[7], 0.5),
|
|
3160
3176
|
border: `0.1vh solid ${alpha(
|
|
3161
|
-
typed === confirmText ? "#ef4444" :
|
|
3177
|
+
typed === confirmText ? "#ef4444" : t4.colors.dark[5],
|
|
3162
3178
|
0.5
|
|
3163
3179
|
)}`,
|
|
3164
3180
|
color: "rgba(255,255,255,0.85)",
|
|
@@ -3803,7 +3819,7 @@ function useAdminState(key, initial) {
|
|
|
3803
3819
|
useEffect(() => {
|
|
3804
3820
|
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
3805
3821
|
listeners.set(key, set);
|
|
3806
|
-
const handler = () => setTick((
|
|
3822
|
+
const handler = () => setTick((t4) => t4 + 1);
|
|
3807
3823
|
set.add(handler);
|
|
3808
3824
|
return () => {
|
|
3809
3825
|
set.delete(handler);
|
|
@@ -5491,24 +5507,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
5491
5507
|
"yellow",
|
|
5492
5508
|
"orange"
|
|
5493
5509
|
].map((value) => ({ value, label: value }));
|
|
5494
|
-
var DEFAULT_PALETTE = [
|
|
5495
|
-
"#f0f4ff",
|
|
5496
|
-
"#d9e3ff",
|
|
5497
|
-
"#bfcfff",
|
|
5498
|
-
"#a6bbff",
|
|
5499
|
-
"#8ca7ff",
|
|
5500
|
-
"#7393ff",
|
|
5501
|
-
"#5a7fff",
|
|
5502
|
-
"#406bff",
|
|
5503
|
-
"#2547ff",
|
|
5504
|
-
"#0b33ff"
|
|
5505
|
-
];
|
|
5506
|
-
var DEFAULT_VALUE = {
|
|
5507
|
-
useOverride: false,
|
|
5508
|
-
primaryColor: "dirk",
|
|
5509
|
-
primaryShade: 5,
|
|
5510
|
-
customTheme: DEFAULT_PALETTE
|
|
5511
|
-
};
|
|
5512
5510
|
function GroupLabel({ label }) {
|
|
5513
5511
|
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
5514
5512
|
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label }),
|
|
@@ -5523,10 +5521,10 @@ function ThemeOverrideSection({
|
|
|
5523
5521
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
5524
5522
|
const raw = useFormField(schemaKey);
|
|
5525
5523
|
const value = {
|
|
5526
|
-
useOverride: raw?.useOverride ??
|
|
5527
|
-
primaryColor: raw?.primaryColor ??
|
|
5528
|
-
primaryShade: raw?.primaryShade ??
|
|
5529
|
-
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme :
|
|
5524
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
5525
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
5526
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
5527
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
5530
5528
|
};
|
|
5531
5529
|
const { setValue } = useFormActions();
|
|
5532
5530
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -5733,6 +5731,403 @@ function SwatchTile({
|
|
|
5733
5731
|
) })
|
|
5734
5732
|
] });
|
|
5735
5733
|
}
|
|
5734
|
+
function usePlayers(opts = {}) {
|
|
5735
|
+
const {
|
|
5736
|
+
includeOffline = false,
|
|
5737
|
+
search = "",
|
|
5738
|
+
limit = 50,
|
|
5739
|
+
staleTimeMs,
|
|
5740
|
+
refetchIntervalMs
|
|
5741
|
+
} = opts;
|
|
5742
|
+
const query = useQuery({
|
|
5743
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
5744
|
+
queryFn: async () => {
|
|
5745
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
5746
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
5747
|
+
const result = await fetchNui(
|
|
5748
|
+
"ADMIN_TOOL_QUERY",
|
|
5749
|
+
payload,
|
|
5750
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
5751
|
+
// dev shell isn't blank.
|
|
5752
|
+
includeOffline ? [
|
|
5753
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
5754
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
5755
|
+
] : [
|
|
5756
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
5757
|
+
]
|
|
5758
|
+
);
|
|
5759
|
+
return Array.isArray(result) ? result : [];
|
|
5760
|
+
},
|
|
5761
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
5762
|
+
gcTime: 5 * 6e4,
|
|
5763
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
5764
|
+
refetchOnWindowFocus: false,
|
|
5765
|
+
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
5766
|
+
});
|
|
5767
|
+
return {
|
|
5768
|
+
players: query.data ?? [],
|
|
5769
|
+
isLoading: query.isLoading,
|
|
5770
|
+
isFetching: query.isFetching,
|
|
5771
|
+
error: query.error ?? null,
|
|
5772
|
+
refresh: () => query.refetch()
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
var DEBOUNCE_MS = 300;
|
|
5776
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
5777
|
+
var OFFLINE_COLOR = "#E54141";
|
|
5778
|
+
function PlayerSelect({
|
|
5779
|
+
value,
|
|
5780
|
+
onChange,
|
|
5781
|
+
includeOffline = false,
|
|
5782
|
+
limit = 50,
|
|
5783
|
+
searchable: searchableProp,
|
|
5784
|
+
placeholder,
|
|
5785
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
5786
|
+
loadingLabel = "Loading\u2026",
|
|
5787
|
+
onlineLabel = "Online",
|
|
5788
|
+
offlineLabel = "Offline",
|
|
5789
|
+
refreshLabel = "Refresh player list",
|
|
5790
|
+
...rest
|
|
5791
|
+
}) {
|
|
5792
|
+
const theme = useMantineTheme();
|
|
5793
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
5794
|
+
const [searchInput, setSearchInput] = useState("");
|
|
5795
|
+
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
5796
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
5797
|
+
includeOffline,
|
|
5798
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
5799
|
+
limit
|
|
5800
|
+
});
|
|
5801
|
+
const sortedPlayers = useMemo(
|
|
5802
|
+
() => [...players].sort((a, b) => {
|
|
5803
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
5804
|
+
return a.charName.localeCompare(b.charName);
|
|
5805
|
+
}),
|
|
5806
|
+
[players]
|
|
5807
|
+
);
|
|
5808
|
+
const playerByCitizen = useMemo(() => {
|
|
5809
|
+
const m = /* @__PURE__ */ new Map();
|
|
5810
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
5811
|
+
return m;
|
|
5812
|
+
}, [sortedPlayers]);
|
|
5813
|
+
const data = useMemo(() => {
|
|
5814
|
+
const items = sortedPlayers.map((p) => ({
|
|
5815
|
+
value: p.citizenId,
|
|
5816
|
+
label: formatLabel(p)
|
|
5817
|
+
}));
|
|
5818
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
5819
|
+
items.unshift({ value, label: value });
|
|
5820
|
+
}
|
|
5821
|
+
return items;
|
|
5822
|
+
}, [sortedPlayers, value]);
|
|
5823
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
5824
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
5825
|
+
useEffect(() => {
|
|
5826
|
+
if (!includeOffline) return;
|
|
5827
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
5828
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
5829
|
+
return () => clearTimeout(t4);
|
|
5830
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
5831
|
+
const renderOption = ({ option }) => {
|
|
5832
|
+
const p = playerByCitizen.get(option.value);
|
|
5833
|
+
if (!p) return option.label;
|
|
5834
|
+
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
5835
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
5836
|
+
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
5837
|
+
] });
|
|
5838
|
+
};
|
|
5839
|
+
return /* @__PURE__ */ jsx(
|
|
5840
|
+
Select,
|
|
5841
|
+
{
|
|
5842
|
+
...rest,
|
|
5843
|
+
data,
|
|
5844
|
+
value: value ?? null,
|
|
5845
|
+
onChange: (v) => {
|
|
5846
|
+
if (!v) return onChange(null);
|
|
5847
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
5848
|
+
onChange(player);
|
|
5849
|
+
},
|
|
5850
|
+
searchable: searchableProp ?? true,
|
|
5851
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
5852
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
5853
|
+
placeholder,
|
|
5854
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
5855
|
+
maxDropdownHeight: 300,
|
|
5856
|
+
renderOption,
|
|
5857
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
5858
|
+
rightSectionWidth: "3.5vh",
|
|
5859
|
+
rightSectionPointerEvents: "all",
|
|
5860
|
+
rightSection: /* @__PURE__ */ jsx(
|
|
5861
|
+
ActionIcon,
|
|
5862
|
+
{
|
|
5863
|
+
variant: "subtle",
|
|
5864
|
+
size: "sm",
|
|
5865
|
+
onClick: (e) => {
|
|
5866
|
+
e.stopPropagation();
|
|
5867
|
+
refresh();
|
|
5868
|
+
},
|
|
5869
|
+
"aria-label": refreshLabel,
|
|
5870
|
+
title: refreshLabel,
|
|
5871
|
+
style: { marginRight: "0.6vh" },
|
|
5872
|
+
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
5873
|
+
}
|
|
5874
|
+
)
|
|
5875
|
+
}
|
|
5876
|
+
);
|
|
5877
|
+
}
|
|
5878
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
5879
|
+
return /* @__PURE__ */ jsx(
|
|
5880
|
+
"span",
|
|
5881
|
+
{
|
|
5882
|
+
title: online ? onlineLabel : offlineLabel,
|
|
5883
|
+
style: {
|
|
5884
|
+
display: "inline-block",
|
|
5885
|
+
width: "0.9vh",
|
|
5886
|
+
height: "0.9vh",
|
|
5887
|
+
borderRadius: "50%",
|
|
5888
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
5889
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
5890
|
+
flexShrink: 0
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
);
|
|
5894
|
+
}
|
|
5895
|
+
function formatLabel(p) {
|
|
5896
|
+
const parts = [p.charName || p.citizenId];
|
|
5897
|
+
if (p.online) {
|
|
5898
|
+
if (p.name) parts.push(p.name);
|
|
5899
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
5900
|
+
}
|
|
5901
|
+
return parts.join(" \xB7 ");
|
|
5902
|
+
}
|
|
5903
|
+
var t = (key, fallback) => {
|
|
5904
|
+
const v = locale(key);
|
|
5905
|
+
return v === key ? fallback : v;
|
|
5906
|
+
};
|
|
5907
|
+
var DEFAULT_VALUE = {
|
|
5908
|
+
groups: [],
|
|
5909
|
+
identifiers: []
|
|
5910
|
+
};
|
|
5911
|
+
function SectionLabel({ icon: Icon, label }) {
|
|
5912
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
5913
|
+
/* @__PURE__ */ jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
5914
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label }),
|
|
5915
|
+
/* @__PURE__ */ jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
5916
|
+
] });
|
|
5917
|
+
}
|
|
5918
|
+
function EmptyHint({ text }) {
|
|
5919
|
+
return /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
5920
|
+
}
|
|
5921
|
+
function AccessOverrideSection({
|
|
5922
|
+
schemaKey = "access",
|
|
5923
|
+
title,
|
|
5924
|
+
description,
|
|
5925
|
+
groupType,
|
|
5926
|
+
includeOffline = true
|
|
5927
|
+
}) {
|
|
5928
|
+
const mantineTheme = useMantineTheme();
|
|
5929
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
5930
|
+
const raw = useFormField(schemaKey);
|
|
5931
|
+
const value = {
|
|
5932
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
5933
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
5934
|
+
};
|
|
5935
|
+
const { setValue } = useFormActions();
|
|
5936
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
5937
|
+
const [addingGroup, setAddingGroup] = useState(false);
|
|
5938
|
+
const [addingPlayer, setAddingPlayer] = useState(false);
|
|
5939
|
+
const commitGroup = (name) => {
|
|
5940
|
+
if (!name) return;
|
|
5941
|
+
set("groups", [...value.groups, name]);
|
|
5942
|
+
setAddingGroup(false);
|
|
5943
|
+
};
|
|
5944
|
+
const setGroup = (index, name) => {
|
|
5945
|
+
const next = [...value.groups];
|
|
5946
|
+
next[index] = name;
|
|
5947
|
+
set("groups", next.filter((g) => g !== ""));
|
|
5948
|
+
};
|
|
5949
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
5950
|
+
const commitIdentifier = (id) => {
|
|
5951
|
+
if (!id) return;
|
|
5952
|
+
set("identifiers", [...value.identifiers, id]);
|
|
5953
|
+
setAddingPlayer(false);
|
|
5954
|
+
};
|
|
5955
|
+
const setIdentifier = (index, id) => {
|
|
5956
|
+
const next = [...value.identifiers];
|
|
5957
|
+
next[index] = id;
|
|
5958
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
5959
|
+
};
|
|
5960
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
5961
|
+
return /* @__PURE__ */ jsxs(
|
|
5962
|
+
Flex,
|
|
5963
|
+
{
|
|
5964
|
+
direction: "column",
|
|
5965
|
+
gap: "xs",
|
|
5966
|
+
p: "sm",
|
|
5967
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
5968
|
+
children: [
|
|
5969
|
+
/* @__PURE__ */ jsx(
|
|
5970
|
+
AdminPageTitle,
|
|
5971
|
+
{
|
|
5972
|
+
icon: ShieldCheck,
|
|
5973
|
+
title: title || t("Access", "Access"),
|
|
5974
|
+
color
|
|
5975
|
+
}
|
|
5976
|
+
),
|
|
5977
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description || t(
|
|
5978
|
+
"AccessOverrideDesc",
|
|
5979
|
+
"Grant access to this resource's admin panel to specific groups and players, in addition to your global dirk_lib admins. Enforcement is server-side."
|
|
5980
|
+
) }),
|
|
5981
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: Users, label: t("AccessGroups", "Groups") }),
|
|
5982
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
5983
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsx(EmptyHint, { text: t("AccessNoGroups", "No groups added.") }),
|
|
5984
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
5985
|
+
/* @__PURE__ */ jsx(
|
|
5986
|
+
GroupName,
|
|
5987
|
+
{
|
|
5988
|
+
value: name,
|
|
5989
|
+
onChange: (v) => setGroup(i, v),
|
|
5990
|
+
type: groupType,
|
|
5991
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
5992
|
+
style: { flex: 1 }
|
|
5993
|
+
}
|
|
5994
|
+
),
|
|
5995
|
+
/* @__PURE__ */ jsx(
|
|
5996
|
+
ActionIcon,
|
|
5997
|
+
{
|
|
5998
|
+
variant: "subtle",
|
|
5999
|
+
color: "red",
|
|
6000
|
+
size: "md",
|
|
6001
|
+
onClick: () => removeGroup(i),
|
|
6002
|
+
title: t("Remove", "Remove"),
|
|
6003
|
+
"aria-label": t("Remove", "Remove"),
|
|
6004
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
6005
|
+
}
|
|
6006
|
+
)
|
|
6007
|
+
] }, i)),
|
|
6008
|
+
addingGroup && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
6009
|
+
/* @__PURE__ */ jsx(
|
|
6010
|
+
GroupName,
|
|
6011
|
+
{
|
|
6012
|
+
value: "",
|
|
6013
|
+
onChange: (v) => commitGroup(v),
|
|
6014
|
+
type: groupType,
|
|
6015
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
6016
|
+
style: { flex: 1 }
|
|
6017
|
+
}
|
|
6018
|
+
),
|
|
6019
|
+
/* @__PURE__ */ jsx(
|
|
6020
|
+
ActionIcon,
|
|
6021
|
+
{
|
|
6022
|
+
variant: "subtle",
|
|
6023
|
+
color: "red",
|
|
6024
|
+
size: "md",
|
|
6025
|
+
onClick: () => setAddingGroup(false),
|
|
6026
|
+
title: t("Remove", "Remove"),
|
|
6027
|
+
"aria-label": t("Remove", "Remove"),
|
|
6028
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
6029
|
+
}
|
|
6030
|
+
)
|
|
6031
|
+
] })
|
|
6032
|
+
] }),
|
|
6033
|
+
!addingGroup && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
6034
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: UserRound, label: t("AccessPlayers", "Players") }),
|
|
6035
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
6036
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
6037
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
6038
|
+
/* @__PURE__ */ jsx(
|
|
6039
|
+
PlayerSelect,
|
|
6040
|
+
{
|
|
6041
|
+
value: id || null,
|
|
6042
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
6043
|
+
includeOffline,
|
|
6044
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
6045
|
+
style: { flex: 1 },
|
|
6046
|
+
size: "xs"
|
|
6047
|
+
}
|
|
6048
|
+
),
|
|
6049
|
+
/* @__PURE__ */ jsx(
|
|
6050
|
+
ActionIcon,
|
|
6051
|
+
{
|
|
6052
|
+
variant: "subtle",
|
|
6053
|
+
color: "red",
|
|
6054
|
+
size: "md",
|
|
6055
|
+
onClick: () => removeIdentifier(i),
|
|
6056
|
+
title: t("Remove", "Remove"),
|
|
6057
|
+
"aria-label": t("Remove", "Remove"),
|
|
6058
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
6059
|
+
}
|
|
6060
|
+
)
|
|
6061
|
+
] }, i)),
|
|
6062
|
+
addingPlayer && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
6063
|
+
/* @__PURE__ */ jsx(
|
|
6064
|
+
PlayerSelect,
|
|
6065
|
+
{
|
|
6066
|
+
value: null,
|
|
6067
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
6068
|
+
includeOffline,
|
|
6069
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
6070
|
+
style: { flex: 1 },
|
|
6071
|
+
size: "xs"
|
|
6072
|
+
}
|
|
6073
|
+
),
|
|
6074
|
+
/* @__PURE__ */ jsx(
|
|
6075
|
+
ActionIcon,
|
|
6076
|
+
{
|
|
6077
|
+
variant: "subtle",
|
|
6078
|
+
color: "red",
|
|
6079
|
+
size: "md",
|
|
6080
|
+
onClick: () => setAddingPlayer(false),
|
|
6081
|
+
title: t("Remove", "Remove"),
|
|
6082
|
+
"aria-label": t("Remove", "Remove"),
|
|
6083
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
6084
|
+
}
|
|
6085
|
+
)
|
|
6086
|
+
] })
|
|
6087
|
+
] }),
|
|
6088
|
+
!addingPlayer && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
6089
|
+
]
|
|
6090
|
+
}
|
|
6091
|
+
);
|
|
6092
|
+
}
|
|
6093
|
+
function AddRowButton({ label, onClick }) {
|
|
6094
|
+
return /* @__PURE__ */ jsxs(
|
|
6095
|
+
Flex,
|
|
6096
|
+
{
|
|
6097
|
+
align: "center",
|
|
6098
|
+
justify: "center",
|
|
6099
|
+
gap: "xs",
|
|
6100
|
+
onClick,
|
|
6101
|
+
role: "button",
|
|
6102
|
+
tabIndex: 0,
|
|
6103
|
+
onKeyDown: (e) => {
|
|
6104
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
6105
|
+
e.preventDefault();
|
|
6106
|
+
onClick();
|
|
6107
|
+
}
|
|
6108
|
+
},
|
|
6109
|
+
py: "xs",
|
|
6110
|
+
style: {
|
|
6111
|
+
cursor: "pointer",
|
|
6112
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
6113
|
+
borderRadius: "0.4vh",
|
|
6114
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
6115
|
+
},
|
|
6116
|
+
onMouseEnter: (e) => {
|
|
6117
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
6118
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
6119
|
+
},
|
|
6120
|
+
onMouseLeave: (e) => {
|
|
6121
|
+
e.currentTarget.style.background = "transparent";
|
|
6122
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
6123
|
+
},
|
|
6124
|
+
children: [
|
|
6125
|
+
/* @__PURE__ */ jsx(Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
6126
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label })
|
|
6127
|
+
]
|
|
6128
|
+
}
|
|
6129
|
+
);
|
|
6130
|
+
}
|
|
5736
6131
|
|
|
5737
6132
|
// src/utils/gtaAnimPostFx.ts
|
|
5738
6133
|
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
@@ -6322,7 +6717,7 @@ function ScenarioSelect({
|
|
|
6322
6717
|
}
|
|
6323
6718
|
);
|
|
6324
6719
|
}
|
|
6325
|
-
var
|
|
6720
|
+
var t2 = (key, fallback) => {
|
|
6326
6721
|
const v = locale(key);
|
|
6327
6722
|
return v === key ? fallback : v;
|
|
6328
6723
|
};
|
|
@@ -6390,7 +6785,7 @@ function DiscordRoleSelect(props) {
|
|
|
6390
6785
|
return map;
|
|
6391
6786
|
}, [roles]);
|
|
6392
6787
|
if (errorCode === "NotConfigured") {
|
|
6393
|
-
const notConfiguredPlaceholder =
|
|
6788
|
+
const notConfiguredPlaceholder = t2(
|
|
6394
6789
|
"DiscordNotConfigured",
|
|
6395
6790
|
"Not configured \u2014 set in /dirk_lib"
|
|
6396
6791
|
);
|
|
@@ -6458,9 +6853,9 @@ function DiscordRoleSelect(props) {
|
|
|
6458
6853
|
e.stopPropagation();
|
|
6459
6854
|
refresh();
|
|
6460
6855
|
},
|
|
6461
|
-
title:
|
|
6856
|
+
title: t2("Refresh", "Refresh"),
|
|
6462
6857
|
loading,
|
|
6463
|
-
"aria-label":
|
|
6858
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
6464
6859
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
6465
6860
|
}
|
|
6466
6861
|
);
|
|
@@ -6470,7 +6865,7 @@ function DiscordRoleSelect(props) {
|
|
|
6470
6865
|
{
|
|
6471
6866
|
label,
|
|
6472
6867
|
size,
|
|
6473
|
-
placeholder: placeholder ||
|
|
6868
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
6474
6869
|
data,
|
|
6475
6870
|
value: props.value || [],
|
|
6476
6871
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -6482,7 +6877,7 @@ function DiscordRoleSelect(props) {
|
|
|
6482
6877
|
rightSectionPointerEvents: "all",
|
|
6483
6878
|
style,
|
|
6484
6879
|
styles,
|
|
6485
|
-
nothingFoundMessage: errorCode ? `${
|
|
6880
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
6486
6881
|
}
|
|
6487
6882
|
);
|
|
6488
6883
|
}
|
|
@@ -6491,7 +6886,7 @@ function DiscordRoleSelect(props) {
|
|
|
6491
6886
|
{
|
|
6492
6887
|
label,
|
|
6493
6888
|
size,
|
|
6494
|
-
placeholder: placeholder ||
|
|
6889
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
6495
6890
|
data,
|
|
6496
6891
|
value: props.value || null,
|
|
6497
6892
|
onChange: (id) => props.onChange(id),
|
|
@@ -6503,11 +6898,11 @@ function DiscordRoleSelect(props) {
|
|
|
6503
6898
|
rightSectionPointerEvents: "all",
|
|
6504
6899
|
style,
|
|
6505
6900
|
styles,
|
|
6506
|
-
nothingFoundMessage: errorCode ? `${
|
|
6901
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
6507
6902
|
}
|
|
6508
6903
|
);
|
|
6509
6904
|
}
|
|
6510
|
-
var
|
|
6905
|
+
var t3 = (key, fallback) => {
|
|
6511
6906
|
const v = locale(key);
|
|
6512
6907
|
return v === key ? fallback : v;
|
|
6513
6908
|
};
|
|
@@ -6528,7 +6923,7 @@ function FrameworkHint({ framework }) {
|
|
|
6528
6923
|
const theme = useMantineTheme();
|
|
6529
6924
|
if (!framework) return null;
|
|
6530
6925
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
6531
|
-
const text =
|
|
6926
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
6532
6927
|
return /* @__PURE__ */ jsxs(
|
|
6533
6928
|
Flex,
|
|
6534
6929
|
{
|
|
@@ -6612,9 +7007,9 @@ function AccountSelect(props) {
|
|
|
6612
7007
|
e.stopPropagation();
|
|
6613
7008
|
refresh();
|
|
6614
7009
|
},
|
|
6615
|
-
title:
|
|
7010
|
+
title: t3("Refresh", "Refresh"),
|
|
6616
7011
|
loading,
|
|
6617
|
-
"aria-label":
|
|
7012
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
6618
7013
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
6619
7014
|
}
|
|
6620
7015
|
);
|
|
@@ -6628,14 +7023,14 @@ function AccountSelect(props) {
|
|
|
6628
7023
|
rightSection: refreshButton,
|
|
6629
7024
|
rightSectionPointerEvents: "all",
|
|
6630
7025
|
style,
|
|
6631
|
-
nothingFoundMessage:
|
|
7026
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
6632
7027
|
};
|
|
6633
7028
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
6634
7029
|
props.multi ? /* @__PURE__ */ jsx(
|
|
6635
7030
|
MultiSelect,
|
|
6636
7031
|
{
|
|
6637
7032
|
...sharedSelectProps,
|
|
6638
|
-
placeholder: placeholder ||
|
|
7033
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
6639
7034
|
value: props.value || [],
|
|
6640
7035
|
onChange: (names) => props.onChange(names),
|
|
6641
7036
|
renderOption,
|
|
@@ -6647,7 +7042,7 @@ function AccountSelect(props) {
|
|
|
6647
7042
|
Select,
|
|
6648
7043
|
{
|
|
6649
7044
|
...sharedSelectProps,
|
|
6650
|
-
placeholder: placeholder ||
|
|
7045
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
6651
7046
|
value: props.value || null,
|
|
6652
7047
|
onChange: (name) => props.onChange(name),
|
|
6653
7048
|
renderOption,
|
|
@@ -6939,175 +7334,6 @@ function WorldPositionGotoButton2({
|
|
|
6939
7334
|
}
|
|
6940
7335
|
) });
|
|
6941
7336
|
}
|
|
6942
|
-
function usePlayers(opts = {}) {
|
|
6943
|
-
const {
|
|
6944
|
-
includeOffline = false,
|
|
6945
|
-
search = "",
|
|
6946
|
-
limit = 50,
|
|
6947
|
-
staleTimeMs,
|
|
6948
|
-
refetchIntervalMs
|
|
6949
|
-
} = opts;
|
|
6950
|
-
const query = useQuery({
|
|
6951
|
-
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6952
|
-
queryFn: async () => {
|
|
6953
|
-
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6954
|
-
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6955
|
-
const result = await fetchNui(
|
|
6956
|
-
"ADMIN_TOOL_QUERY",
|
|
6957
|
-
payload,
|
|
6958
|
-
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6959
|
-
// dev shell isn't blank.
|
|
6960
|
-
includeOffline ? [
|
|
6961
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6962
|
-
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6963
|
-
] : [
|
|
6964
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6965
|
-
]
|
|
6966
|
-
);
|
|
6967
|
-
return Array.isArray(result) ? result : [];
|
|
6968
|
-
},
|
|
6969
|
-
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6970
|
-
gcTime: 5 * 6e4,
|
|
6971
|
-
refetchInterval: refetchIntervalMs ?? false,
|
|
6972
|
-
refetchOnWindowFocus: false,
|
|
6973
|
-
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
6974
|
-
});
|
|
6975
|
-
return {
|
|
6976
|
-
players: query.data ?? [],
|
|
6977
|
-
isLoading: query.isLoading,
|
|
6978
|
-
isFetching: query.isFetching,
|
|
6979
|
-
error: query.error ?? null,
|
|
6980
|
-
refresh: () => query.refetch()
|
|
6981
|
-
};
|
|
6982
|
-
}
|
|
6983
|
-
var DEBOUNCE_MS = 300;
|
|
6984
|
-
var ONLINE_COLOR = "#3FA83F";
|
|
6985
|
-
var OFFLINE_COLOR = "#E54141";
|
|
6986
|
-
function PlayerSelect({
|
|
6987
|
-
value,
|
|
6988
|
-
onChange,
|
|
6989
|
-
includeOffline = false,
|
|
6990
|
-
limit = 50,
|
|
6991
|
-
searchable: searchableProp,
|
|
6992
|
-
placeholder,
|
|
6993
|
-
nothingFoundMessage: nothingFoundMessageProp,
|
|
6994
|
-
loadingLabel = "Loading\u2026",
|
|
6995
|
-
onlineLabel = "Online",
|
|
6996
|
-
offlineLabel = "Offline",
|
|
6997
|
-
refreshLabel = "Refresh player list",
|
|
6998
|
-
...rest
|
|
6999
|
-
}) {
|
|
7000
|
-
const theme = useMantineTheme();
|
|
7001
|
-
const color = theme.colors[theme.primaryColor][5];
|
|
7002
|
-
const [searchInput, setSearchInput] = useState("");
|
|
7003
|
-
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
7004
|
-
const { players, isFetching, refresh } = usePlayers({
|
|
7005
|
-
includeOffline,
|
|
7006
|
-
search: includeOffline ? debouncedSearch : void 0,
|
|
7007
|
-
limit
|
|
7008
|
-
});
|
|
7009
|
-
const sortedPlayers = useMemo(
|
|
7010
|
-
() => [...players].sort((a, b) => {
|
|
7011
|
-
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
7012
|
-
return a.charName.localeCompare(b.charName);
|
|
7013
|
-
}),
|
|
7014
|
-
[players]
|
|
7015
|
-
);
|
|
7016
|
-
const playerByCitizen = useMemo(() => {
|
|
7017
|
-
const m = /* @__PURE__ */ new Map();
|
|
7018
|
-
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
7019
|
-
return m;
|
|
7020
|
-
}, [sortedPlayers]);
|
|
7021
|
-
const data = useMemo(() => {
|
|
7022
|
-
const items = sortedPlayers.map((p) => ({
|
|
7023
|
-
value: p.citizenId,
|
|
7024
|
-
label: formatLabel(p)
|
|
7025
|
-
}));
|
|
7026
|
-
if (value && !items.some((i) => i.value === value)) {
|
|
7027
|
-
items.unshift({ value, label: value });
|
|
7028
|
-
}
|
|
7029
|
-
return items;
|
|
7030
|
-
}, [sortedPlayers, value]);
|
|
7031
|
-
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
7032
|
-
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
7033
|
-
useEffect(() => {
|
|
7034
|
-
if (!includeOffline) return;
|
|
7035
|
-
if (selectedLabel && searchInput === selectedLabel) return;
|
|
7036
|
-
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
7037
|
-
return () => clearTimeout(t3);
|
|
7038
|
-
}, [searchInput, includeOffline, selectedLabel]);
|
|
7039
|
-
const renderOption = ({ option }) => {
|
|
7040
|
-
const p = playerByCitizen.get(option.value);
|
|
7041
|
-
if (!p) return option.label;
|
|
7042
|
-
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
7043
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
7044
|
-
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
7045
|
-
] });
|
|
7046
|
-
};
|
|
7047
|
-
return /* @__PURE__ */ jsx(
|
|
7048
|
-
Select,
|
|
7049
|
-
{
|
|
7050
|
-
...rest,
|
|
7051
|
-
data,
|
|
7052
|
-
value: value ?? null,
|
|
7053
|
-
onChange: (v) => {
|
|
7054
|
-
if (!v) return onChange(null);
|
|
7055
|
-
const player = playerByCitizen.get(v) ?? null;
|
|
7056
|
-
onChange(player);
|
|
7057
|
-
},
|
|
7058
|
-
searchable: searchableProp ?? true,
|
|
7059
|
-
searchValue: includeOffline ? searchInput : void 0,
|
|
7060
|
-
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
7061
|
-
placeholder,
|
|
7062
|
-
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
7063
|
-
maxDropdownHeight: 300,
|
|
7064
|
-
renderOption,
|
|
7065
|
-
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
7066
|
-
rightSectionWidth: "3.5vh",
|
|
7067
|
-
rightSectionPointerEvents: "all",
|
|
7068
|
-
rightSection: /* @__PURE__ */ jsx(
|
|
7069
|
-
ActionIcon,
|
|
7070
|
-
{
|
|
7071
|
-
variant: "subtle",
|
|
7072
|
-
size: "sm",
|
|
7073
|
-
onClick: (e) => {
|
|
7074
|
-
e.stopPropagation();
|
|
7075
|
-
refresh();
|
|
7076
|
-
},
|
|
7077
|
-
"aria-label": refreshLabel,
|
|
7078
|
-
title: refreshLabel,
|
|
7079
|
-
style: { marginRight: "0.6vh" },
|
|
7080
|
-
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
7081
|
-
}
|
|
7082
|
-
)
|
|
7083
|
-
}
|
|
7084
|
-
);
|
|
7085
|
-
}
|
|
7086
|
-
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7087
|
-
return /* @__PURE__ */ jsx(
|
|
7088
|
-
"span",
|
|
7089
|
-
{
|
|
7090
|
-
title: online ? onlineLabel : offlineLabel,
|
|
7091
|
-
style: {
|
|
7092
|
-
display: "inline-block",
|
|
7093
|
-
width: "0.9vh",
|
|
7094
|
-
height: "0.9vh",
|
|
7095
|
-
borderRadius: "50%",
|
|
7096
|
-
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7097
|
-
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7098
|
-
flexShrink: 0
|
|
7099
|
-
}
|
|
7100
|
-
}
|
|
7101
|
-
);
|
|
7102
|
-
}
|
|
7103
|
-
function formatLabel(p) {
|
|
7104
|
-
const parts = [p.charName || p.citizenId];
|
|
7105
|
-
if (p.online) {
|
|
7106
|
-
if (p.name) parts.push(p.name);
|
|
7107
|
-
if (p.id != null) parts.push(`#${p.id}`);
|
|
7108
|
-
}
|
|
7109
|
-
return parts.join(" \xB7 ");
|
|
7110
|
-
}
|
|
7111
7337
|
function usePickDoor() {
|
|
7112
7338
|
const begin = useAdminToolStore((s) => s.begin);
|
|
7113
7339
|
return async () => {
|
|
@@ -7384,6 +7610,6 @@ function BlipMarker({
|
|
|
7384
7610
|
);
|
|
7385
7611
|
}
|
|
7386
7612
|
|
|
7387
|
-
export { AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BlipMarker, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DiscordRoleSelect, DoorPickerButton, FiveMKeyBindInput, FloatingParticles, GroupName, GroupRank, GroupSelect, InfoBox, InputContainer, InstructionPanel, LevelBanner, LevelPanel, Map2 as Map, MapLayer, MissingItemsBanner, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PlayerSelect, PositionPicker, PromptModal, ScenarioSelect, SegmentedControl, SegmentedProgress, SelectItem, SwitchPanel, TestBed, ThemeOverrideSection, Title, Vector4DeleteButton, Vector4Display, WorldPositionGotoButton, WorldPositionPicker, WorldPositionSetButton, ZoomControls, blipUrl, blipUrlForSprite, getBlipColor, getBlipEntry, useAdminToolStore, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, usePickDoor };
|
|
7613
|
+
export { AccessOverrideSection, AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BlipMarker, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DiscordRoleSelect, DoorPickerButton, FiveMKeyBindInput, FloatingParticles, GroupName, GroupRank, GroupSelect, InfoBox, InputContainer, InstructionPanel, LevelBanner, LevelPanel, Map2 as Map, MapLayer, MissingItemsBanner, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PlayerSelect, PositionPicker, PromptModal, ScenarioSelect, SegmentedControl, SegmentedProgress, SelectItem, SwitchPanel, TestBed, ThemeOverrideSection, Title, Vector4DeleteButton, Vector4Display, WorldPositionGotoButton, WorldPositionPicker, WorldPositionSetButton, ZoomControls, blipUrl, blipUrlForSprite, getBlipColor, getBlipEntry, useAdminToolStore, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, usePickDoor };
|
|
7388
7614
|
//# sourceMappingURL=index.js.map
|
|
7389
7615
|
//# sourceMappingURL=index.js.map
|