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
|
@@ -4,6 +4,7 @@ var core = require('@mantine/core');
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var zustand = require('zustand');
|
|
7
|
+
var zod = require('zod');
|
|
7
8
|
var reactFontawesome = require('@fortawesome/react-fontawesome');
|
|
8
9
|
var framerMotion = require('framer-motion');
|
|
9
10
|
var lucideReact = require('lucide-react');
|
|
@@ -1289,6 +1290,32 @@ function colorWithAlpha(color, alpha17) {
|
|
|
1289
1290
|
|
|
1290
1291
|
// src/utils/misc.ts
|
|
1291
1292
|
var isEnvBrowser = () => !window.invokeNative;
|
|
1293
|
+
var DEFAULT_PALETTE = [
|
|
1294
|
+
"#f0f4ff",
|
|
1295
|
+
"#d9e3ff",
|
|
1296
|
+
"#bfcfff",
|
|
1297
|
+
"#a6bbff",
|
|
1298
|
+
"#8ca7ff",
|
|
1299
|
+
"#7393ff",
|
|
1300
|
+
"#5a7fff",
|
|
1301
|
+
"#406bff",
|
|
1302
|
+
"#2547ff",
|
|
1303
|
+
"#0b33ff"
|
|
1304
|
+
];
|
|
1305
|
+
zod.z.object({
|
|
1306
|
+
useOverride: zod.z.boolean(),
|
|
1307
|
+
primaryColor: zod.z.string(),
|
|
1308
|
+
primaryShade: zod.z.number(),
|
|
1309
|
+
customTheme: zod.z.array(zod.z.string())
|
|
1310
|
+
});
|
|
1311
|
+
var defaultThemeOverride = {
|
|
1312
|
+
useOverride: false,
|
|
1313
|
+
primaryColor: "dirk",
|
|
1314
|
+
primaryShade: 5,
|
|
1315
|
+
customTheme: DEFAULT_PALETTE
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
// src/utils/useSettings.ts
|
|
1292
1319
|
var useSettings = zustand.create(() => ({
|
|
1293
1320
|
currency: "$",
|
|
1294
1321
|
game: "fivem",
|
|
@@ -1296,18 +1323,7 @@ var useSettings = zustand.create(() => ({
|
|
|
1296
1323
|
primaryShade: 9,
|
|
1297
1324
|
itemImgPath: "",
|
|
1298
1325
|
resourceVersion: "dev",
|
|
1299
|
-
customTheme:
|
|
1300
|
-
"#f0f4ff",
|
|
1301
|
-
"#d9e3ff",
|
|
1302
|
-
"#bfcfff",
|
|
1303
|
-
"#a6bbff",
|
|
1304
|
-
"#8ca7ff",
|
|
1305
|
-
"#7393ff",
|
|
1306
|
-
"#5a7fff",
|
|
1307
|
-
"#406bff",
|
|
1308
|
-
"#2547ff",
|
|
1309
|
-
"#0b33ff"
|
|
1310
|
-
]
|
|
1326
|
+
customTheme: DEFAULT_PALETTE
|
|
1311
1327
|
}));
|
|
1312
1328
|
|
|
1313
1329
|
// src/utils/fetchNui.ts
|
|
@@ -3161,11 +3177,11 @@ function ConfirmModal({
|
|
|
3161
3177
|
placeholder: confirmText,
|
|
3162
3178
|
value: typed,
|
|
3163
3179
|
onChange: (e) => setTyped(e.currentTarget.value),
|
|
3164
|
-
styles: (
|
|
3180
|
+
styles: (t4) => ({
|
|
3165
3181
|
input: {
|
|
3166
|
-
backgroundColor: core.alpha(
|
|
3182
|
+
backgroundColor: core.alpha(t4.colors.dark[7], 0.5),
|
|
3167
3183
|
border: `0.1vh solid ${core.alpha(
|
|
3168
|
-
typed === confirmText ? "#ef4444" :
|
|
3184
|
+
typed === confirmText ? "#ef4444" : t4.colors.dark[5],
|
|
3169
3185
|
0.5
|
|
3170
3186
|
)}`,
|
|
3171
3187
|
color: "rgba(255,255,255,0.85)",
|
|
@@ -3810,7 +3826,7 @@ function useAdminState(key, initial) {
|
|
|
3810
3826
|
react.useEffect(() => {
|
|
3811
3827
|
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
3812
3828
|
listeners.set(key, set);
|
|
3813
|
-
const handler = () => setTick((
|
|
3829
|
+
const handler = () => setTick((t4) => t4 + 1);
|
|
3814
3830
|
set.add(handler);
|
|
3815
3831
|
return () => {
|
|
3816
3832
|
set.delete(handler);
|
|
@@ -5498,24 +5514,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
5498
5514
|
"yellow",
|
|
5499
5515
|
"orange"
|
|
5500
5516
|
].map((value) => ({ value, label: value }));
|
|
5501
|
-
var DEFAULT_PALETTE = [
|
|
5502
|
-
"#f0f4ff",
|
|
5503
|
-
"#d9e3ff",
|
|
5504
|
-
"#bfcfff",
|
|
5505
|
-
"#a6bbff",
|
|
5506
|
-
"#8ca7ff",
|
|
5507
|
-
"#7393ff",
|
|
5508
|
-
"#5a7fff",
|
|
5509
|
-
"#406bff",
|
|
5510
|
-
"#2547ff",
|
|
5511
|
-
"#0b33ff"
|
|
5512
|
-
];
|
|
5513
|
-
var DEFAULT_VALUE = {
|
|
5514
|
-
useOverride: false,
|
|
5515
|
-
primaryColor: "dirk",
|
|
5516
|
-
primaryShade: 5,
|
|
5517
|
-
customTheme: DEFAULT_PALETTE
|
|
5518
|
-
};
|
|
5519
5517
|
function GroupLabel({ label }) {
|
|
5520
5518
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
5521
5519
|
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label }),
|
|
@@ -5530,10 +5528,10 @@ function ThemeOverrideSection({
|
|
|
5530
5528
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
5531
5529
|
const raw = useFormField(schemaKey);
|
|
5532
5530
|
const value = {
|
|
5533
|
-
useOverride: raw?.useOverride ??
|
|
5534
|
-
primaryColor: raw?.primaryColor ??
|
|
5535
|
-
primaryShade: raw?.primaryShade ??
|
|
5536
|
-
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme :
|
|
5531
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
5532
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
5533
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
5534
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
5537
5535
|
};
|
|
5538
5536
|
const { setValue } = useFormActions();
|
|
5539
5537
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -5740,6 +5738,403 @@ function SwatchTile({
|
|
|
5740
5738
|
) })
|
|
5741
5739
|
] });
|
|
5742
5740
|
}
|
|
5741
|
+
function usePlayers(opts = {}) {
|
|
5742
|
+
const {
|
|
5743
|
+
includeOffline = false,
|
|
5744
|
+
search = "",
|
|
5745
|
+
limit = 50,
|
|
5746
|
+
staleTimeMs,
|
|
5747
|
+
refetchIntervalMs
|
|
5748
|
+
} = opts;
|
|
5749
|
+
const query = reactQuery.useQuery({
|
|
5750
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
5751
|
+
queryFn: async () => {
|
|
5752
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
5753
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
5754
|
+
const result = await fetchNui(
|
|
5755
|
+
"ADMIN_TOOL_QUERY",
|
|
5756
|
+
payload,
|
|
5757
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
5758
|
+
// dev shell isn't blank.
|
|
5759
|
+
includeOffline ? [
|
|
5760
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
5761
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
5762
|
+
] : [
|
|
5763
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
5764
|
+
]
|
|
5765
|
+
);
|
|
5766
|
+
return Array.isArray(result) ? result : [];
|
|
5767
|
+
},
|
|
5768
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
5769
|
+
gcTime: 5 * 6e4,
|
|
5770
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
5771
|
+
refetchOnWindowFocus: false,
|
|
5772
|
+
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
5773
|
+
});
|
|
5774
|
+
return {
|
|
5775
|
+
players: query.data ?? [],
|
|
5776
|
+
isLoading: query.isLoading,
|
|
5777
|
+
isFetching: query.isFetching,
|
|
5778
|
+
error: query.error ?? null,
|
|
5779
|
+
refresh: () => query.refetch()
|
|
5780
|
+
};
|
|
5781
|
+
}
|
|
5782
|
+
var DEBOUNCE_MS = 300;
|
|
5783
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
5784
|
+
var OFFLINE_COLOR = "#E54141";
|
|
5785
|
+
function PlayerSelect({
|
|
5786
|
+
value,
|
|
5787
|
+
onChange,
|
|
5788
|
+
includeOffline = false,
|
|
5789
|
+
limit = 50,
|
|
5790
|
+
searchable: searchableProp,
|
|
5791
|
+
placeholder,
|
|
5792
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
5793
|
+
loadingLabel = "Loading\u2026",
|
|
5794
|
+
onlineLabel = "Online",
|
|
5795
|
+
offlineLabel = "Offline",
|
|
5796
|
+
refreshLabel = "Refresh player list",
|
|
5797
|
+
...rest
|
|
5798
|
+
}) {
|
|
5799
|
+
const theme = core.useMantineTheme();
|
|
5800
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
5801
|
+
const [searchInput, setSearchInput] = react.useState("");
|
|
5802
|
+
const [debouncedSearch, setDebouncedSearch] = react.useState("");
|
|
5803
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
5804
|
+
includeOffline,
|
|
5805
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
5806
|
+
limit
|
|
5807
|
+
});
|
|
5808
|
+
const sortedPlayers = react.useMemo(
|
|
5809
|
+
() => [...players].sort((a, b) => {
|
|
5810
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
5811
|
+
return a.charName.localeCompare(b.charName);
|
|
5812
|
+
}),
|
|
5813
|
+
[players]
|
|
5814
|
+
);
|
|
5815
|
+
const playerByCitizen = react.useMemo(() => {
|
|
5816
|
+
const m = /* @__PURE__ */ new Map();
|
|
5817
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
5818
|
+
return m;
|
|
5819
|
+
}, [sortedPlayers]);
|
|
5820
|
+
const data = react.useMemo(() => {
|
|
5821
|
+
const items = sortedPlayers.map((p) => ({
|
|
5822
|
+
value: p.citizenId,
|
|
5823
|
+
label: formatLabel(p)
|
|
5824
|
+
}));
|
|
5825
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
5826
|
+
items.unshift({ value, label: value });
|
|
5827
|
+
}
|
|
5828
|
+
return items;
|
|
5829
|
+
}, [sortedPlayers, value]);
|
|
5830
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
5831
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
5832
|
+
react.useEffect(() => {
|
|
5833
|
+
if (!includeOffline) return;
|
|
5834
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
5835
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
5836
|
+
return () => clearTimeout(t4);
|
|
5837
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
5838
|
+
const renderOption = ({ option }) => {
|
|
5839
|
+
const p = playerByCitizen.get(option.value);
|
|
5840
|
+
if (!p) return option.label;
|
|
5841
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
5842
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
5843
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
5844
|
+
] });
|
|
5845
|
+
};
|
|
5846
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5847
|
+
core.Select,
|
|
5848
|
+
{
|
|
5849
|
+
...rest,
|
|
5850
|
+
data,
|
|
5851
|
+
value: value ?? null,
|
|
5852
|
+
onChange: (v) => {
|
|
5853
|
+
if (!v) return onChange(null);
|
|
5854
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
5855
|
+
onChange(player);
|
|
5856
|
+
},
|
|
5857
|
+
searchable: searchableProp ?? true,
|
|
5858
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
5859
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
5860
|
+
placeholder,
|
|
5861
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
5862
|
+
maxDropdownHeight: 300,
|
|
5863
|
+
renderOption,
|
|
5864
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
5865
|
+
rightSectionWidth: "3.5vh",
|
|
5866
|
+
rightSectionPointerEvents: "all",
|
|
5867
|
+
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5868
|
+
core.ActionIcon,
|
|
5869
|
+
{
|
|
5870
|
+
variant: "subtle",
|
|
5871
|
+
size: "sm",
|
|
5872
|
+
onClick: (e) => {
|
|
5873
|
+
e.stopPropagation();
|
|
5874
|
+
refresh();
|
|
5875
|
+
},
|
|
5876
|
+
"aria-label": refreshLabel,
|
|
5877
|
+
title: refreshLabel,
|
|
5878
|
+
style: { marginRight: "0.6vh" },
|
|
5879
|
+
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
5880
|
+
}
|
|
5881
|
+
)
|
|
5882
|
+
}
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
5886
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5887
|
+
"span",
|
|
5888
|
+
{
|
|
5889
|
+
title: online ? onlineLabel : offlineLabel,
|
|
5890
|
+
style: {
|
|
5891
|
+
display: "inline-block",
|
|
5892
|
+
width: "0.9vh",
|
|
5893
|
+
height: "0.9vh",
|
|
5894
|
+
borderRadius: "50%",
|
|
5895
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
5896
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
5897
|
+
flexShrink: 0
|
|
5898
|
+
}
|
|
5899
|
+
}
|
|
5900
|
+
);
|
|
5901
|
+
}
|
|
5902
|
+
function formatLabel(p) {
|
|
5903
|
+
const parts = [p.charName || p.citizenId];
|
|
5904
|
+
if (p.online) {
|
|
5905
|
+
if (p.name) parts.push(p.name);
|
|
5906
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
5907
|
+
}
|
|
5908
|
+
return parts.join(" \xB7 ");
|
|
5909
|
+
}
|
|
5910
|
+
var t = (key, fallback) => {
|
|
5911
|
+
const v = locale(key);
|
|
5912
|
+
return v === key ? fallback : v;
|
|
5913
|
+
};
|
|
5914
|
+
var DEFAULT_VALUE = {
|
|
5915
|
+
groups: [],
|
|
5916
|
+
identifiers: []
|
|
5917
|
+
};
|
|
5918
|
+
function SectionLabel({ icon: Icon, label }) {
|
|
5919
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
5920
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
5921
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label }),
|
|
5922
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
5923
|
+
] });
|
|
5924
|
+
}
|
|
5925
|
+
function EmptyHint({ text }) {
|
|
5926
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
5927
|
+
}
|
|
5928
|
+
function AccessOverrideSection({
|
|
5929
|
+
schemaKey = "access",
|
|
5930
|
+
title,
|
|
5931
|
+
description,
|
|
5932
|
+
groupType,
|
|
5933
|
+
includeOffline = true
|
|
5934
|
+
}) {
|
|
5935
|
+
const mantineTheme = core.useMantineTheme();
|
|
5936
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
5937
|
+
const raw = useFormField(schemaKey);
|
|
5938
|
+
const value = {
|
|
5939
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
5940
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
5941
|
+
};
|
|
5942
|
+
const { setValue } = useFormActions();
|
|
5943
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
5944
|
+
const [addingGroup, setAddingGroup] = react.useState(false);
|
|
5945
|
+
const [addingPlayer, setAddingPlayer] = react.useState(false);
|
|
5946
|
+
const commitGroup = (name) => {
|
|
5947
|
+
if (!name) return;
|
|
5948
|
+
set("groups", [...value.groups, name]);
|
|
5949
|
+
setAddingGroup(false);
|
|
5950
|
+
};
|
|
5951
|
+
const setGroup = (index, name) => {
|
|
5952
|
+
const next = [...value.groups];
|
|
5953
|
+
next[index] = name;
|
|
5954
|
+
set("groups", next.filter((g) => g !== ""));
|
|
5955
|
+
};
|
|
5956
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
5957
|
+
const commitIdentifier = (id) => {
|
|
5958
|
+
if (!id) return;
|
|
5959
|
+
set("identifiers", [...value.identifiers, id]);
|
|
5960
|
+
setAddingPlayer(false);
|
|
5961
|
+
};
|
|
5962
|
+
const setIdentifier = (index, id) => {
|
|
5963
|
+
const next = [...value.identifiers];
|
|
5964
|
+
next[index] = id;
|
|
5965
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
5966
|
+
};
|
|
5967
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
5968
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5969
|
+
core.Flex,
|
|
5970
|
+
{
|
|
5971
|
+
direction: "column",
|
|
5972
|
+
gap: "xs",
|
|
5973
|
+
p: "sm",
|
|
5974
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
5975
|
+
children: [
|
|
5976
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5977
|
+
AdminPageTitle,
|
|
5978
|
+
{
|
|
5979
|
+
icon: lucideReact.ShieldCheck,
|
|
5980
|
+
title: title || t("Access", "Access"),
|
|
5981
|
+
color
|
|
5982
|
+
}
|
|
5983
|
+
),
|
|
5984
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description || t(
|
|
5985
|
+
"AccessOverrideDesc",
|
|
5986
|
+
"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."
|
|
5987
|
+
) }),
|
|
5988
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.Users, label: t("AccessGroups", "Groups") }),
|
|
5989
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
5990
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsxRuntime.jsx(EmptyHint, { text: t("AccessNoGroups", "No groups added.") }),
|
|
5991
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
5992
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5993
|
+
GroupName,
|
|
5994
|
+
{
|
|
5995
|
+
value: name,
|
|
5996
|
+
onChange: (v) => setGroup(i, v),
|
|
5997
|
+
type: groupType,
|
|
5998
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
5999
|
+
style: { flex: 1 }
|
|
6000
|
+
}
|
|
6001
|
+
),
|
|
6002
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6003
|
+
core.ActionIcon,
|
|
6004
|
+
{
|
|
6005
|
+
variant: "subtle",
|
|
6006
|
+
color: "red",
|
|
6007
|
+
size: "md",
|
|
6008
|
+
onClick: () => removeGroup(i),
|
|
6009
|
+
title: t("Remove", "Remove"),
|
|
6010
|
+
"aria-label": t("Remove", "Remove"),
|
|
6011
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
6012
|
+
}
|
|
6013
|
+
)
|
|
6014
|
+
] }, i)),
|
|
6015
|
+
addingGroup && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
6016
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6017
|
+
GroupName,
|
|
6018
|
+
{
|
|
6019
|
+
value: "",
|
|
6020
|
+
onChange: (v) => commitGroup(v),
|
|
6021
|
+
type: groupType,
|
|
6022
|
+
placeholder: t("AccessPickGroup", "Pick a group\u2026"),
|
|
6023
|
+
style: { flex: 1 }
|
|
6024
|
+
}
|
|
6025
|
+
),
|
|
6026
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6027
|
+
core.ActionIcon,
|
|
6028
|
+
{
|
|
6029
|
+
variant: "subtle",
|
|
6030
|
+
color: "red",
|
|
6031
|
+
size: "md",
|
|
6032
|
+
onClick: () => setAddingGroup(false),
|
|
6033
|
+
title: t("Remove", "Remove"),
|
|
6034
|
+
"aria-label": t("Remove", "Remove"),
|
|
6035
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
6036
|
+
}
|
|
6037
|
+
)
|
|
6038
|
+
] })
|
|
6039
|
+
] }),
|
|
6040
|
+
!addingGroup && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
6041
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.UserRound, label: t("AccessPlayers", "Players") }),
|
|
6042
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
6043
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
6044
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
6045
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6046
|
+
PlayerSelect,
|
|
6047
|
+
{
|
|
6048
|
+
value: id || null,
|
|
6049
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
6050
|
+
includeOffline,
|
|
6051
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
6052
|
+
style: { flex: 1 },
|
|
6053
|
+
size: "xs"
|
|
6054
|
+
}
|
|
6055
|
+
),
|
|
6056
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6057
|
+
core.ActionIcon,
|
|
6058
|
+
{
|
|
6059
|
+
variant: "subtle",
|
|
6060
|
+
color: "red",
|
|
6061
|
+
size: "md",
|
|
6062
|
+
onClick: () => removeIdentifier(i),
|
|
6063
|
+
title: t("Remove", "Remove"),
|
|
6064
|
+
"aria-label": t("Remove", "Remove"),
|
|
6065
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
6066
|
+
}
|
|
6067
|
+
)
|
|
6068
|
+
] }, i)),
|
|
6069
|
+
addingPlayer && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
6070
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6071
|
+
PlayerSelect,
|
|
6072
|
+
{
|
|
6073
|
+
value: null,
|
|
6074
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
6075
|
+
includeOffline,
|
|
6076
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
6077
|
+
style: { flex: 1 },
|
|
6078
|
+
size: "xs"
|
|
6079
|
+
}
|
|
6080
|
+
),
|
|
6081
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6082
|
+
core.ActionIcon,
|
|
6083
|
+
{
|
|
6084
|
+
variant: "subtle",
|
|
6085
|
+
color: "red",
|
|
6086
|
+
size: "md",
|
|
6087
|
+
onClick: () => setAddingPlayer(false),
|
|
6088
|
+
title: t("Remove", "Remove"),
|
|
6089
|
+
"aria-label": t("Remove", "Remove"),
|
|
6090
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
6091
|
+
}
|
|
6092
|
+
)
|
|
6093
|
+
] })
|
|
6094
|
+
] }),
|
|
6095
|
+
!addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
6096
|
+
]
|
|
6097
|
+
}
|
|
6098
|
+
);
|
|
6099
|
+
}
|
|
6100
|
+
function AddRowButton({ label, onClick }) {
|
|
6101
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6102
|
+
core.Flex,
|
|
6103
|
+
{
|
|
6104
|
+
align: "center",
|
|
6105
|
+
justify: "center",
|
|
6106
|
+
gap: "xs",
|
|
6107
|
+
onClick,
|
|
6108
|
+
role: "button",
|
|
6109
|
+
tabIndex: 0,
|
|
6110
|
+
onKeyDown: (e) => {
|
|
6111
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
6112
|
+
e.preventDefault();
|
|
6113
|
+
onClick();
|
|
6114
|
+
}
|
|
6115
|
+
},
|
|
6116
|
+
py: "xs",
|
|
6117
|
+
style: {
|
|
6118
|
+
cursor: "pointer",
|
|
6119
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
6120
|
+
borderRadius: "0.4vh",
|
|
6121
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
6122
|
+
},
|
|
6123
|
+
onMouseEnter: (e) => {
|
|
6124
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
6125
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
6126
|
+
},
|
|
6127
|
+
onMouseLeave: (e) => {
|
|
6128
|
+
e.currentTarget.style.background = "transparent";
|
|
6129
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
6130
|
+
},
|
|
6131
|
+
children: [
|
|
6132
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
6133
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label })
|
|
6134
|
+
]
|
|
6135
|
+
}
|
|
6136
|
+
);
|
|
6137
|
+
}
|
|
5743
6138
|
|
|
5744
6139
|
// src/utils/gtaAnimPostFx.ts
|
|
5745
6140
|
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
@@ -6329,7 +6724,7 @@ function ScenarioSelect({
|
|
|
6329
6724
|
}
|
|
6330
6725
|
);
|
|
6331
6726
|
}
|
|
6332
|
-
var
|
|
6727
|
+
var t2 = (key, fallback) => {
|
|
6333
6728
|
const v = locale(key);
|
|
6334
6729
|
return v === key ? fallback : v;
|
|
6335
6730
|
};
|
|
@@ -6397,7 +6792,7 @@ function DiscordRoleSelect(props) {
|
|
|
6397
6792
|
return map;
|
|
6398
6793
|
}, [roles]);
|
|
6399
6794
|
if (errorCode === "NotConfigured") {
|
|
6400
|
-
const notConfiguredPlaceholder =
|
|
6795
|
+
const notConfiguredPlaceholder = t2(
|
|
6401
6796
|
"DiscordNotConfigured",
|
|
6402
6797
|
"Not configured \u2014 set in /dirk_lib"
|
|
6403
6798
|
);
|
|
@@ -6465,9 +6860,9 @@ function DiscordRoleSelect(props) {
|
|
|
6465
6860
|
e.stopPropagation();
|
|
6466
6861
|
refresh();
|
|
6467
6862
|
},
|
|
6468
|
-
title:
|
|
6863
|
+
title: t2("Refresh", "Refresh"),
|
|
6469
6864
|
loading,
|
|
6470
|
-
"aria-label":
|
|
6865
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
6471
6866
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
6472
6867
|
}
|
|
6473
6868
|
);
|
|
@@ -6477,7 +6872,7 @@ function DiscordRoleSelect(props) {
|
|
|
6477
6872
|
{
|
|
6478
6873
|
label,
|
|
6479
6874
|
size,
|
|
6480
|
-
placeholder: placeholder ||
|
|
6875
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
6481
6876
|
data,
|
|
6482
6877
|
value: props.value || [],
|
|
6483
6878
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -6489,7 +6884,7 @@ function DiscordRoleSelect(props) {
|
|
|
6489
6884
|
rightSectionPointerEvents: "all",
|
|
6490
6885
|
style,
|
|
6491
6886
|
styles,
|
|
6492
|
-
nothingFoundMessage: errorCode ? `${
|
|
6887
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
6493
6888
|
}
|
|
6494
6889
|
);
|
|
6495
6890
|
}
|
|
@@ -6498,7 +6893,7 @@ function DiscordRoleSelect(props) {
|
|
|
6498
6893
|
{
|
|
6499
6894
|
label,
|
|
6500
6895
|
size,
|
|
6501
|
-
placeholder: placeholder ||
|
|
6896
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
6502
6897
|
data,
|
|
6503
6898
|
value: props.value || null,
|
|
6504
6899
|
onChange: (id) => props.onChange(id),
|
|
@@ -6510,11 +6905,11 @@ function DiscordRoleSelect(props) {
|
|
|
6510
6905
|
rightSectionPointerEvents: "all",
|
|
6511
6906
|
style,
|
|
6512
6907
|
styles,
|
|
6513
|
-
nothingFoundMessage: errorCode ? `${
|
|
6908
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
6514
6909
|
}
|
|
6515
6910
|
);
|
|
6516
6911
|
}
|
|
6517
|
-
var
|
|
6912
|
+
var t3 = (key, fallback) => {
|
|
6518
6913
|
const v = locale(key);
|
|
6519
6914
|
return v === key ? fallback : v;
|
|
6520
6915
|
};
|
|
@@ -6535,7 +6930,7 @@ function FrameworkHint({ framework }) {
|
|
|
6535
6930
|
const theme = core.useMantineTheme();
|
|
6536
6931
|
if (!framework) return null;
|
|
6537
6932
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
6538
|
-
const text =
|
|
6933
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
6539
6934
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6540
6935
|
core.Flex,
|
|
6541
6936
|
{
|
|
@@ -6619,9 +7014,9 @@ function AccountSelect(props) {
|
|
|
6619
7014
|
e.stopPropagation();
|
|
6620
7015
|
refresh();
|
|
6621
7016
|
},
|
|
6622
|
-
title:
|
|
7017
|
+
title: t3("Refresh", "Refresh"),
|
|
6623
7018
|
loading,
|
|
6624
|
-
"aria-label":
|
|
7019
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
6625
7020
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
6626
7021
|
}
|
|
6627
7022
|
);
|
|
@@ -6635,14 +7030,14 @@ function AccountSelect(props) {
|
|
|
6635
7030
|
rightSection: refreshButton,
|
|
6636
7031
|
rightSectionPointerEvents: "all",
|
|
6637
7032
|
style,
|
|
6638
|
-
nothingFoundMessage:
|
|
7033
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
6639
7034
|
};
|
|
6640
7035
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
6641
7036
|
props.multi ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6642
7037
|
core.MultiSelect,
|
|
6643
7038
|
{
|
|
6644
7039
|
...sharedSelectProps,
|
|
6645
|
-
placeholder: placeholder ||
|
|
7040
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
6646
7041
|
value: props.value || [],
|
|
6647
7042
|
onChange: (names) => props.onChange(names),
|
|
6648
7043
|
renderOption,
|
|
@@ -6654,7 +7049,7 @@ function AccountSelect(props) {
|
|
|
6654
7049
|
core.Select,
|
|
6655
7050
|
{
|
|
6656
7051
|
...sharedSelectProps,
|
|
6657
|
-
placeholder: placeholder ||
|
|
7052
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
6658
7053
|
value: props.value || null,
|
|
6659
7054
|
onChange: (name) => props.onChange(name),
|
|
6660
7055
|
renderOption,
|
|
@@ -6946,175 +7341,6 @@ function WorldPositionGotoButton2({
|
|
|
6946
7341
|
}
|
|
6947
7342
|
) });
|
|
6948
7343
|
}
|
|
6949
|
-
function usePlayers(opts = {}) {
|
|
6950
|
-
const {
|
|
6951
|
-
includeOffline = false,
|
|
6952
|
-
search = "",
|
|
6953
|
-
limit = 50,
|
|
6954
|
-
staleTimeMs,
|
|
6955
|
-
refetchIntervalMs
|
|
6956
|
-
} = opts;
|
|
6957
|
-
const query = reactQuery.useQuery({
|
|
6958
|
-
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6959
|
-
queryFn: async () => {
|
|
6960
|
-
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6961
|
-
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6962
|
-
const result = await fetchNui(
|
|
6963
|
-
"ADMIN_TOOL_QUERY",
|
|
6964
|
-
payload,
|
|
6965
|
-
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6966
|
-
// dev shell isn't blank.
|
|
6967
|
-
includeOffline ? [
|
|
6968
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6969
|
-
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6970
|
-
] : [
|
|
6971
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6972
|
-
]
|
|
6973
|
-
);
|
|
6974
|
-
return Array.isArray(result) ? result : [];
|
|
6975
|
-
},
|
|
6976
|
-
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6977
|
-
gcTime: 5 * 6e4,
|
|
6978
|
-
refetchInterval: refetchIntervalMs ?? false,
|
|
6979
|
-
refetchOnWindowFocus: false,
|
|
6980
|
-
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
6981
|
-
});
|
|
6982
|
-
return {
|
|
6983
|
-
players: query.data ?? [],
|
|
6984
|
-
isLoading: query.isLoading,
|
|
6985
|
-
isFetching: query.isFetching,
|
|
6986
|
-
error: query.error ?? null,
|
|
6987
|
-
refresh: () => query.refetch()
|
|
6988
|
-
};
|
|
6989
|
-
}
|
|
6990
|
-
var DEBOUNCE_MS = 300;
|
|
6991
|
-
var ONLINE_COLOR = "#3FA83F";
|
|
6992
|
-
var OFFLINE_COLOR = "#E54141";
|
|
6993
|
-
function PlayerSelect({
|
|
6994
|
-
value,
|
|
6995
|
-
onChange,
|
|
6996
|
-
includeOffline = false,
|
|
6997
|
-
limit = 50,
|
|
6998
|
-
searchable: searchableProp,
|
|
6999
|
-
placeholder,
|
|
7000
|
-
nothingFoundMessage: nothingFoundMessageProp,
|
|
7001
|
-
loadingLabel = "Loading\u2026",
|
|
7002
|
-
onlineLabel = "Online",
|
|
7003
|
-
offlineLabel = "Offline",
|
|
7004
|
-
refreshLabel = "Refresh player list",
|
|
7005
|
-
...rest
|
|
7006
|
-
}) {
|
|
7007
|
-
const theme = core.useMantineTheme();
|
|
7008
|
-
const color = theme.colors[theme.primaryColor][5];
|
|
7009
|
-
const [searchInput, setSearchInput] = react.useState("");
|
|
7010
|
-
const [debouncedSearch, setDebouncedSearch] = react.useState("");
|
|
7011
|
-
const { players, isFetching, refresh } = usePlayers({
|
|
7012
|
-
includeOffline,
|
|
7013
|
-
search: includeOffline ? debouncedSearch : void 0,
|
|
7014
|
-
limit
|
|
7015
|
-
});
|
|
7016
|
-
const sortedPlayers = react.useMemo(
|
|
7017
|
-
() => [...players].sort((a, b) => {
|
|
7018
|
-
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
7019
|
-
return a.charName.localeCompare(b.charName);
|
|
7020
|
-
}),
|
|
7021
|
-
[players]
|
|
7022
|
-
);
|
|
7023
|
-
const playerByCitizen = react.useMemo(() => {
|
|
7024
|
-
const m = /* @__PURE__ */ new Map();
|
|
7025
|
-
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
7026
|
-
return m;
|
|
7027
|
-
}, [sortedPlayers]);
|
|
7028
|
-
const data = react.useMemo(() => {
|
|
7029
|
-
const items = sortedPlayers.map((p) => ({
|
|
7030
|
-
value: p.citizenId,
|
|
7031
|
-
label: formatLabel(p)
|
|
7032
|
-
}));
|
|
7033
|
-
if (value && !items.some((i) => i.value === value)) {
|
|
7034
|
-
items.unshift({ value, label: value });
|
|
7035
|
-
}
|
|
7036
|
-
return items;
|
|
7037
|
-
}, [sortedPlayers, value]);
|
|
7038
|
-
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
7039
|
-
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
7040
|
-
react.useEffect(() => {
|
|
7041
|
-
if (!includeOffline) return;
|
|
7042
|
-
if (selectedLabel && searchInput === selectedLabel) return;
|
|
7043
|
-
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
7044
|
-
return () => clearTimeout(t3);
|
|
7045
|
-
}, [searchInput, includeOffline, selectedLabel]);
|
|
7046
|
-
const renderOption = ({ option }) => {
|
|
7047
|
-
const p = playerByCitizen.get(option.value);
|
|
7048
|
-
if (!p) return option.label;
|
|
7049
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
7050
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
7051
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
7052
|
-
] });
|
|
7053
|
-
};
|
|
7054
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7055
|
-
core.Select,
|
|
7056
|
-
{
|
|
7057
|
-
...rest,
|
|
7058
|
-
data,
|
|
7059
|
-
value: value ?? null,
|
|
7060
|
-
onChange: (v) => {
|
|
7061
|
-
if (!v) return onChange(null);
|
|
7062
|
-
const player = playerByCitizen.get(v) ?? null;
|
|
7063
|
-
onChange(player);
|
|
7064
|
-
},
|
|
7065
|
-
searchable: searchableProp ?? true,
|
|
7066
|
-
searchValue: includeOffline ? searchInput : void 0,
|
|
7067
|
-
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
7068
|
-
placeholder,
|
|
7069
|
-
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
7070
|
-
maxDropdownHeight: 300,
|
|
7071
|
-
renderOption,
|
|
7072
|
-
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
7073
|
-
rightSectionWidth: "3.5vh",
|
|
7074
|
-
rightSectionPointerEvents: "all",
|
|
7075
|
-
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7076
|
-
core.ActionIcon,
|
|
7077
|
-
{
|
|
7078
|
-
variant: "subtle",
|
|
7079
|
-
size: "sm",
|
|
7080
|
-
onClick: (e) => {
|
|
7081
|
-
e.stopPropagation();
|
|
7082
|
-
refresh();
|
|
7083
|
-
},
|
|
7084
|
-
"aria-label": refreshLabel,
|
|
7085
|
-
title: refreshLabel,
|
|
7086
|
-
style: { marginRight: "0.6vh" },
|
|
7087
|
-
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
7088
|
-
}
|
|
7089
|
-
)
|
|
7090
|
-
}
|
|
7091
|
-
);
|
|
7092
|
-
}
|
|
7093
|
-
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7094
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7095
|
-
"span",
|
|
7096
|
-
{
|
|
7097
|
-
title: online ? onlineLabel : offlineLabel,
|
|
7098
|
-
style: {
|
|
7099
|
-
display: "inline-block",
|
|
7100
|
-
width: "0.9vh",
|
|
7101
|
-
height: "0.9vh",
|
|
7102
|
-
borderRadius: "50%",
|
|
7103
|
-
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7104
|
-
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7105
|
-
flexShrink: 0
|
|
7106
|
-
}
|
|
7107
|
-
}
|
|
7108
|
-
);
|
|
7109
|
-
}
|
|
7110
|
-
function formatLabel(p) {
|
|
7111
|
-
const parts = [p.charName || p.citizenId];
|
|
7112
|
-
if (p.online) {
|
|
7113
|
-
if (p.name) parts.push(p.name);
|
|
7114
|
-
if (p.id != null) parts.push(`#${p.id}`);
|
|
7115
|
-
}
|
|
7116
|
-
return parts.join(" \xB7 ");
|
|
7117
|
-
}
|
|
7118
7344
|
function usePickDoor() {
|
|
7119
7345
|
const begin = useAdminToolStore((s) => s.begin);
|
|
7120
7346
|
return async () => {
|
|
@@ -7391,6 +7617,7 @@ function BlipMarker({
|
|
|
7391
7617
|
);
|
|
7392
7618
|
}
|
|
7393
7619
|
|
|
7620
|
+
exports.AccessOverrideSection = AccessOverrideSection;
|
|
7394
7621
|
exports.AccountSelect = AccountSelect;
|
|
7395
7622
|
exports.AdminPageTitle = AdminPageTitle;
|
|
7396
7623
|
exports.AnimPostFxSelect = AnimPostFxSelect;
|