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/index.js
CHANGED
|
@@ -2,10 +2,11 @@ import { Flex, Text, Image as Image$1, createTheme, alpha, Box, Stack, Title as
|
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import React4, { createContext, memo, useRef, useEffect, useContext, useState, useCallback, useMemo, useLayoutEffect } from 'react';
|
|
4
4
|
import { create, useStore, createStore } from 'zustand';
|
|
5
|
+
import { z } from 'zod';
|
|
5
6
|
import axios from 'axios';
|
|
6
7
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
7
8
|
import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
|
|
8
|
-
import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, Palette,
|
|
9
|
+
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';
|
|
9
10
|
import clickSoundUrl from './click_sound-PNCRRTM4.mp3';
|
|
10
11
|
import hoverSoundUrl from './hover_sound-NBUA222C.mp3';
|
|
11
12
|
import { notifications } from '@mantine/notifications';
|
|
@@ -26,7 +27,6 @@ import { CRS, tileLayer, latLngBounds, latLng } from 'leaflet';
|
|
|
26
27
|
import 'leaflet/dist/leaflet.css';
|
|
27
28
|
import { MapContainer, useMap } from 'react-leaflet';
|
|
28
29
|
import { Marker } from '@adamscybot/react-leaflet-component-marker';
|
|
29
|
-
import { z } from 'zod';
|
|
30
30
|
|
|
31
31
|
var __defProp = Object.defineProperty;
|
|
32
32
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -1312,6 +1312,32 @@ var openLink = (url) => {
|
|
|
1312
1312
|
window.invokeNative("openLink", url);
|
|
1313
1313
|
}
|
|
1314
1314
|
};
|
|
1315
|
+
var DEFAULT_PALETTE = [
|
|
1316
|
+
"#f0f4ff",
|
|
1317
|
+
"#d9e3ff",
|
|
1318
|
+
"#bfcfff",
|
|
1319
|
+
"#a6bbff",
|
|
1320
|
+
"#8ca7ff",
|
|
1321
|
+
"#7393ff",
|
|
1322
|
+
"#5a7fff",
|
|
1323
|
+
"#406bff",
|
|
1324
|
+
"#2547ff",
|
|
1325
|
+
"#0b33ff"
|
|
1326
|
+
];
|
|
1327
|
+
var ThemeOverrideSchema = z.object({
|
|
1328
|
+
useOverride: z.boolean(),
|
|
1329
|
+
primaryColor: z.string(),
|
|
1330
|
+
primaryShade: z.number(),
|
|
1331
|
+
customTheme: z.array(z.string())
|
|
1332
|
+
});
|
|
1333
|
+
var defaultThemeOverride = {
|
|
1334
|
+
useOverride: false,
|
|
1335
|
+
primaryColor: "dirk",
|
|
1336
|
+
primaryShade: 5,
|
|
1337
|
+
customTheme: DEFAULT_PALETTE
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
// src/utils/useSettings.ts
|
|
1315
1341
|
var useSettings = create(() => ({
|
|
1316
1342
|
currency: "$",
|
|
1317
1343
|
game: "fivem",
|
|
@@ -1319,18 +1345,7 @@ var useSettings = create(() => ({
|
|
|
1319
1345
|
primaryShade: 9,
|
|
1320
1346
|
itemImgPath: "",
|
|
1321
1347
|
resourceVersion: "dev",
|
|
1322
|
-
customTheme:
|
|
1323
|
-
"#f0f4ff",
|
|
1324
|
-
"#d9e3ff",
|
|
1325
|
-
"#bfcfff",
|
|
1326
|
-
"#a6bbff",
|
|
1327
|
-
"#8ca7ff",
|
|
1328
|
-
"#7393ff",
|
|
1329
|
-
"#5a7fff",
|
|
1330
|
-
"#406bff",
|
|
1331
|
-
"#2547ff",
|
|
1332
|
-
"#0b33ff"
|
|
1333
|
-
]
|
|
1348
|
+
customTheme: DEFAULT_PALETTE
|
|
1334
1349
|
}));
|
|
1335
1350
|
|
|
1336
1351
|
// src/utils/fetchNui.ts
|
|
@@ -3742,11 +3757,11 @@ function ConfirmModal({
|
|
|
3742
3757
|
placeholder: confirmText,
|
|
3743
3758
|
value: typed,
|
|
3744
3759
|
onChange: (e) => setTyped(e.currentTarget.value),
|
|
3745
|
-
styles: (
|
|
3760
|
+
styles: (t4) => ({
|
|
3746
3761
|
input: {
|
|
3747
|
-
backgroundColor: alpha(
|
|
3762
|
+
backgroundColor: alpha(t4.colors.dark[7], 0.5),
|
|
3748
3763
|
border: `0.1vh solid ${alpha(
|
|
3749
|
-
typed === confirmText ? "#ef4444" :
|
|
3764
|
+
typed === confirmText ? "#ef4444" : t4.colors.dark[5],
|
|
3750
3765
|
0.5
|
|
3751
3766
|
)}`,
|
|
3752
3767
|
color: "rgba(255,255,255,0.85)",
|
|
@@ -4424,7 +4439,7 @@ function useAdminState(key, initial) {
|
|
|
4424
4439
|
useEffect(() => {
|
|
4425
4440
|
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
4426
4441
|
listeners.set(key, set);
|
|
4427
|
-
const handler = () => setTick((
|
|
4442
|
+
const handler = () => setTick((t4) => t4 + 1);
|
|
4428
4443
|
set.add(handler);
|
|
4429
4444
|
return () => {
|
|
4430
4445
|
set.delete(handler);
|
|
@@ -6604,24 +6619,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
6604
6619
|
"yellow",
|
|
6605
6620
|
"orange"
|
|
6606
6621
|
].map((value) => ({ value, label: value }));
|
|
6607
|
-
var DEFAULT_PALETTE = [
|
|
6608
|
-
"#f0f4ff",
|
|
6609
|
-
"#d9e3ff",
|
|
6610
|
-
"#bfcfff",
|
|
6611
|
-
"#a6bbff",
|
|
6612
|
-
"#8ca7ff",
|
|
6613
|
-
"#7393ff",
|
|
6614
|
-
"#5a7fff",
|
|
6615
|
-
"#406bff",
|
|
6616
|
-
"#2547ff",
|
|
6617
|
-
"#0b33ff"
|
|
6618
|
-
];
|
|
6619
|
-
var DEFAULT_VALUE = {
|
|
6620
|
-
useOverride: false,
|
|
6621
|
-
primaryColor: "dirk",
|
|
6622
|
-
primaryShade: 5,
|
|
6623
|
-
customTheme: DEFAULT_PALETTE
|
|
6624
|
-
};
|
|
6625
6622
|
function GroupLabel({ label: label2 }) {
|
|
6626
6623
|
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
6627
6624
|
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
@@ -6636,10 +6633,10 @@ function ThemeOverrideSection({
|
|
|
6636
6633
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
6637
6634
|
const raw = useFormField(schemaKey);
|
|
6638
6635
|
const value = {
|
|
6639
|
-
useOverride: raw?.useOverride ??
|
|
6640
|
-
primaryColor: raw?.primaryColor ??
|
|
6641
|
-
primaryShade: raw?.primaryShade ??
|
|
6642
|
-
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme :
|
|
6636
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
6637
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
6638
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
6639
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
6643
6640
|
};
|
|
6644
6641
|
const { setValue } = useFormActions();
|
|
6645
6642
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -6846,6 +6843,403 @@ function SwatchTile({
|
|
|
6846
6843
|
) })
|
|
6847
6844
|
] });
|
|
6848
6845
|
}
|
|
6846
|
+
function usePlayers(opts = {}) {
|
|
6847
|
+
const {
|
|
6848
|
+
includeOffline = false,
|
|
6849
|
+
search = "",
|
|
6850
|
+
limit = 50,
|
|
6851
|
+
staleTimeMs,
|
|
6852
|
+
refetchIntervalMs
|
|
6853
|
+
} = opts;
|
|
6854
|
+
const query = useQuery({
|
|
6855
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6856
|
+
queryFn: async () => {
|
|
6857
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6858
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6859
|
+
const result = await fetchNui(
|
|
6860
|
+
"ADMIN_TOOL_QUERY",
|
|
6861
|
+
payload,
|
|
6862
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6863
|
+
// dev shell isn't blank.
|
|
6864
|
+
includeOffline ? [
|
|
6865
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6866
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6867
|
+
] : [
|
|
6868
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6869
|
+
]
|
|
6870
|
+
);
|
|
6871
|
+
return Array.isArray(result) ? result : [];
|
|
6872
|
+
},
|
|
6873
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6874
|
+
gcTime: 5 * 6e4,
|
|
6875
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6876
|
+
refetchOnWindowFocus: false,
|
|
6877
|
+
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
6878
|
+
});
|
|
6879
|
+
return {
|
|
6880
|
+
players: query.data ?? [],
|
|
6881
|
+
isLoading: query.isLoading,
|
|
6882
|
+
isFetching: query.isFetching,
|
|
6883
|
+
error: query.error ?? null,
|
|
6884
|
+
refresh: () => query.refetch()
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6887
|
+
var DEBOUNCE_MS = 300;
|
|
6888
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6889
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6890
|
+
function PlayerSelect({
|
|
6891
|
+
value,
|
|
6892
|
+
onChange,
|
|
6893
|
+
includeOffline = false,
|
|
6894
|
+
limit = 50,
|
|
6895
|
+
searchable: searchableProp,
|
|
6896
|
+
placeholder,
|
|
6897
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
6898
|
+
loadingLabel = "Loading\u2026",
|
|
6899
|
+
onlineLabel = "Online",
|
|
6900
|
+
offlineLabel = "Offline",
|
|
6901
|
+
refreshLabel = "Refresh player list",
|
|
6902
|
+
...rest
|
|
6903
|
+
}) {
|
|
6904
|
+
const theme2 = useMantineTheme();
|
|
6905
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
6906
|
+
const [searchInput, setSearchInput] = useState("");
|
|
6907
|
+
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
6908
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
6909
|
+
includeOffline,
|
|
6910
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
6911
|
+
limit
|
|
6912
|
+
});
|
|
6913
|
+
const sortedPlayers = useMemo(
|
|
6914
|
+
() => [...players].sort((a, b) => {
|
|
6915
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
6916
|
+
return a.charName.localeCompare(b.charName);
|
|
6917
|
+
}),
|
|
6918
|
+
[players]
|
|
6919
|
+
);
|
|
6920
|
+
const playerByCitizen = useMemo(() => {
|
|
6921
|
+
const m = /* @__PURE__ */ new Map();
|
|
6922
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
6923
|
+
return m;
|
|
6924
|
+
}, [sortedPlayers]);
|
|
6925
|
+
const data = useMemo(() => {
|
|
6926
|
+
const items = sortedPlayers.map((p) => ({
|
|
6927
|
+
value: p.citizenId,
|
|
6928
|
+
label: formatLabel(p)
|
|
6929
|
+
}));
|
|
6930
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
6931
|
+
items.unshift({ value, label: value });
|
|
6932
|
+
}
|
|
6933
|
+
return items;
|
|
6934
|
+
}, [sortedPlayers, value]);
|
|
6935
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
6936
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
6937
|
+
useEffect(() => {
|
|
6938
|
+
if (!includeOffline) return;
|
|
6939
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
6940
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
6941
|
+
return () => clearTimeout(t4);
|
|
6942
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
6943
|
+
const renderOption = ({ option }) => {
|
|
6944
|
+
const p = playerByCitizen.get(option.value);
|
|
6945
|
+
if (!p) return option.label;
|
|
6946
|
+
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
6947
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
6948
|
+
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
6949
|
+
] });
|
|
6950
|
+
};
|
|
6951
|
+
return /* @__PURE__ */ jsx(
|
|
6952
|
+
Select,
|
|
6953
|
+
{
|
|
6954
|
+
...rest,
|
|
6955
|
+
data,
|
|
6956
|
+
value: value ?? null,
|
|
6957
|
+
onChange: (v) => {
|
|
6958
|
+
if (!v) return onChange(null);
|
|
6959
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
6960
|
+
onChange(player);
|
|
6961
|
+
},
|
|
6962
|
+
searchable: searchableProp ?? true,
|
|
6963
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
6964
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
6965
|
+
placeholder,
|
|
6966
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
6967
|
+
maxDropdownHeight: 300,
|
|
6968
|
+
renderOption,
|
|
6969
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
6970
|
+
rightSectionWidth: "3.5vh",
|
|
6971
|
+
rightSectionPointerEvents: "all",
|
|
6972
|
+
rightSection: /* @__PURE__ */ jsx(
|
|
6973
|
+
ActionIcon,
|
|
6974
|
+
{
|
|
6975
|
+
variant: "subtle",
|
|
6976
|
+
size: "sm",
|
|
6977
|
+
onClick: (e) => {
|
|
6978
|
+
e.stopPropagation();
|
|
6979
|
+
refresh();
|
|
6980
|
+
},
|
|
6981
|
+
"aria-label": refreshLabel,
|
|
6982
|
+
title: refreshLabel,
|
|
6983
|
+
style: { marginRight: "0.6vh" },
|
|
6984
|
+
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
6985
|
+
}
|
|
6986
|
+
)
|
|
6987
|
+
}
|
|
6988
|
+
);
|
|
6989
|
+
}
|
|
6990
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
6991
|
+
return /* @__PURE__ */ jsx(
|
|
6992
|
+
"span",
|
|
6993
|
+
{
|
|
6994
|
+
title: online ? onlineLabel : offlineLabel,
|
|
6995
|
+
style: {
|
|
6996
|
+
display: "inline-block",
|
|
6997
|
+
width: "0.9vh",
|
|
6998
|
+
height: "0.9vh",
|
|
6999
|
+
borderRadius: "50%",
|
|
7000
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7001
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7002
|
+
flexShrink: 0
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
);
|
|
7006
|
+
}
|
|
7007
|
+
function formatLabel(p) {
|
|
7008
|
+
const parts = [p.charName || p.citizenId];
|
|
7009
|
+
if (p.online) {
|
|
7010
|
+
if (p.name) parts.push(p.name);
|
|
7011
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7012
|
+
}
|
|
7013
|
+
return parts.join(" \xB7 ");
|
|
7014
|
+
}
|
|
7015
|
+
var t = (key, fallback) => {
|
|
7016
|
+
const v = locale(key);
|
|
7017
|
+
return v === key ? fallback : v;
|
|
7018
|
+
};
|
|
7019
|
+
var DEFAULT_VALUE = {
|
|
7020
|
+
groups: [],
|
|
7021
|
+
identifiers: []
|
|
7022
|
+
};
|
|
7023
|
+
function SectionLabel({ icon: Icon, label: label2 }) {
|
|
7024
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
7025
|
+
/* @__PURE__ */ jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
7026
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
7027
|
+
/* @__PURE__ */ jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
7028
|
+
] });
|
|
7029
|
+
}
|
|
7030
|
+
function EmptyHint({ text }) {
|
|
7031
|
+
return /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
7032
|
+
}
|
|
7033
|
+
function AccessOverrideSection({
|
|
7034
|
+
schemaKey = "access",
|
|
7035
|
+
title,
|
|
7036
|
+
description: description2,
|
|
7037
|
+
groupType,
|
|
7038
|
+
includeOffline = true
|
|
7039
|
+
}) {
|
|
7040
|
+
const mantineTheme = useMantineTheme();
|
|
7041
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
7042
|
+
const raw = useFormField(schemaKey);
|
|
7043
|
+
const value = {
|
|
7044
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
7045
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
7046
|
+
};
|
|
7047
|
+
const { setValue } = useFormActions();
|
|
7048
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
7049
|
+
const [addingGroup, setAddingGroup] = useState(false);
|
|
7050
|
+
const [addingPlayer, setAddingPlayer] = useState(false);
|
|
7051
|
+
const commitGroup = (name) => {
|
|
7052
|
+
if (!name) return;
|
|
7053
|
+
set("groups", [...value.groups, name]);
|
|
7054
|
+
setAddingGroup(false);
|
|
7055
|
+
};
|
|
7056
|
+
const setGroup = (index, name) => {
|
|
7057
|
+
const next = [...value.groups];
|
|
7058
|
+
next[index] = name;
|
|
7059
|
+
set("groups", next.filter((g) => g !== ""));
|
|
7060
|
+
};
|
|
7061
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
7062
|
+
const commitIdentifier = (id) => {
|
|
7063
|
+
if (!id) return;
|
|
7064
|
+
set("identifiers", [...value.identifiers, id]);
|
|
7065
|
+
setAddingPlayer(false);
|
|
7066
|
+
};
|
|
7067
|
+
const setIdentifier = (index, id) => {
|
|
7068
|
+
const next = [...value.identifiers];
|
|
7069
|
+
next[index] = id;
|
|
7070
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
7071
|
+
};
|
|
7072
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
7073
|
+
return /* @__PURE__ */ jsxs(
|
|
7074
|
+
Flex,
|
|
7075
|
+
{
|
|
7076
|
+
direction: "column",
|
|
7077
|
+
gap: "xs",
|
|
7078
|
+
p: "sm",
|
|
7079
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
7080
|
+
children: [
|
|
7081
|
+
/* @__PURE__ */ jsx(
|
|
7082
|
+
AdminPageTitle,
|
|
7083
|
+
{
|
|
7084
|
+
icon: ShieldCheck,
|
|
7085
|
+
title: title || t("Access", "Access"),
|
|
7086
|
+
color
|
|
7087
|
+
}
|
|
7088
|
+
),
|
|
7089
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description2 || t(
|
|
7090
|
+
"AccessOverrideDesc",
|
|
7091
|
+
"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."
|
|
7092
|
+
) }),
|
|
7093
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: Users, label: t("AccessGroups", "Groups") }),
|
|
7094
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
7095
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsx(EmptyHint, { text: t("AccessNoGroups", "No groups added.") }),
|
|
7096
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7097
|
+
/* @__PURE__ */ jsx(
|
|
7098
|
+
GroupName,
|
|
7099
|
+
{
|
|
7100
|
+
value: name,
|
|
7101
|
+
onChange: (v) => setGroup(i, v),
|
|
7102
|
+
type: groupType,
|
|
7103
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
7104
|
+
style: { flex: 1 }
|
|
7105
|
+
}
|
|
7106
|
+
),
|
|
7107
|
+
/* @__PURE__ */ jsx(
|
|
7108
|
+
ActionIcon,
|
|
7109
|
+
{
|
|
7110
|
+
variant: "subtle",
|
|
7111
|
+
color: "red",
|
|
7112
|
+
size: "md",
|
|
7113
|
+
onClick: () => removeGroup(i),
|
|
7114
|
+
title: t("Remove", "Remove"),
|
|
7115
|
+
"aria-label": t("Remove", "Remove"),
|
|
7116
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7117
|
+
}
|
|
7118
|
+
)
|
|
7119
|
+
] }, i)),
|
|
7120
|
+
addingGroup && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7121
|
+
/* @__PURE__ */ jsx(
|
|
7122
|
+
GroupName,
|
|
7123
|
+
{
|
|
7124
|
+
value: "",
|
|
7125
|
+
onChange: (v) => commitGroup(v),
|
|
7126
|
+
type: groupType,
|
|
7127
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
7128
|
+
style: { flex: 1 }
|
|
7129
|
+
}
|
|
7130
|
+
),
|
|
7131
|
+
/* @__PURE__ */ jsx(
|
|
7132
|
+
ActionIcon,
|
|
7133
|
+
{
|
|
7134
|
+
variant: "subtle",
|
|
7135
|
+
color: "red",
|
|
7136
|
+
size: "md",
|
|
7137
|
+
onClick: () => setAddingGroup(false),
|
|
7138
|
+
title: t("Remove", "Remove"),
|
|
7139
|
+
"aria-label": t("Remove", "Remove"),
|
|
7140
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7141
|
+
}
|
|
7142
|
+
)
|
|
7143
|
+
] })
|
|
7144
|
+
] }),
|
|
7145
|
+
!addingGroup && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
7146
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: UserRound, label: t("AccessPlayers", "Players") }),
|
|
7147
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
7148
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
7149
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7150
|
+
/* @__PURE__ */ jsx(
|
|
7151
|
+
PlayerSelect,
|
|
7152
|
+
{
|
|
7153
|
+
value: id || null,
|
|
7154
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
7155
|
+
includeOffline,
|
|
7156
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7157
|
+
style: { flex: 1 },
|
|
7158
|
+
size: "xs"
|
|
7159
|
+
}
|
|
7160
|
+
),
|
|
7161
|
+
/* @__PURE__ */ jsx(
|
|
7162
|
+
ActionIcon,
|
|
7163
|
+
{
|
|
7164
|
+
variant: "subtle",
|
|
7165
|
+
color: "red",
|
|
7166
|
+
size: "md",
|
|
7167
|
+
onClick: () => removeIdentifier(i),
|
|
7168
|
+
title: t("Remove", "Remove"),
|
|
7169
|
+
"aria-label": t("Remove", "Remove"),
|
|
7170
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7171
|
+
}
|
|
7172
|
+
)
|
|
7173
|
+
] }, i)),
|
|
7174
|
+
addingPlayer && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7175
|
+
/* @__PURE__ */ jsx(
|
|
7176
|
+
PlayerSelect,
|
|
7177
|
+
{
|
|
7178
|
+
value: null,
|
|
7179
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
7180
|
+
includeOffline,
|
|
7181
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7182
|
+
style: { flex: 1 },
|
|
7183
|
+
size: "xs"
|
|
7184
|
+
}
|
|
7185
|
+
),
|
|
7186
|
+
/* @__PURE__ */ jsx(
|
|
7187
|
+
ActionIcon,
|
|
7188
|
+
{
|
|
7189
|
+
variant: "subtle",
|
|
7190
|
+
color: "red",
|
|
7191
|
+
size: "md",
|
|
7192
|
+
onClick: () => setAddingPlayer(false),
|
|
7193
|
+
title: t("Remove", "Remove"),
|
|
7194
|
+
"aria-label": t("Remove", "Remove"),
|
|
7195
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7196
|
+
}
|
|
7197
|
+
)
|
|
7198
|
+
] })
|
|
7199
|
+
] }),
|
|
7200
|
+
!addingPlayer && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
7201
|
+
]
|
|
7202
|
+
}
|
|
7203
|
+
);
|
|
7204
|
+
}
|
|
7205
|
+
function AddRowButton({ label: label2, onClick }) {
|
|
7206
|
+
return /* @__PURE__ */ jsxs(
|
|
7207
|
+
Flex,
|
|
7208
|
+
{
|
|
7209
|
+
align: "center",
|
|
7210
|
+
justify: "center",
|
|
7211
|
+
gap: "xs",
|
|
7212
|
+
onClick,
|
|
7213
|
+
role: "button",
|
|
7214
|
+
tabIndex: 0,
|
|
7215
|
+
onKeyDown: (e) => {
|
|
7216
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7217
|
+
e.preventDefault();
|
|
7218
|
+
onClick();
|
|
7219
|
+
}
|
|
7220
|
+
},
|
|
7221
|
+
py: "xs",
|
|
7222
|
+
style: {
|
|
7223
|
+
cursor: "pointer",
|
|
7224
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
7225
|
+
borderRadius: "0.4vh",
|
|
7226
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7227
|
+
},
|
|
7228
|
+
onMouseEnter: (e) => {
|
|
7229
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
7230
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
7231
|
+
},
|
|
7232
|
+
onMouseLeave: (e) => {
|
|
7233
|
+
e.currentTarget.style.background = "transparent";
|
|
7234
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
7235
|
+
},
|
|
7236
|
+
children: [
|
|
7237
|
+
/* @__PURE__ */ jsx(Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
7238
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label2 })
|
|
7239
|
+
]
|
|
7240
|
+
}
|
|
7241
|
+
);
|
|
7242
|
+
}
|
|
6849
7243
|
|
|
6850
7244
|
// src/utils/gtaAnimPostFx.ts
|
|
6851
7245
|
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
@@ -7435,7 +7829,7 @@ function ScenarioSelect({
|
|
|
7435
7829
|
}
|
|
7436
7830
|
);
|
|
7437
7831
|
}
|
|
7438
|
-
var
|
|
7832
|
+
var t2 = (key, fallback) => {
|
|
7439
7833
|
const v = locale(key);
|
|
7440
7834
|
return v === key ? fallback : v;
|
|
7441
7835
|
};
|
|
@@ -7503,7 +7897,7 @@ function DiscordRoleSelect(props) {
|
|
|
7503
7897
|
return map;
|
|
7504
7898
|
}, [roles]);
|
|
7505
7899
|
if (errorCode === "NotConfigured") {
|
|
7506
|
-
const notConfiguredPlaceholder =
|
|
7900
|
+
const notConfiguredPlaceholder = t2(
|
|
7507
7901
|
"DiscordNotConfigured",
|
|
7508
7902
|
"Not configured \u2014 set in /dirk_lib"
|
|
7509
7903
|
);
|
|
@@ -7571,9 +7965,9 @@ function DiscordRoleSelect(props) {
|
|
|
7571
7965
|
e.stopPropagation();
|
|
7572
7966
|
refresh();
|
|
7573
7967
|
},
|
|
7574
|
-
title:
|
|
7968
|
+
title: t2("Refresh", "Refresh"),
|
|
7575
7969
|
loading,
|
|
7576
|
-
"aria-label":
|
|
7970
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
7577
7971
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
7578
7972
|
}
|
|
7579
7973
|
);
|
|
@@ -7583,7 +7977,7 @@ function DiscordRoleSelect(props) {
|
|
|
7583
7977
|
{
|
|
7584
7978
|
label: label2,
|
|
7585
7979
|
size,
|
|
7586
|
-
placeholder: placeholder ||
|
|
7980
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
7587
7981
|
data,
|
|
7588
7982
|
value: props.value || [],
|
|
7589
7983
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -7595,7 +7989,7 @@ function DiscordRoleSelect(props) {
|
|
|
7595
7989
|
rightSectionPointerEvents: "all",
|
|
7596
7990
|
style,
|
|
7597
7991
|
styles,
|
|
7598
|
-
nothingFoundMessage: errorCode ? `${
|
|
7992
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7599
7993
|
}
|
|
7600
7994
|
);
|
|
7601
7995
|
}
|
|
@@ -7604,7 +7998,7 @@ function DiscordRoleSelect(props) {
|
|
|
7604
7998
|
{
|
|
7605
7999
|
label: label2,
|
|
7606
8000
|
size,
|
|
7607
|
-
placeholder: placeholder ||
|
|
8001
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
7608
8002
|
data,
|
|
7609
8003
|
value: props.value || null,
|
|
7610
8004
|
onChange: (id) => props.onChange(id),
|
|
@@ -7616,11 +8010,11 @@ function DiscordRoleSelect(props) {
|
|
|
7616
8010
|
rightSectionPointerEvents: "all",
|
|
7617
8011
|
style,
|
|
7618
8012
|
styles,
|
|
7619
|
-
nothingFoundMessage: errorCode ? `${
|
|
8013
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7620
8014
|
}
|
|
7621
8015
|
);
|
|
7622
8016
|
}
|
|
7623
|
-
var
|
|
8017
|
+
var t3 = (key, fallback) => {
|
|
7624
8018
|
const v = locale(key);
|
|
7625
8019
|
return v === key ? fallback : v;
|
|
7626
8020
|
};
|
|
@@ -7641,7 +8035,7 @@ function FrameworkHint({ framework }) {
|
|
|
7641
8035
|
const theme2 = useMantineTheme();
|
|
7642
8036
|
if (!framework) return null;
|
|
7643
8037
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
7644
|
-
const text =
|
|
8038
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
7645
8039
|
return /* @__PURE__ */ jsxs(
|
|
7646
8040
|
Flex,
|
|
7647
8041
|
{
|
|
@@ -7725,9 +8119,9 @@ function AccountSelect(props) {
|
|
|
7725
8119
|
e.stopPropagation();
|
|
7726
8120
|
refresh();
|
|
7727
8121
|
},
|
|
7728
|
-
title:
|
|
8122
|
+
title: t3("Refresh", "Refresh"),
|
|
7729
8123
|
loading,
|
|
7730
|
-
"aria-label":
|
|
8124
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
7731
8125
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
7732
8126
|
}
|
|
7733
8127
|
);
|
|
@@ -7741,14 +8135,14 @@ function AccountSelect(props) {
|
|
|
7741
8135
|
rightSection: refreshButton,
|
|
7742
8136
|
rightSectionPointerEvents: "all",
|
|
7743
8137
|
style,
|
|
7744
|
-
nothingFoundMessage:
|
|
8138
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
7745
8139
|
};
|
|
7746
8140
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
7747
8141
|
props.multi ? /* @__PURE__ */ jsx(
|
|
7748
8142
|
MultiSelect,
|
|
7749
8143
|
{
|
|
7750
8144
|
...sharedSelectProps,
|
|
7751
|
-
placeholder: placeholder ||
|
|
8145
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
7752
8146
|
value: props.value || [],
|
|
7753
8147
|
onChange: (names) => props.onChange(names),
|
|
7754
8148
|
renderOption,
|
|
@@ -7760,7 +8154,7 @@ function AccountSelect(props) {
|
|
|
7760
8154
|
Select,
|
|
7761
8155
|
{
|
|
7762
8156
|
...sharedSelectProps,
|
|
7763
|
-
placeholder: placeholder ||
|
|
8157
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
7764
8158
|
value: props.value || null,
|
|
7765
8159
|
onChange: (name) => props.onChange(name),
|
|
7766
8160
|
renderOption,
|
|
@@ -8052,175 +8446,6 @@ function WorldPositionGotoButton2({
|
|
|
8052
8446
|
}
|
|
8053
8447
|
) });
|
|
8054
8448
|
}
|
|
8055
|
-
function usePlayers(opts = {}) {
|
|
8056
|
-
const {
|
|
8057
|
-
includeOffline = false,
|
|
8058
|
-
search = "",
|
|
8059
|
-
limit = 50,
|
|
8060
|
-
staleTimeMs,
|
|
8061
|
-
refetchIntervalMs
|
|
8062
|
-
} = opts;
|
|
8063
|
-
const query = useQuery({
|
|
8064
|
-
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
8065
|
-
queryFn: async () => {
|
|
8066
|
-
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
8067
|
-
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
8068
|
-
const result = await fetchNui(
|
|
8069
|
-
"ADMIN_TOOL_QUERY",
|
|
8070
|
-
payload,
|
|
8071
|
-
// Browser-dev fallback. Returns a couple of mock players so the
|
|
8072
|
-
// dev shell isn't blank.
|
|
8073
|
-
includeOffline ? [
|
|
8074
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
8075
|
-
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
8076
|
-
] : [
|
|
8077
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
8078
|
-
]
|
|
8079
|
-
);
|
|
8080
|
-
return Array.isArray(result) ? result : [];
|
|
8081
|
-
},
|
|
8082
|
-
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
8083
|
-
gcTime: 5 * 6e4,
|
|
8084
|
-
refetchInterval: refetchIntervalMs ?? false,
|
|
8085
|
-
refetchOnWindowFocus: false,
|
|
8086
|
-
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
8087
|
-
});
|
|
8088
|
-
return {
|
|
8089
|
-
players: query.data ?? [],
|
|
8090
|
-
isLoading: query.isLoading,
|
|
8091
|
-
isFetching: query.isFetching,
|
|
8092
|
-
error: query.error ?? null,
|
|
8093
|
-
refresh: () => query.refetch()
|
|
8094
|
-
};
|
|
8095
|
-
}
|
|
8096
|
-
var DEBOUNCE_MS = 300;
|
|
8097
|
-
var ONLINE_COLOR = "#3FA83F";
|
|
8098
|
-
var OFFLINE_COLOR = "#E54141";
|
|
8099
|
-
function PlayerSelect({
|
|
8100
|
-
value,
|
|
8101
|
-
onChange,
|
|
8102
|
-
includeOffline = false,
|
|
8103
|
-
limit = 50,
|
|
8104
|
-
searchable: searchableProp,
|
|
8105
|
-
placeholder,
|
|
8106
|
-
nothingFoundMessage: nothingFoundMessageProp,
|
|
8107
|
-
loadingLabel = "Loading\u2026",
|
|
8108
|
-
onlineLabel = "Online",
|
|
8109
|
-
offlineLabel = "Offline",
|
|
8110
|
-
refreshLabel = "Refresh player list",
|
|
8111
|
-
...rest
|
|
8112
|
-
}) {
|
|
8113
|
-
const theme2 = useMantineTheme();
|
|
8114
|
-
const color = theme2.colors[theme2.primaryColor][5];
|
|
8115
|
-
const [searchInput, setSearchInput] = useState("");
|
|
8116
|
-
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
8117
|
-
const { players, isFetching, refresh } = usePlayers({
|
|
8118
|
-
includeOffline,
|
|
8119
|
-
search: includeOffline ? debouncedSearch : void 0,
|
|
8120
|
-
limit
|
|
8121
|
-
});
|
|
8122
|
-
const sortedPlayers = useMemo(
|
|
8123
|
-
() => [...players].sort((a, b) => {
|
|
8124
|
-
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
8125
|
-
return a.charName.localeCompare(b.charName);
|
|
8126
|
-
}),
|
|
8127
|
-
[players]
|
|
8128
|
-
);
|
|
8129
|
-
const playerByCitizen = useMemo(() => {
|
|
8130
|
-
const m = /* @__PURE__ */ new Map();
|
|
8131
|
-
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
8132
|
-
return m;
|
|
8133
|
-
}, [sortedPlayers]);
|
|
8134
|
-
const data = useMemo(() => {
|
|
8135
|
-
const items = sortedPlayers.map((p) => ({
|
|
8136
|
-
value: p.citizenId,
|
|
8137
|
-
label: formatLabel(p)
|
|
8138
|
-
}));
|
|
8139
|
-
if (value && !items.some((i) => i.value === value)) {
|
|
8140
|
-
items.unshift({ value, label: value });
|
|
8141
|
-
}
|
|
8142
|
-
return items;
|
|
8143
|
-
}, [sortedPlayers, value]);
|
|
8144
|
-
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
8145
|
-
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
8146
|
-
useEffect(() => {
|
|
8147
|
-
if (!includeOffline) return;
|
|
8148
|
-
if (selectedLabel && searchInput === selectedLabel) return;
|
|
8149
|
-
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
8150
|
-
return () => clearTimeout(t3);
|
|
8151
|
-
}, [searchInput, includeOffline, selectedLabel]);
|
|
8152
|
-
const renderOption = ({ option }) => {
|
|
8153
|
-
const p = playerByCitizen.get(option.value);
|
|
8154
|
-
if (!p) return option.label;
|
|
8155
|
-
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
8156
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
8157
|
-
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
8158
|
-
] });
|
|
8159
|
-
};
|
|
8160
|
-
return /* @__PURE__ */ jsx(
|
|
8161
|
-
Select,
|
|
8162
|
-
{
|
|
8163
|
-
...rest,
|
|
8164
|
-
data,
|
|
8165
|
-
value: value ?? null,
|
|
8166
|
-
onChange: (v) => {
|
|
8167
|
-
if (!v) return onChange(null);
|
|
8168
|
-
const player = playerByCitizen.get(v) ?? null;
|
|
8169
|
-
onChange(player);
|
|
8170
|
-
},
|
|
8171
|
-
searchable: searchableProp ?? true,
|
|
8172
|
-
searchValue: includeOffline ? searchInput : void 0,
|
|
8173
|
-
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
8174
|
-
placeholder,
|
|
8175
|
-
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
8176
|
-
maxDropdownHeight: 300,
|
|
8177
|
-
renderOption,
|
|
8178
|
-
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
8179
|
-
rightSectionWidth: "3.5vh",
|
|
8180
|
-
rightSectionPointerEvents: "all",
|
|
8181
|
-
rightSection: /* @__PURE__ */ jsx(
|
|
8182
|
-
ActionIcon,
|
|
8183
|
-
{
|
|
8184
|
-
variant: "subtle",
|
|
8185
|
-
size: "sm",
|
|
8186
|
-
onClick: (e) => {
|
|
8187
|
-
e.stopPropagation();
|
|
8188
|
-
refresh();
|
|
8189
|
-
},
|
|
8190
|
-
"aria-label": refreshLabel,
|
|
8191
|
-
title: refreshLabel,
|
|
8192
|
-
style: { marginRight: "0.6vh" },
|
|
8193
|
-
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
8194
|
-
}
|
|
8195
|
-
)
|
|
8196
|
-
}
|
|
8197
|
-
);
|
|
8198
|
-
}
|
|
8199
|
-
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
8200
|
-
return /* @__PURE__ */ jsx(
|
|
8201
|
-
"span",
|
|
8202
|
-
{
|
|
8203
|
-
title: online ? onlineLabel : offlineLabel,
|
|
8204
|
-
style: {
|
|
8205
|
-
display: "inline-block",
|
|
8206
|
-
width: "0.9vh",
|
|
8207
|
-
height: "0.9vh",
|
|
8208
|
-
borderRadius: "50%",
|
|
8209
|
-
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
8210
|
-
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
8211
|
-
flexShrink: 0
|
|
8212
|
-
}
|
|
8213
|
-
}
|
|
8214
|
-
);
|
|
8215
|
-
}
|
|
8216
|
-
function formatLabel(p) {
|
|
8217
|
-
const parts = [p.charName || p.citizenId];
|
|
8218
|
-
if (p.online) {
|
|
8219
|
-
if (p.name) parts.push(p.name);
|
|
8220
|
-
if (p.id != null) parts.push(`#${p.id}`);
|
|
8221
|
-
}
|
|
8222
|
-
return parts.join(" \xB7 ");
|
|
8223
|
-
}
|
|
8224
8449
|
function usePickDoor() {
|
|
8225
8450
|
const begin = useAdminToolStore((s) => s.begin);
|
|
8226
8451
|
return async () => {
|
|
@@ -8612,6 +8837,6 @@ var Vector4Schema = z.object({
|
|
|
8612
8837
|
w: z.number()
|
|
8613
8838
|
});
|
|
8614
8839
|
|
|
8615
|
-
export { AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BlipMarker, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DirkProvider, DiscordRoleSelect, DoorPickerButton, FiveMKeyBindInput, FloatingParticles, FormProvider, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GroupName, GroupRank, GroupSelect, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, 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, TornEdgeSVGFilter, Vector2Schema, Vector3Schema, Vector4DeleteButton, Vector4Display, Vector4Schema, WorldPositionGotoButton, WorldPositionPicker, WorldPositionSetButton, ZoomControls, blipUrl, blipUrlForSprite, clearAdminState, colorWithAlpha, copyToClipboard, createFormStore, createScriptConfig, createSkill, dirkQueryClient, ensureFrameworkGroups, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getBlipColor, getBlipEntry, getGtaControl, getImageShape, getItemImageUrl, getScriptConfigInstance, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAdminState, useAdminToolStore, useAudio, useAutoFetcher, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useFrameworkGroups, useItems, useItemsList, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, useNuiEvent, usePickDoor, usePlayers, useProfanityStore, useSettings, useTornEdges, useValidModels };
|
|
8840
|
+
export { AccessOverrideSection, AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BlipMarker, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DEFAULT_PALETTE, DirkProvider, DiscordRoleSelect, DoorPickerButton, FiveMKeyBindInput, FloatingParticles, FormProvider, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GroupName, GroupRank, GroupSelect, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, 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, ThemeOverrideSchema, ThemeOverrideSection, Title, TornEdgeSVGFilter, Vector2Schema, Vector3Schema, Vector4DeleteButton, Vector4Display, Vector4Schema, WorldPositionGotoButton, WorldPositionPicker, WorldPositionSetButton, ZoomControls, blipUrl, blipUrlForSprite, clearAdminState, colorWithAlpha, copyToClipboard, createFormStore, createScriptConfig, createSkill, defaultThemeOverride, dirkQueryClient, ensureFrameworkGroups, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getBlipColor, getBlipEntry, getGtaControl, getImageShape, getItemImageUrl, getScriptConfigInstance, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAdminState, useAdminToolStore, useAudio, useAutoFetcher, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useFrameworkGroups, useItems, useItemsList, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, useNuiEvent, usePickDoor, usePlayers, useProfanityStore, useSettings, useTornEdges, useValidModels };
|
|
8616
8841
|
//# sourceMappingURL=index.js.map
|
|
8617
8842
|
//# sourceMappingURL=index.js.map
|