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.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var core = require('@mantine/core');
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var React4 = require('react');
|
|
6
6
|
var zustand = require('zustand');
|
|
7
|
+
var zod = require('zod');
|
|
7
8
|
var axios = require('axios');
|
|
8
9
|
var reactFontawesome = require('@fortawesome/react-fontawesome');
|
|
9
10
|
var framerMotion = require('framer-motion');
|
|
@@ -28,7 +29,6 @@ var leaflet = require('leaflet');
|
|
|
28
29
|
require('leaflet/dist/leaflet.css');
|
|
29
30
|
var reactLeaflet = require('react-leaflet');
|
|
30
31
|
var reactLeafletComponentMarker = require('@adamscybot/react-leaflet-component-marker');
|
|
31
|
-
var zod = require('zod');
|
|
32
32
|
|
|
33
33
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
34
34
|
|
|
@@ -1321,6 +1321,32 @@ var openLink = (url) => {
|
|
|
1321
1321
|
window.invokeNative("openLink", url);
|
|
1322
1322
|
}
|
|
1323
1323
|
};
|
|
1324
|
+
var DEFAULT_PALETTE = [
|
|
1325
|
+
"#f0f4ff",
|
|
1326
|
+
"#d9e3ff",
|
|
1327
|
+
"#bfcfff",
|
|
1328
|
+
"#a6bbff",
|
|
1329
|
+
"#8ca7ff",
|
|
1330
|
+
"#7393ff",
|
|
1331
|
+
"#5a7fff",
|
|
1332
|
+
"#406bff",
|
|
1333
|
+
"#2547ff",
|
|
1334
|
+
"#0b33ff"
|
|
1335
|
+
];
|
|
1336
|
+
var ThemeOverrideSchema = zod.z.object({
|
|
1337
|
+
useOverride: zod.z.boolean(),
|
|
1338
|
+
primaryColor: zod.z.string(),
|
|
1339
|
+
primaryShade: zod.z.number(),
|
|
1340
|
+
customTheme: zod.z.array(zod.z.string())
|
|
1341
|
+
});
|
|
1342
|
+
var defaultThemeOverride = {
|
|
1343
|
+
useOverride: false,
|
|
1344
|
+
primaryColor: "dirk",
|
|
1345
|
+
primaryShade: 5,
|
|
1346
|
+
customTheme: DEFAULT_PALETTE
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
// src/utils/useSettings.ts
|
|
1324
1350
|
var useSettings = zustand.create(() => ({
|
|
1325
1351
|
currency: "$",
|
|
1326
1352
|
game: "fivem",
|
|
@@ -1328,18 +1354,7 @@ var useSettings = zustand.create(() => ({
|
|
|
1328
1354
|
primaryShade: 9,
|
|
1329
1355
|
itemImgPath: "",
|
|
1330
1356
|
resourceVersion: "dev",
|
|
1331
|
-
customTheme:
|
|
1332
|
-
"#f0f4ff",
|
|
1333
|
-
"#d9e3ff",
|
|
1334
|
-
"#bfcfff",
|
|
1335
|
-
"#a6bbff",
|
|
1336
|
-
"#8ca7ff",
|
|
1337
|
-
"#7393ff",
|
|
1338
|
-
"#5a7fff",
|
|
1339
|
-
"#406bff",
|
|
1340
|
-
"#2547ff",
|
|
1341
|
-
"#0b33ff"
|
|
1342
|
-
]
|
|
1357
|
+
customTheme: DEFAULT_PALETTE
|
|
1343
1358
|
}));
|
|
1344
1359
|
|
|
1345
1360
|
// src/utils/fetchNui.ts
|
|
@@ -3751,11 +3766,11 @@ function ConfirmModal({
|
|
|
3751
3766
|
placeholder: confirmText,
|
|
3752
3767
|
value: typed,
|
|
3753
3768
|
onChange: (e) => setTyped(e.currentTarget.value),
|
|
3754
|
-
styles: (
|
|
3769
|
+
styles: (t4) => ({
|
|
3755
3770
|
input: {
|
|
3756
|
-
backgroundColor: core.alpha(
|
|
3771
|
+
backgroundColor: core.alpha(t4.colors.dark[7], 0.5),
|
|
3757
3772
|
border: `0.1vh solid ${core.alpha(
|
|
3758
|
-
typed === confirmText ? "#ef4444" :
|
|
3773
|
+
typed === confirmText ? "#ef4444" : t4.colors.dark[5],
|
|
3759
3774
|
0.5
|
|
3760
3775
|
)}`,
|
|
3761
3776
|
color: "rgba(255,255,255,0.85)",
|
|
@@ -4433,7 +4448,7 @@ function useAdminState(key, initial) {
|
|
|
4433
4448
|
React4.useEffect(() => {
|
|
4434
4449
|
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
4435
4450
|
listeners.set(key, set);
|
|
4436
|
-
const handler = () => setTick((
|
|
4451
|
+
const handler = () => setTick((t4) => t4 + 1);
|
|
4437
4452
|
set.add(handler);
|
|
4438
4453
|
return () => {
|
|
4439
4454
|
set.delete(handler);
|
|
@@ -6613,24 +6628,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
6613
6628
|
"yellow",
|
|
6614
6629
|
"orange"
|
|
6615
6630
|
].map((value) => ({ value, label: value }));
|
|
6616
|
-
var DEFAULT_PALETTE = [
|
|
6617
|
-
"#f0f4ff",
|
|
6618
|
-
"#d9e3ff",
|
|
6619
|
-
"#bfcfff",
|
|
6620
|
-
"#a6bbff",
|
|
6621
|
-
"#8ca7ff",
|
|
6622
|
-
"#7393ff",
|
|
6623
|
-
"#5a7fff",
|
|
6624
|
-
"#406bff",
|
|
6625
|
-
"#2547ff",
|
|
6626
|
-
"#0b33ff"
|
|
6627
|
-
];
|
|
6628
|
-
var DEFAULT_VALUE = {
|
|
6629
|
-
useOverride: false,
|
|
6630
|
-
primaryColor: "dirk",
|
|
6631
|
-
primaryShade: 5,
|
|
6632
|
-
customTheme: DEFAULT_PALETTE
|
|
6633
|
-
};
|
|
6634
6631
|
function GroupLabel({ label: label2 }) {
|
|
6635
6632
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
6636
6633
|
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
@@ -6645,10 +6642,10 @@ function ThemeOverrideSection({
|
|
|
6645
6642
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
6646
6643
|
const raw = useFormField(schemaKey);
|
|
6647
6644
|
const value = {
|
|
6648
|
-
useOverride: raw?.useOverride ??
|
|
6649
|
-
primaryColor: raw?.primaryColor ??
|
|
6650
|
-
primaryShade: raw?.primaryShade ??
|
|
6651
|
-
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme :
|
|
6645
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
6646
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
6647
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
6648
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
6652
6649
|
};
|
|
6653
6650
|
const { setValue } = useFormActions();
|
|
6654
6651
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -6855,6 +6852,403 @@ function SwatchTile({
|
|
|
6855
6852
|
) })
|
|
6856
6853
|
] });
|
|
6857
6854
|
}
|
|
6855
|
+
function usePlayers(opts = {}) {
|
|
6856
|
+
const {
|
|
6857
|
+
includeOffline = false,
|
|
6858
|
+
search = "",
|
|
6859
|
+
limit = 50,
|
|
6860
|
+
staleTimeMs,
|
|
6861
|
+
refetchIntervalMs
|
|
6862
|
+
} = opts;
|
|
6863
|
+
const query = reactQuery.useQuery({
|
|
6864
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6865
|
+
queryFn: async () => {
|
|
6866
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6867
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6868
|
+
const result = await fetchNui(
|
|
6869
|
+
"ADMIN_TOOL_QUERY",
|
|
6870
|
+
payload,
|
|
6871
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6872
|
+
// dev shell isn't blank.
|
|
6873
|
+
includeOffline ? [
|
|
6874
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6875
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6876
|
+
] : [
|
|
6877
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6878
|
+
]
|
|
6879
|
+
);
|
|
6880
|
+
return Array.isArray(result) ? result : [];
|
|
6881
|
+
},
|
|
6882
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6883
|
+
gcTime: 5 * 6e4,
|
|
6884
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6885
|
+
refetchOnWindowFocus: false,
|
|
6886
|
+
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
6887
|
+
});
|
|
6888
|
+
return {
|
|
6889
|
+
players: query.data ?? [],
|
|
6890
|
+
isLoading: query.isLoading,
|
|
6891
|
+
isFetching: query.isFetching,
|
|
6892
|
+
error: query.error ?? null,
|
|
6893
|
+
refresh: () => query.refetch()
|
|
6894
|
+
};
|
|
6895
|
+
}
|
|
6896
|
+
var DEBOUNCE_MS = 300;
|
|
6897
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6898
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6899
|
+
function PlayerSelect({
|
|
6900
|
+
value,
|
|
6901
|
+
onChange,
|
|
6902
|
+
includeOffline = false,
|
|
6903
|
+
limit = 50,
|
|
6904
|
+
searchable: searchableProp,
|
|
6905
|
+
placeholder,
|
|
6906
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
6907
|
+
loadingLabel = "Loading\u2026",
|
|
6908
|
+
onlineLabel = "Online",
|
|
6909
|
+
offlineLabel = "Offline",
|
|
6910
|
+
refreshLabel = "Refresh player list",
|
|
6911
|
+
...rest
|
|
6912
|
+
}) {
|
|
6913
|
+
const theme2 = core.useMantineTheme();
|
|
6914
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
6915
|
+
const [searchInput, setSearchInput] = React4.useState("");
|
|
6916
|
+
const [debouncedSearch, setDebouncedSearch] = React4.useState("");
|
|
6917
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
6918
|
+
includeOffline,
|
|
6919
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
6920
|
+
limit
|
|
6921
|
+
});
|
|
6922
|
+
const sortedPlayers = React4.useMemo(
|
|
6923
|
+
() => [...players].sort((a, b) => {
|
|
6924
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
6925
|
+
return a.charName.localeCompare(b.charName);
|
|
6926
|
+
}),
|
|
6927
|
+
[players]
|
|
6928
|
+
);
|
|
6929
|
+
const playerByCitizen = React4.useMemo(() => {
|
|
6930
|
+
const m = /* @__PURE__ */ new Map();
|
|
6931
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
6932
|
+
return m;
|
|
6933
|
+
}, [sortedPlayers]);
|
|
6934
|
+
const data = React4.useMemo(() => {
|
|
6935
|
+
const items = sortedPlayers.map((p) => ({
|
|
6936
|
+
value: p.citizenId,
|
|
6937
|
+
label: formatLabel(p)
|
|
6938
|
+
}));
|
|
6939
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
6940
|
+
items.unshift({ value, label: value });
|
|
6941
|
+
}
|
|
6942
|
+
return items;
|
|
6943
|
+
}, [sortedPlayers, value]);
|
|
6944
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
6945
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
6946
|
+
React4.useEffect(() => {
|
|
6947
|
+
if (!includeOffline) return;
|
|
6948
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
6949
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
6950
|
+
return () => clearTimeout(t4);
|
|
6951
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
6952
|
+
const renderOption = ({ option }) => {
|
|
6953
|
+
const p = playerByCitizen.get(option.value);
|
|
6954
|
+
if (!p) return option.label;
|
|
6955
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
6956
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
6957
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
6958
|
+
] });
|
|
6959
|
+
};
|
|
6960
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6961
|
+
core.Select,
|
|
6962
|
+
{
|
|
6963
|
+
...rest,
|
|
6964
|
+
data,
|
|
6965
|
+
value: value ?? null,
|
|
6966
|
+
onChange: (v) => {
|
|
6967
|
+
if (!v) return onChange(null);
|
|
6968
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
6969
|
+
onChange(player);
|
|
6970
|
+
},
|
|
6971
|
+
searchable: searchableProp ?? true,
|
|
6972
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
6973
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
6974
|
+
placeholder,
|
|
6975
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
6976
|
+
maxDropdownHeight: 300,
|
|
6977
|
+
renderOption,
|
|
6978
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
6979
|
+
rightSectionWidth: "3.5vh",
|
|
6980
|
+
rightSectionPointerEvents: "all",
|
|
6981
|
+
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6982
|
+
core.ActionIcon,
|
|
6983
|
+
{
|
|
6984
|
+
variant: "subtle",
|
|
6985
|
+
size: "sm",
|
|
6986
|
+
onClick: (e) => {
|
|
6987
|
+
e.stopPropagation();
|
|
6988
|
+
refresh();
|
|
6989
|
+
},
|
|
6990
|
+
"aria-label": refreshLabel,
|
|
6991
|
+
title: refreshLabel,
|
|
6992
|
+
style: { marginRight: "0.6vh" },
|
|
6993
|
+
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
6994
|
+
}
|
|
6995
|
+
)
|
|
6996
|
+
}
|
|
6997
|
+
);
|
|
6998
|
+
}
|
|
6999
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7000
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7001
|
+
"span",
|
|
7002
|
+
{
|
|
7003
|
+
title: online ? onlineLabel : offlineLabel,
|
|
7004
|
+
style: {
|
|
7005
|
+
display: "inline-block",
|
|
7006
|
+
width: "0.9vh",
|
|
7007
|
+
height: "0.9vh",
|
|
7008
|
+
borderRadius: "50%",
|
|
7009
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7010
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7011
|
+
flexShrink: 0
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
);
|
|
7015
|
+
}
|
|
7016
|
+
function formatLabel(p) {
|
|
7017
|
+
const parts = [p.charName || p.citizenId];
|
|
7018
|
+
if (p.online) {
|
|
7019
|
+
if (p.name) parts.push(p.name);
|
|
7020
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7021
|
+
}
|
|
7022
|
+
return parts.join(" \xB7 ");
|
|
7023
|
+
}
|
|
7024
|
+
var t = (key, fallback) => {
|
|
7025
|
+
const v = locale(key);
|
|
7026
|
+
return v === key ? fallback : v;
|
|
7027
|
+
};
|
|
7028
|
+
var DEFAULT_VALUE = {
|
|
7029
|
+
groups: [],
|
|
7030
|
+
identifiers: []
|
|
7031
|
+
};
|
|
7032
|
+
function SectionLabel({ icon: Icon, label: label2 }) {
|
|
7033
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
7034
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
7035
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
7036
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
7037
|
+
] });
|
|
7038
|
+
}
|
|
7039
|
+
function EmptyHint({ text }) {
|
|
7040
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
7041
|
+
}
|
|
7042
|
+
function AccessOverrideSection({
|
|
7043
|
+
schemaKey = "access",
|
|
7044
|
+
title,
|
|
7045
|
+
description: description2,
|
|
7046
|
+
groupType,
|
|
7047
|
+
includeOffline = true
|
|
7048
|
+
}) {
|
|
7049
|
+
const mantineTheme = core.useMantineTheme();
|
|
7050
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
7051
|
+
const raw = useFormField(schemaKey);
|
|
7052
|
+
const value = {
|
|
7053
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
7054
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
7055
|
+
};
|
|
7056
|
+
const { setValue } = useFormActions();
|
|
7057
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
7058
|
+
const [addingGroup, setAddingGroup] = React4.useState(false);
|
|
7059
|
+
const [addingPlayer, setAddingPlayer] = React4.useState(false);
|
|
7060
|
+
const commitGroup = (name) => {
|
|
7061
|
+
if (!name) return;
|
|
7062
|
+
set("groups", [...value.groups, name]);
|
|
7063
|
+
setAddingGroup(false);
|
|
7064
|
+
};
|
|
7065
|
+
const setGroup = (index, name) => {
|
|
7066
|
+
const next = [...value.groups];
|
|
7067
|
+
next[index] = name;
|
|
7068
|
+
set("groups", next.filter((g) => g !== ""));
|
|
7069
|
+
};
|
|
7070
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
7071
|
+
const commitIdentifier = (id) => {
|
|
7072
|
+
if (!id) return;
|
|
7073
|
+
set("identifiers", [...value.identifiers, id]);
|
|
7074
|
+
setAddingPlayer(false);
|
|
7075
|
+
};
|
|
7076
|
+
const setIdentifier = (index, id) => {
|
|
7077
|
+
const next = [...value.identifiers];
|
|
7078
|
+
next[index] = id;
|
|
7079
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
7080
|
+
};
|
|
7081
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
7082
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7083
|
+
core.Flex,
|
|
7084
|
+
{
|
|
7085
|
+
direction: "column",
|
|
7086
|
+
gap: "xs",
|
|
7087
|
+
p: "sm",
|
|
7088
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
7089
|
+
children: [
|
|
7090
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7091
|
+
AdminPageTitle,
|
|
7092
|
+
{
|
|
7093
|
+
icon: lucideReact.ShieldCheck,
|
|
7094
|
+
title: title || t("Access", "Access"),
|
|
7095
|
+
color
|
|
7096
|
+
}
|
|
7097
|
+
),
|
|
7098
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description2 || t(
|
|
7099
|
+
"AccessOverrideDesc",
|
|
7100
|
+
"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."
|
|
7101
|
+
) }),
|
|
7102
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.Users, label: t("AccessGroups", "Groups") }),
|
|
7103
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
7104
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsxRuntime.jsx(EmptyHint, { text: t("AccessNoGroups", "No groups added.") }),
|
|
7105
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7106
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7107
|
+
GroupName,
|
|
7108
|
+
{
|
|
7109
|
+
value: name,
|
|
7110
|
+
onChange: (v) => setGroup(i, v),
|
|
7111
|
+
type: groupType,
|
|
7112
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
7113
|
+
style: { flex: 1 }
|
|
7114
|
+
}
|
|
7115
|
+
),
|
|
7116
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7117
|
+
core.ActionIcon,
|
|
7118
|
+
{
|
|
7119
|
+
variant: "subtle",
|
|
7120
|
+
color: "red",
|
|
7121
|
+
size: "md",
|
|
7122
|
+
onClick: () => removeGroup(i),
|
|
7123
|
+
title: t("Remove", "Remove"),
|
|
7124
|
+
"aria-label": t("Remove", "Remove"),
|
|
7125
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7126
|
+
}
|
|
7127
|
+
)
|
|
7128
|
+
] }, i)),
|
|
7129
|
+
addingGroup && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7130
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7131
|
+
GroupName,
|
|
7132
|
+
{
|
|
7133
|
+
value: "",
|
|
7134
|
+
onChange: (v) => commitGroup(v),
|
|
7135
|
+
type: groupType,
|
|
7136
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
7137
|
+
style: { flex: 1 }
|
|
7138
|
+
}
|
|
7139
|
+
),
|
|
7140
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7141
|
+
core.ActionIcon,
|
|
7142
|
+
{
|
|
7143
|
+
variant: "subtle",
|
|
7144
|
+
color: "red",
|
|
7145
|
+
size: "md",
|
|
7146
|
+
onClick: () => setAddingGroup(false),
|
|
7147
|
+
title: t("Remove", "Remove"),
|
|
7148
|
+
"aria-label": t("Remove", "Remove"),
|
|
7149
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7150
|
+
}
|
|
7151
|
+
)
|
|
7152
|
+
] })
|
|
7153
|
+
] }),
|
|
7154
|
+
!addingGroup && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
7155
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.UserRound, label: t("AccessPlayers", "Players") }),
|
|
7156
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
7157
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
7158
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7160
|
+
PlayerSelect,
|
|
7161
|
+
{
|
|
7162
|
+
value: id || null,
|
|
7163
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
7164
|
+
includeOffline,
|
|
7165
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7166
|
+
style: { flex: 1 },
|
|
7167
|
+
size: "xs"
|
|
7168
|
+
}
|
|
7169
|
+
),
|
|
7170
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7171
|
+
core.ActionIcon,
|
|
7172
|
+
{
|
|
7173
|
+
variant: "subtle",
|
|
7174
|
+
color: "red",
|
|
7175
|
+
size: "md",
|
|
7176
|
+
onClick: () => removeIdentifier(i),
|
|
7177
|
+
title: t("Remove", "Remove"),
|
|
7178
|
+
"aria-label": t("Remove", "Remove"),
|
|
7179
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7180
|
+
}
|
|
7181
|
+
)
|
|
7182
|
+
] }, i)),
|
|
7183
|
+
addingPlayer && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7184
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7185
|
+
PlayerSelect,
|
|
7186
|
+
{
|
|
7187
|
+
value: null,
|
|
7188
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
7189
|
+
includeOffline,
|
|
7190
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7191
|
+
style: { flex: 1 },
|
|
7192
|
+
size: "xs"
|
|
7193
|
+
}
|
|
7194
|
+
),
|
|
7195
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7196
|
+
core.ActionIcon,
|
|
7197
|
+
{
|
|
7198
|
+
variant: "subtle",
|
|
7199
|
+
color: "red",
|
|
7200
|
+
size: "md",
|
|
7201
|
+
onClick: () => setAddingPlayer(false),
|
|
7202
|
+
title: t("Remove", "Remove"),
|
|
7203
|
+
"aria-label": t("Remove", "Remove"),
|
|
7204
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7205
|
+
}
|
|
7206
|
+
)
|
|
7207
|
+
] })
|
|
7208
|
+
] }),
|
|
7209
|
+
!addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
7210
|
+
]
|
|
7211
|
+
}
|
|
7212
|
+
);
|
|
7213
|
+
}
|
|
7214
|
+
function AddRowButton({ label: label2, onClick }) {
|
|
7215
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7216
|
+
core.Flex,
|
|
7217
|
+
{
|
|
7218
|
+
align: "center",
|
|
7219
|
+
justify: "center",
|
|
7220
|
+
gap: "xs",
|
|
7221
|
+
onClick,
|
|
7222
|
+
role: "button",
|
|
7223
|
+
tabIndex: 0,
|
|
7224
|
+
onKeyDown: (e) => {
|
|
7225
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7226
|
+
e.preventDefault();
|
|
7227
|
+
onClick();
|
|
7228
|
+
}
|
|
7229
|
+
},
|
|
7230
|
+
py: "xs",
|
|
7231
|
+
style: {
|
|
7232
|
+
cursor: "pointer",
|
|
7233
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
7234
|
+
borderRadius: "0.4vh",
|
|
7235
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7236
|
+
},
|
|
7237
|
+
onMouseEnter: (e) => {
|
|
7238
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
7239
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
7240
|
+
},
|
|
7241
|
+
onMouseLeave: (e) => {
|
|
7242
|
+
e.currentTarget.style.background = "transparent";
|
|
7243
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
7244
|
+
},
|
|
7245
|
+
children: [
|
|
7246
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
7247
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label2 })
|
|
7248
|
+
]
|
|
7249
|
+
}
|
|
7250
|
+
);
|
|
7251
|
+
}
|
|
6858
7252
|
|
|
6859
7253
|
// src/utils/gtaAnimPostFx.ts
|
|
6860
7254
|
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
@@ -7444,7 +7838,7 @@ function ScenarioSelect({
|
|
|
7444
7838
|
}
|
|
7445
7839
|
);
|
|
7446
7840
|
}
|
|
7447
|
-
var
|
|
7841
|
+
var t2 = (key, fallback) => {
|
|
7448
7842
|
const v = locale(key);
|
|
7449
7843
|
return v === key ? fallback : v;
|
|
7450
7844
|
};
|
|
@@ -7512,7 +7906,7 @@ function DiscordRoleSelect(props) {
|
|
|
7512
7906
|
return map;
|
|
7513
7907
|
}, [roles]);
|
|
7514
7908
|
if (errorCode === "NotConfigured") {
|
|
7515
|
-
const notConfiguredPlaceholder =
|
|
7909
|
+
const notConfiguredPlaceholder = t2(
|
|
7516
7910
|
"DiscordNotConfigured",
|
|
7517
7911
|
"Not configured \u2014 set in /dirk_lib"
|
|
7518
7912
|
);
|
|
@@ -7580,9 +7974,9 @@ function DiscordRoleSelect(props) {
|
|
|
7580
7974
|
e.stopPropagation();
|
|
7581
7975
|
refresh();
|
|
7582
7976
|
},
|
|
7583
|
-
title:
|
|
7977
|
+
title: t2("Refresh", "Refresh"),
|
|
7584
7978
|
loading,
|
|
7585
|
-
"aria-label":
|
|
7979
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
7586
7980
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
7587
7981
|
}
|
|
7588
7982
|
);
|
|
@@ -7592,7 +7986,7 @@ function DiscordRoleSelect(props) {
|
|
|
7592
7986
|
{
|
|
7593
7987
|
label: label2,
|
|
7594
7988
|
size,
|
|
7595
|
-
placeholder: placeholder ||
|
|
7989
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
7596
7990
|
data,
|
|
7597
7991
|
value: props.value || [],
|
|
7598
7992
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -7604,7 +7998,7 @@ function DiscordRoleSelect(props) {
|
|
|
7604
7998
|
rightSectionPointerEvents: "all",
|
|
7605
7999
|
style,
|
|
7606
8000
|
styles,
|
|
7607
|
-
nothingFoundMessage: errorCode ? `${
|
|
8001
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7608
8002
|
}
|
|
7609
8003
|
);
|
|
7610
8004
|
}
|
|
@@ -7613,7 +8007,7 @@ function DiscordRoleSelect(props) {
|
|
|
7613
8007
|
{
|
|
7614
8008
|
label: label2,
|
|
7615
8009
|
size,
|
|
7616
|
-
placeholder: placeholder ||
|
|
8010
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
7617
8011
|
data,
|
|
7618
8012
|
value: props.value || null,
|
|
7619
8013
|
onChange: (id) => props.onChange(id),
|
|
@@ -7625,11 +8019,11 @@ function DiscordRoleSelect(props) {
|
|
|
7625
8019
|
rightSectionPointerEvents: "all",
|
|
7626
8020
|
style,
|
|
7627
8021
|
styles,
|
|
7628
|
-
nothingFoundMessage: errorCode ? `${
|
|
8022
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7629
8023
|
}
|
|
7630
8024
|
);
|
|
7631
8025
|
}
|
|
7632
|
-
var
|
|
8026
|
+
var t3 = (key, fallback) => {
|
|
7633
8027
|
const v = locale(key);
|
|
7634
8028
|
return v === key ? fallback : v;
|
|
7635
8029
|
};
|
|
@@ -7650,7 +8044,7 @@ function FrameworkHint({ framework }) {
|
|
|
7650
8044
|
const theme2 = core.useMantineTheme();
|
|
7651
8045
|
if (!framework) return null;
|
|
7652
8046
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
7653
|
-
const text =
|
|
8047
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
7654
8048
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7655
8049
|
core.Flex,
|
|
7656
8050
|
{
|
|
@@ -7734,9 +8128,9 @@ function AccountSelect(props) {
|
|
|
7734
8128
|
e.stopPropagation();
|
|
7735
8129
|
refresh();
|
|
7736
8130
|
},
|
|
7737
|
-
title:
|
|
8131
|
+
title: t3("Refresh", "Refresh"),
|
|
7738
8132
|
loading,
|
|
7739
|
-
"aria-label":
|
|
8133
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
7740
8134
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
7741
8135
|
}
|
|
7742
8136
|
);
|
|
@@ -7750,14 +8144,14 @@ function AccountSelect(props) {
|
|
|
7750
8144
|
rightSection: refreshButton,
|
|
7751
8145
|
rightSectionPointerEvents: "all",
|
|
7752
8146
|
style,
|
|
7753
|
-
nothingFoundMessage:
|
|
8147
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
7754
8148
|
};
|
|
7755
8149
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
7756
8150
|
props.multi ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7757
8151
|
core.MultiSelect,
|
|
7758
8152
|
{
|
|
7759
8153
|
...sharedSelectProps,
|
|
7760
|
-
placeholder: placeholder ||
|
|
8154
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
7761
8155
|
value: props.value || [],
|
|
7762
8156
|
onChange: (names) => props.onChange(names),
|
|
7763
8157
|
renderOption,
|
|
@@ -7769,7 +8163,7 @@ function AccountSelect(props) {
|
|
|
7769
8163
|
core.Select,
|
|
7770
8164
|
{
|
|
7771
8165
|
...sharedSelectProps,
|
|
7772
|
-
placeholder: placeholder ||
|
|
8166
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
7773
8167
|
value: props.value || null,
|
|
7774
8168
|
onChange: (name) => props.onChange(name),
|
|
7775
8169
|
renderOption,
|
|
@@ -8061,175 +8455,6 @@ function WorldPositionGotoButton2({
|
|
|
8061
8455
|
}
|
|
8062
8456
|
) });
|
|
8063
8457
|
}
|
|
8064
|
-
function usePlayers(opts = {}) {
|
|
8065
|
-
const {
|
|
8066
|
-
includeOffline = false,
|
|
8067
|
-
search = "",
|
|
8068
|
-
limit = 50,
|
|
8069
|
-
staleTimeMs,
|
|
8070
|
-
refetchIntervalMs
|
|
8071
|
-
} = opts;
|
|
8072
|
-
const query = reactQuery.useQuery({
|
|
8073
|
-
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
8074
|
-
queryFn: async () => {
|
|
8075
|
-
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
8076
|
-
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
8077
|
-
const result = await fetchNui(
|
|
8078
|
-
"ADMIN_TOOL_QUERY",
|
|
8079
|
-
payload,
|
|
8080
|
-
// Browser-dev fallback. Returns a couple of mock players so the
|
|
8081
|
-
// dev shell isn't blank.
|
|
8082
|
-
includeOffline ? [
|
|
8083
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
8084
|
-
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
8085
|
-
] : [
|
|
8086
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
8087
|
-
]
|
|
8088
|
-
);
|
|
8089
|
-
return Array.isArray(result) ? result : [];
|
|
8090
|
-
},
|
|
8091
|
-
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
8092
|
-
gcTime: 5 * 6e4,
|
|
8093
|
-
refetchInterval: refetchIntervalMs ?? false,
|
|
8094
|
-
refetchOnWindowFocus: false,
|
|
8095
|
-
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
8096
|
-
});
|
|
8097
|
-
return {
|
|
8098
|
-
players: query.data ?? [],
|
|
8099
|
-
isLoading: query.isLoading,
|
|
8100
|
-
isFetching: query.isFetching,
|
|
8101
|
-
error: query.error ?? null,
|
|
8102
|
-
refresh: () => query.refetch()
|
|
8103
|
-
};
|
|
8104
|
-
}
|
|
8105
|
-
var DEBOUNCE_MS = 300;
|
|
8106
|
-
var ONLINE_COLOR = "#3FA83F";
|
|
8107
|
-
var OFFLINE_COLOR = "#E54141";
|
|
8108
|
-
function PlayerSelect({
|
|
8109
|
-
value,
|
|
8110
|
-
onChange,
|
|
8111
|
-
includeOffline = false,
|
|
8112
|
-
limit = 50,
|
|
8113
|
-
searchable: searchableProp,
|
|
8114
|
-
placeholder,
|
|
8115
|
-
nothingFoundMessage: nothingFoundMessageProp,
|
|
8116
|
-
loadingLabel = "Loading\u2026",
|
|
8117
|
-
onlineLabel = "Online",
|
|
8118
|
-
offlineLabel = "Offline",
|
|
8119
|
-
refreshLabel = "Refresh player list",
|
|
8120
|
-
...rest
|
|
8121
|
-
}) {
|
|
8122
|
-
const theme2 = core.useMantineTheme();
|
|
8123
|
-
const color = theme2.colors[theme2.primaryColor][5];
|
|
8124
|
-
const [searchInput, setSearchInput] = React4.useState("");
|
|
8125
|
-
const [debouncedSearch, setDebouncedSearch] = React4.useState("");
|
|
8126
|
-
const { players, isFetching, refresh } = usePlayers({
|
|
8127
|
-
includeOffline,
|
|
8128
|
-
search: includeOffline ? debouncedSearch : void 0,
|
|
8129
|
-
limit
|
|
8130
|
-
});
|
|
8131
|
-
const sortedPlayers = React4.useMemo(
|
|
8132
|
-
() => [...players].sort((a, b) => {
|
|
8133
|
-
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
8134
|
-
return a.charName.localeCompare(b.charName);
|
|
8135
|
-
}),
|
|
8136
|
-
[players]
|
|
8137
|
-
);
|
|
8138
|
-
const playerByCitizen = React4.useMemo(() => {
|
|
8139
|
-
const m = /* @__PURE__ */ new Map();
|
|
8140
|
-
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
8141
|
-
return m;
|
|
8142
|
-
}, [sortedPlayers]);
|
|
8143
|
-
const data = React4.useMemo(() => {
|
|
8144
|
-
const items = sortedPlayers.map((p) => ({
|
|
8145
|
-
value: p.citizenId,
|
|
8146
|
-
label: formatLabel(p)
|
|
8147
|
-
}));
|
|
8148
|
-
if (value && !items.some((i) => i.value === value)) {
|
|
8149
|
-
items.unshift({ value, label: value });
|
|
8150
|
-
}
|
|
8151
|
-
return items;
|
|
8152
|
-
}, [sortedPlayers, value]);
|
|
8153
|
-
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
8154
|
-
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
8155
|
-
React4.useEffect(() => {
|
|
8156
|
-
if (!includeOffline) return;
|
|
8157
|
-
if (selectedLabel && searchInput === selectedLabel) return;
|
|
8158
|
-
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
8159
|
-
return () => clearTimeout(t3);
|
|
8160
|
-
}, [searchInput, includeOffline, selectedLabel]);
|
|
8161
|
-
const renderOption = ({ option }) => {
|
|
8162
|
-
const p = playerByCitizen.get(option.value);
|
|
8163
|
-
if (!p) return option.label;
|
|
8164
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
8165
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
8166
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
8167
|
-
] });
|
|
8168
|
-
};
|
|
8169
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8170
|
-
core.Select,
|
|
8171
|
-
{
|
|
8172
|
-
...rest,
|
|
8173
|
-
data,
|
|
8174
|
-
value: value ?? null,
|
|
8175
|
-
onChange: (v) => {
|
|
8176
|
-
if (!v) return onChange(null);
|
|
8177
|
-
const player = playerByCitizen.get(v) ?? null;
|
|
8178
|
-
onChange(player);
|
|
8179
|
-
},
|
|
8180
|
-
searchable: searchableProp ?? true,
|
|
8181
|
-
searchValue: includeOffline ? searchInput : void 0,
|
|
8182
|
-
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
8183
|
-
placeholder,
|
|
8184
|
-
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
8185
|
-
maxDropdownHeight: 300,
|
|
8186
|
-
renderOption,
|
|
8187
|
-
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
8188
|
-
rightSectionWidth: "3.5vh",
|
|
8189
|
-
rightSectionPointerEvents: "all",
|
|
8190
|
-
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8191
|
-
core.ActionIcon,
|
|
8192
|
-
{
|
|
8193
|
-
variant: "subtle",
|
|
8194
|
-
size: "sm",
|
|
8195
|
-
onClick: (e) => {
|
|
8196
|
-
e.stopPropagation();
|
|
8197
|
-
refresh();
|
|
8198
|
-
},
|
|
8199
|
-
"aria-label": refreshLabel,
|
|
8200
|
-
title: refreshLabel,
|
|
8201
|
-
style: { marginRight: "0.6vh" },
|
|
8202
|
-
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
8203
|
-
}
|
|
8204
|
-
)
|
|
8205
|
-
}
|
|
8206
|
-
);
|
|
8207
|
-
}
|
|
8208
|
-
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
8209
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8210
|
-
"span",
|
|
8211
|
-
{
|
|
8212
|
-
title: online ? onlineLabel : offlineLabel,
|
|
8213
|
-
style: {
|
|
8214
|
-
display: "inline-block",
|
|
8215
|
-
width: "0.9vh",
|
|
8216
|
-
height: "0.9vh",
|
|
8217
|
-
borderRadius: "50%",
|
|
8218
|
-
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
8219
|
-
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
8220
|
-
flexShrink: 0
|
|
8221
|
-
}
|
|
8222
|
-
}
|
|
8223
|
-
);
|
|
8224
|
-
}
|
|
8225
|
-
function formatLabel(p) {
|
|
8226
|
-
const parts = [p.charName || p.citizenId];
|
|
8227
|
-
if (p.online) {
|
|
8228
|
-
if (p.name) parts.push(p.name);
|
|
8229
|
-
if (p.id != null) parts.push(`#${p.id}`);
|
|
8230
|
-
}
|
|
8231
|
-
return parts.join(" \xB7 ");
|
|
8232
|
-
}
|
|
8233
8458
|
function usePickDoor() {
|
|
8234
8459
|
const begin = useAdminToolStore((s) => s.begin);
|
|
8235
8460
|
return async () => {
|
|
@@ -8621,6 +8846,7 @@ var Vector4Schema = zod.z.object({
|
|
|
8621
8846
|
w: zod.z.number()
|
|
8622
8847
|
});
|
|
8623
8848
|
|
|
8849
|
+
exports.AccessOverrideSection = AccessOverrideSection;
|
|
8624
8850
|
exports.AccountSelect = AccountSelect;
|
|
8625
8851
|
exports.AdminPageTitle = AdminPageTitle;
|
|
8626
8852
|
exports.AnimPostFxSelect = AnimPostFxSelect;
|
|
@@ -8635,6 +8861,7 @@ exports.ConfirmModal = ConfirmModal;
|
|
|
8635
8861
|
exports.ControlMultiSelect = ControlMultiSelect;
|
|
8636
8862
|
exports.ControlSelect = ControlSelect;
|
|
8637
8863
|
exports.Counter = Counter;
|
|
8864
|
+
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|
|
8638
8865
|
exports.DirkProvider = DirkProvider;
|
|
8639
8866
|
exports.DiscordRoleSelect = DiscordRoleSelect;
|
|
8640
8867
|
exports.DoorPickerButton = DoorPickerButton;
|
|
@@ -8675,6 +8902,7 @@ exports.SegmentedProgress = SegmentedProgress;
|
|
|
8675
8902
|
exports.SelectItem = SelectItem;
|
|
8676
8903
|
exports.SwitchPanel = SwitchPanel;
|
|
8677
8904
|
exports.TestBed = TestBed;
|
|
8905
|
+
exports.ThemeOverrideSchema = ThemeOverrideSchema;
|
|
8678
8906
|
exports.ThemeOverrideSection = ThemeOverrideSection;
|
|
8679
8907
|
exports.Title = Title;
|
|
8680
8908
|
exports.TornEdgeSVGFilter = TornEdgeSVGFilter;
|
|
@@ -8695,6 +8923,7 @@ exports.copyToClipboard = copyToClipboard;
|
|
|
8695
8923
|
exports.createFormStore = createFormStore;
|
|
8696
8924
|
exports.createScriptConfig = createScriptConfig;
|
|
8697
8925
|
exports.createSkill = createSkill;
|
|
8926
|
+
exports.defaultThemeOverride = defaultThemeOverride;
|
|
8698
8927
|
exports.dirkQueryClient = dirkQueryClient;
|
|
8699
8928
|
exports.ensureFrameworkGroups = ensureFrameworkGroups;
|
|
8700
8929
|
exports.extractDefaults = extractDefaults;
|