dirk-cfx-react 1.1.90 → 1.1.92
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 +540 -227
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +35 -9
- package/dist/components/index.d.ts +35 -9
- package/dist/components/index.js +541 -229
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/index.cjs +55 -25
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +55 -25
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +782 -447
- 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 +780 -449
- 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, Plus, UserRound, 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;
|
|
@@ -1261,11 +1261,11 @@ var colorNames = {
|
|
|
1261
1261
|
Yellow: { r: 255, g: 255, b: 0 },
|
|
1262
1262
|
YellowGreen: { r: 154, g: 205, b: 50 }
|
|
1263
1263
|
};
|
|
1264
|
-
function colorWithAlpha(color,
|
|
1264
|
+
function colorWithAlpha(color, alpha19) {
|
|
1265
1265
|
const lowerCasedColor = color.toLowerCase();
|
|
1266
1266
|
if (colorNames[lowerCasedColor]) {
|
|
1267
1267
|
const rgb = colorNames[lowerCasedColor];
|
|
1268
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${
|
|
1268
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha19})`;
|
|
1269
1269
|
}
|
|
1270
1270
|
if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
|
|
1271
1271
|
const hex = color.slice(1);
|
|
@@ -1273,12 +1273,12 @@ function colorWithAlpha(color, alpha18) {
|
|
|
1273
1273
|
const r = bigint >> 16 & 255;
|
|
1274
1274
|
const g = bigint >> 8 & 255;
|
|
1275
1275
|
const b = bigint & 255;
|
|
1276
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
1276
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha19})`;
|
|
1277
1277
|
}
|
|
1278
1278
|
if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
|
|
1279
1279
|
const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
|
|
1280
1280
|
if (result) {
|
|
1281
|
-
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${
|
|
1281
|
+
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha19})`;
|
|
1282
1282
|
}
|
|
1283
1283
|
}
|
|
1284
1284
|
return color;
|
|
@@ -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);
|
|
@@ -4663,6 +4678,16 @@ function mergeMantineThemeSafe(base, custom, override) {
|
|
|
4663
4678
|
}
|
|
4664
4679
|
};
|
|
4665
4680
|
}
|
|
4681
|
+
function changedTopLevelSections(changedFields) {
|
|
4682
|
+
if (!changedFields || changedFields.length === 0) return [];
|
|
4683
|
+
const sections = /* @__PURE__ */ new Set();
|
|
4684
|
+
for (const path of changedFields) {
|
|
4685
|
+
if (typeof path !== "string" || path.length === 0) continue;
|
|
4686
|
+
const dot = path.indexOf(".");
|
|
4687
|
+
sections.add(dot === -1 ? path : path.slice(0, dot));
|
|
4688
|
+
}
|
|
4689
|
+
return Array.from(sections);
|
|
4690
|
+
}
|
|
4666
4691
|
var _instance = null;
|
|
4667
4692
|
function getScriptConfigInstance() {
|
|
4668
4693
|
if (!_instance) throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
|
|
@@ -4672,15 +4697,18 @@ function createScriptConfig(defaultValue) {
|
|
|
4672
4697
|
const store2 = create(() => defaultValue);
|
|
4673
4698
|
let clientVersion = 0;
|
|
4674
4699
|
const useScriptConfigHooks = () => {
|
|
4675
|
-
useNuiEvent(
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4700
|
+
useNuiEvent(
|
|
4701
|
+
"UPDATE_SCRIPT_CONFIG",
|
|
4702
|
+
(data) => {
|
|
4703
|
+
if (!data) return;
|
|
4704
|
+
if (typeof data.clientVersion === "number") {
|
|
4705
|
+
clientVersion = data.clientVersion;
|
|
4706
|
+
}
|
|
4707
|
+
if (data.config && typeof data.config === "object") {
|
|
4708
|
+
store2.setState((prev) => ({ ...prev, ...data.config }));
|
|
4709
|
+
}
|
|
4682
4710
|
}
|
|
4683
|
-
|
|
4711
|
+
);
|
|
4684
4712
|
};
|
|
4685
4713
|
const fetchScriptConfig = async () => {
|
|
4686
4714
|
try {
|
|
@@ -4696,12 +4724,19 @@ function createScriptConfig(defaultValue) {
|
|
|
4696
4724
|
}
|
|
4697
4725
|
return null;
|
|
4698
4726
|
};
|
|
4699
|
-
const updateScriptConfig = async (newConfig) => {
|
|
4727
|
+
const updateScriptConfig = async (newConfig, changedFields) => {
|
|
4700
4728
|
store2.setState((prev) => ({ ...prev, ...newConfig }));
|
|
4701
|
-
const
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4729
|
+
const sections = changedTopLevelSections(changedFields);
|
|
4730
|
+
let payload;
|
|
4731
|
+
if (sections.length > 0) {
|
|
4732
|
+
const current = store2.getState();
|
|
4733
|
+
const delta = {};
|
|
4734
|
+
for (const key of sections) delta[key] = current[key];
|
|
4735
|
+
payload = { data: delta, expectedVersion: clientVersion, sectionReplace: true };
|
|
4736
|
+
} else {
|
|
4737
|
+
payload = { data: newConfig, expectedVersion: clientVersion };
|
|
4738
|
+
}
|
|
4739
|
+
const response = await fetchNui("UPDATE_SCRIPT_CONFIG", payload);
|
|
4705
4740
|
if (response?.meta?.client_version != null) {
|
|
4706
4741
|
clientVersion = response.meta.client_version;
|
|
4707
4742
|
}
|
|
@@ -5570,7 +5605,7 @@ function ConfigPanel(props) {
|
|
|
5570
5605
|
if (isSaving) return;
|
|
5571
5606
|
setIsSaving(true);
|
|
5572
5607
|
try {
|
|
5573
|
-
const result = await updateConfig(form.values);
|
|
5608
|
+
const result = await updateConfig(form.values, form.changedFields);
|
|
5574
5609
|
if (result?.success) {
|
|
5575
5610
|
form.reinitialize(cloneConfig(form.values));
|
|
5576
5611
|
dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
|
|
@@ -6604,24 +6639,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
6604
6639
|
"yellow",
|
|
6605
6640
|
"orange"
|
|
6606
6641
|
].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
6642
|
function GroupLabel({ label: label2 }) {
|
|
6626
6643
|
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
6627
6644
|
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
@@ -6636,10 +6653,10 @@ function ThemeOverrideSection({
|
|
|
6636
6653
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
6637
6654
|
const raw = useFormField(schemaKey);
|
|
6638
6655
|
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 :
|
|
6656
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
6657
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
6658
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
6659
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
6643
6660
|
};
|
|
6644
6661
|
const { setValue } = useFormActions();
|
|
6645
6662
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -6846,212 +6863,695 @@ function SwatchTile({
|
|
|
6846
6863
|
) })
|
|
6847
6864
|
] });
|
|
6848
6865
|
}
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
{
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
]
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
return
|
|
7029
|
-
}
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
});
|
|
7052
|
-
const
|
|
7053
|
-
const
|
|
7054
|
-
|
|
6866
|
+
function usePlayers(opts = {}) {
|
|
6867
|
+
const {
|
|
6868
|
+
includeOffline = false,
|
|
6869
|
+
search = "",
|
|
6870
|
+
limit = 50,
|
|
6871
|
+
staleTimeMs,
|
|
6872
|
+
refetchIntervalMs
|
|
6873
|
+
} = opts;
|
|
6874
|
+
const query = useQuery({
|
|
6875
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6876
|
+
queryFn: async () => {
|
|
6877
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6878
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6879
|
+
const result = await fetchNui(
|
|
6880
|
+
"ADMIN_TOOL_QUERY",
|
|
6881
|
+
payload,
|
|
6882
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6883
|
+
// dev shell isn't blank.
|
|
6884
|
+
includeOffline ? [
|
|
6885
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6886
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6887
|
+
] : [
|
|
6888
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6889
|
+
]
|
|
6890
|
+
);
|
|
6891
|
+
return Array.isArray(result) ? result : [];
|
|
6892
|
+
},
|
|
6893
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6894
|
+
gcTime: 5 * 6e4,
|
|
6895
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6896
|
+
refetchOnWindowFocus: false,
|
|
6897
|
+
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
6898
|
+
});
|
|
6899
|
+
return {
|
|
6900
|
+
players: query.data ?? [],
|
|
6901
|
+
isLoading: query.isLoading,
|
|
6902
|
+
isFetching: query.isFetching,
|
|
6903
|
+
error: query.error ?? null,
|
|
6904
|
+
refresh: () => query.refetch()
|
|
6905
|
+
};
|
|
6906
|
+
}
|
|
6907
|
+
var DEBOUNCE_MS = 300;
|
|
6908
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6909
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6910
|
+
function PlayerSelect({
|
|
6911
|
+
value,
|
|
6912
|
+
onChange,
|
|
6913
|
+
includeOffline = false,
|
|
6914
|
+
limit = 50,
|
|
6915
|
+
searchable: searchableProp,
|
|
6916
|
+
placeholder,
|
|
6917
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
6918
|
+
loadingLabel = "Loading\u2026",
|
|
6919
|
+
onlineLabel = "Online",
|
|
6920
|
+
offlineLabel = "Offline",
|
|
6921
|
+
refreshLabel = "Refresh player list",
|
|
6922
|
+
...rest
|
|
6923
|
+
}) {
|
|
6924
|
+
const theme2 = useMantineTheme();
|
|
6925
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
6926
|
+
const [searchInput, setSearchInput] = useState("");
|
|
6927
|
+
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
6928
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
6929
|
+
includeOffline,
|
|
6930
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
6931
|
+
limit
|
|
6932
|
+
});
|
|
6933
|
+
const sortedPlayers = useMemo(
|
|
6934
|
+
() => [...players].sort((a, b) => {
|
|
6935
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
6936
|
+
return a.charName.localeCompare(b.charName);
|
|
6937
|
+
}),
|
|
6938
|
+
[players]
|
|
6939
|
+
);
|
|
6940
|
+
const playerByCitizen = useMemo(() => {
|
|
6941
|
+
const m = /* @__PURE__ */ new Map();
|
|
6942
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
6943
|
+
return m;
|
|
6944
|
+
}, [sortedPlayers]);
|
|
6945
|
+
const data = useMemo(() => {
|
|
6946
|
+
const items = sortedPlayers.map((p) => ({
|
|
6947
|
+
value: p.citizenId,
|
|
6948
|
+
label: formatLabel(p)
|
|
6949
|
+
}));
|
|
6950
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
6951
|
+
items.unshift({ value, label: value });
|
|
6952
|
+
}
|
|
6953
|
+
return items;
|
|
6954
|
+
}, [sortedPlayers, value]);
|
|
6955
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
6956
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
6957
|
+
useEffect(() => {
|
|
6958
|
+
if (!includeOffline) return;
|
|
6959
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
6960
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
6961
|
+
return () => clearTimeout(t4);
|
|
6962
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
6963
|
+
const renderOption = ({ option }) => {
|
|
6964
|
+
const p = playerByCitizen.get(option.value);
|
|
6965
|
+
if (!p) return option.label;
|
|
6966
|
+
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
6967
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
6968
|
+
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
6969
|
+
] });
|
|
6970
|
+
};
|
|
6971
|
+
return /* @__PURE__ */ jsx(
|
|
6972
|
+
Select,
|
|
6973
|
+
{
|
|
6974
|
+
...rest,
|
|
6975
|
+
data,
|
|
6976
|
+
value: value ?? null,
|
|
6977
|
+
onChange: (v) => {
|
|
6978
|
+
if (!v) return onChange(null);
|
|
6979
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
6980
|
+
onChange(player);
|
|
6981
|
+
},
|
|
6982
|
+
searchable: searchableProp ?? true,
|
|
6983
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
6984
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
6985
|
+
placeholder,
|
|
6986
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
6987
|
+
maxDropdownHeight: 300,
|
|
6988
|
+
renderOption,
|
|
6989
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
6990
|
+
rightSectionWidth: "3.5vh",
|
|
6991
|
+
rightSectionPointerEvents: "all",
|
|
6992
|
+
rightSection: /* @__PURE__ */ jsx(
|
|
6993
|
+
ActionIcon,
|
|
6994
|
+
{
|
|
6995
|
+
variant: "subtle",
|
|
6996
|
+
size: "sm",
|
|
6997
|
+
onClick: (e) => {
|
|
6998
|
+
e.stopPropagation();
|
|
6999
|
+
refresh();
|
|
7000
|
+
},
|
|
7001
|
+
"aria-label": refreshLabel,
|
|
7002
|
+
title: refreshLabel,
|
|
7003
|
+
style: { marginRight: "0.6vh" },
|
|
7004
|
+
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
7005
|
+
}
|
|
7006
|
+
)
|
|
7007
|
+
}
|
|
7008
|
+
);
|
|
7009
|
+
}
|
|
7010
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7011
|
+
return /* @__PURE__ */ jsx(
|
|
7012
|
+
"span",
|
|
7013
|
+
{
|
|
7014
|
+
title: online ? onlineLabel : offlineLabel,
|
|
7015
|
+
style: {
|
|
7016
|
+
display: "inline-block",
|
|
7017
|
+
width: "0.9vh",
|
|
7018
|
+
height: "0.9vh",
|
|
7019
|
+
borderRadius: "50%",
|
|
7020
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7021
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7022
|
+
flexShrink: 0
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
);
|
|
7026
|
+
}
|
|
7027
|
+
function formatLabel(p) {
|
|
7028
|
+
const parts = [p.charName || p.citizenId];
|
|
7029
|
+
if (p.online) {
|
|
7030
|
+
if (p.name) parts.push(p.name);
|
|
7031
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7032
|
+
}
|
|
7033
|
+
return parts.join(" \xB7 ");
|
|
7034
|
+
}
|
|
7035
|
+
var COMMON_ACE_GROUPS = ["group.admin", "group.mod", "group.superadmin"];
|
|
7036
|
+
var t = (key, fallback) => {
|
|
7037
|
+
const v = locale(key);
|
|
7038
|
+
return v === key ? fallback : v;
|
|
7039
|
+
};
|
|
7040
|
+
var DEFAULT_VALUE = {
|
|
7041
|
+
groups: [],
|
|
7042
|
+
identifiers: []
|
|
7043
|
+
};
|
|
7044
|
+
function SectionLabel({ icon: Icon, label: label2 }) {
|
|
7045
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
7046
|
+
/* @__PURE__ */ jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
7047
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
7048
|
+
/* @__PURE__ */ jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
7049
|
+
] });
|
|
7050
|
+
}
|
|
7051
|
+
function EmptyHint({ text }) {
|
|
7052
|
+
return /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
7053
|
+
}
|
|
7054
|
+
function AccessOverrideSection({
|
|
7055
|
+
schemaKey = "access",
|
|
7056
|
+
title,
|
|
7057
|
+
description: description2,
|
|
7058
|
+
includeOffline = true
|
|
7059
|
+
}) {
|
|
7060
|
+
const mantineTheme = useMantineTheme();
|
|
7061
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
7062
|
+
const raw = useFormField(schemaKey);
|
|
7063
|
+
const value = {
|
|
7064
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
7065
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
7066
|
+
};
|
|
7067
|
+
const { setValue } = useFormActions();
|
|
7068
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
7069
|
+
const [addingGroup, setAddingGroup] = useState(false);
|
|
7070
|
+
const [addingPlayer, setAddingPlayer] = useState(false);
|
|
7071
|
+
const commitGroup = (name) => {
|
|
7072
|
+
const g = name.trim();
|
|
7073
|
+
if (!g) return;
|
|
7074
|
+
if (!value.groups.includes(g)) set("groups", [...value.groups, g]);
|
|
7075
|
+
setAddingGroup(false);
|
|
7076
|
+
};
|
|
7077
|
+
const setGroup = (index, name) => {
|
|
7078
|
+
const next = [...value.groups];
|
|
7079
|
+
next[index] = name;
|
|
7080
|
+
set("groups", next);
|
|
7081
|
+
};
|
|
7082
|
+
const quickAddGroup = (name) => {
|
|
7083
|
+
if (value.groups.includes(name)) return;
|
|
7084
|
+
set("groups", [...value.groups, name]);
|
|
7085
|
+
};
|
|
7086
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
7087
|
+
const commitIdentifier = (id) => {
|
|
7088
|
+
if (!id) return;
|
|
7089
|
+
set("identifiers", [...value.identifiers, id]);
|
|
7090
|
+
setAddingPlayer(false);
|
|
7091
|
+
};
|
|
7092
|
+
const setIdentifier = (index, id) => {
|
|
7093
|
+
const next = [...value.identifiers];
|
|
7094
|
+
next[index] = id;
|
|
7095
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
7096
|
+
};
|
|
7097
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
7098
|
+
return /* @__PURE__ */ jsxs(
|
|
7099
|
+
Flex,
|
|
7100
|
+
{
|
|
7101
|
+
direction: "column",
|
|
7102
|
+
gap: "xs",
|
|
7103
|
+
p: "sm",
|
|
7104
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
7105
|
+
children: [
|
|
7106
|
+
/* @__PURE__ */ jsx(
|
|
7107
|
+
AdminPageTitle,
|
|
7108
|
+
{
|
|
7109
|
+
icon: ShieldCheck,
|
|
7110
|
+
title: title || t("Access", "Access"),
|
|
7111
|
+
color
|
|
7112
|
+
}
|
|
7113
|
+
),
|
|
7114
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description2 || t(
|
|
7115
|
+
"AccessOverrideDesc",
|
|
7116
|
+
"Grant access to this resource's admin panel to specific ACE groups and players, in addition to your global dirk_lib admins. Enforcement is server-side."
|
|
7117
|
+
) }),
|
|
7118
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: Users, label: t("AccessGroups", "Admin groups (ACE)") }),
|
|
7119
|
+
/* @__PURE__ */ jsx(Flex, { gap: "xs", wrap: "wrap", children: COMMON_ACE_GROUPS.map((g) => {
|
|
7120
|
+
const added = value.groups.includes(g);
|
|
7121
|
+
return /* @__PURE__ */ jsxs(
|
|
7122
|
+
Flex,
|
|
7123
|
+
{
|
|
7124
|
+
align: "center",
|
|
7125
|
+
gap: "xxs",
|
|
7126
|
+
onClick: added ? void 0 : () => quickAddGroup(g),
|
|
7127
|
+
role: "button",
|
|
7128
|
+
tabIndex: added ? -1 : 0,
|
|
7129
|
+
"aria-disabled": added,
|
|
7130
|
+
onKeyDown: (e) => {
|
|
7131
|
+
if (added) return;
|
|
7132
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7133
|
+
e.preventDefault();
|
|
7134
|
+
quickAddGroup(g);
|
|
7135
|
+
}
|
|
7136
|
+
},
|
|
7137
|
+
px: "xs",
|
|
7138
|
+
py: "xxs",
|
|
7139
|
+
style: {
|
|
7140
|
+
cursor: added ? "default" : "pointer",
|
|
7141
|
+
opacity: added ? 0.4 : 1,
|
|
7142
|
+
background: alpha(color, 0.12),
|
|
7143
|
+
border: `0.1vh solid ${alpha(color, 0.4)}`,
|
|
7144
|
+
borderRadius: "0.4vh",
|
|
7145
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7146
|
+
},
|
|
7147
|
+
onMouseEnter: (e) => {
|
|
7148
|
+
if (added) return;
|
|
7149
|
+
e.currentTarget.style.background = alpha(color, 0.22);
|
|
7150
|
+
},
|
|
7151
|
+
onMouseLeave: (e) => {
|
|
7152
|
+
if (added) return;
|
|
7153
|
+
e.currentTarget.style.background = alpha(color, 0.12);
|
|
7154
|
+
},
|
|
7155
|
+
children: [
|
|
7156
|
+
!added && /* @__PURE__ */ jsx(Plus, { size: "1.2vh", color }),
|
|
7157
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", lts: "0.04em", c: color, children: g })
|
|
7158
|
+
]
|
|
7159
|
+
},
|
|
7160
|
+
g
|
|
7161
|
+
);
|
|
7162
|
+
}) }),
|
|
7163
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
7164
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsx(
|
|
7165
|
+
EmptyHint,
|
|
7166
|
+
{
|
|
7167
|
+
text: t("AccessNoGroups", "No ACE groups added. e.g. group.admin")
|
|
7168
|
+
}
|
|
7169
|
+
),
|
|
7170
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7171
|
+
/* @__PURE__ */ jsx(
|
|
7172
|
+
TextInput,
|
|
7173
|
+
{
|
|
7174
|
+
value: name,
|
|
7175
|
+
onChange: (e) => setGroup(i, e.currentTarget.value),
|
|
7176
|
+
placeholder: t("AccessGroupPlaceholder", "ACE group or permission, e.g. group.admin"),
|
|
7177
|
+
size: "xs",
|
|
7178
|
+
style: { flex: 1 }
|
|
7179
|
+
}
|
|
7180
|
+
),
|
|
7181
|
+
/* @__PURE__ */ jsx(
|
|
7182
|
+
ActionIcon,
|
|
7183
|
+
{
|
|
7184
|
+
variant: "subtle",
|
|
7185
|
+
color: "red",
|
|
7186
|
+
size: "md",
|
|
7187
|
+
onClick: () => removeGroup(i),
|
|
7188
|
+
title: t("Remove", "Remove"),
|
|
7189
|
+
"aria-label": t("Remove", "Remove"),
|
|
7190
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7191
|
+
}
|
|
7192
|
+
)
|
|
7193
|
+
] }, i)),
|
|
7194
|
+
addingGroup && /* @__PURE__ */ jsx(
|
|
7195
|
+
AceGroupAddRow,
|
|
7196
|
+
{
|
|
7197
|
+
placeholder: t("AccessGroupPlaceholder", "ACE group or permission, e.g. group.admin"),
|
|
7198
|
+
onCommit: commitGroup,
|
|
7199
|
+
onCancel: () => setAddingGroup(false),
|
|
7200
|
+
removeLabel: t("Remove", "Remove")
|
|
7201
|
+
}
|
|
7202
|
+
)
|
|
7203
|
+
] }),
|
|
7204
|
+
!addingGroup && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
7205
|
+
/* @__PURE__ */ jsx(SectionLabel, { icon: UserRound, label: t("AccessPlayers", "Players") }),
|
|
7206
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
|
|
7207
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
7208
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7209
|
+
/* @__PURE__ */ jsx(
|
|
7210
|
+
PlayerSelect,
|
|
7211
|
+
{
|
|
7212
|
+
value: id || null,
|
|
7213
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
7214
|
+
includeOffline,
|
|
7215
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7216
|
+
style: { flex: 1 },
|
|
7217
|
+
size: "xs"
|
|
7218
|
+
}
|
|
7219
|
+
),
|
|
7220
|
+
/* @__PURE__ */ jsx(
|
|
7221
|
+
ActionIcon,
|
|
7222
|
+
{
|
|
7223
|
+
variant: "subtle",
|
|
7224
|
+
color: "red",
|
|
7225
|
+
size: "md",
|
|
7226
|
+
onClick: () => removeIdentifier(i),
|
|
7227
|
+
title: t("Remove", "Remove"),
|
|
7228
|
+
"aria-label": t("Remove", "Remove"),
|
|
7229
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7230
|
+
}
|
|
7231
|
+
)
|
|
7232
|
+
] }, i)),
|
|
7233
|
+
addingPlayer && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7234
|
+
/* @__PURE__ */ jsx(
|
|
7235
|
+
PlayerSelect,
|
|
7236
|
+
{
|
|
7237
|
+
value: null,
|
|
7238
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
7239
|
+
includeOffline,
|
|
7240
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7241
|
+
style: { flex: 1 },
|
|
7242
|
+
size: "xs"
|
|
7243
|
+
}
|
|
7244
|
+
),
|
|
7245
|
+
/* @__PURE__ */ jsx(
|
|
7246
|
+
ActionIcon,
|
|
7247
|
+
{
|
|
7248
|
+
variant: "subtle",
|
|
7249
|
+
color: "red",
|
|
7250
|
+
size: "md",
|
|
7251
|
+
onClick: () => setAddingPlayer(false),
|
|
7252
|
+
title: t("Remove", "Remove"),
|
|
7253
|
+
"aria-label": t("Remove", "Remove"),
|
|
7254
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7255
|
+
}
|
|
7256
|
+
)
|
|
7257
|
+
] })
|
|
7258
|
+
] }),
|
|
7259
|
+
!addingPlayer && /* @__PURE__ */ jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
7260
|
+
]
|
|
7261
|
+
}
|
|
7262
|
+
);
|
|
7263
|
+
}
|
|
7264
|
+
function AddRowButton({ label: label2, onClick }) {
|
|
7265
|
+
return /* @__PURE__ */ jsxs(
|
|
7266
|
+
Flex,
|
|
7267
|
+
{
|
|
7268
|
+
align: "center",
|
|
7269
|
+
justify: "center",
|
|
7270
|
+
gap: "xs",
|
|
7271
|
+
onClick,
|
|
7272
|
+
role: "button",
|
|
7273
|
+
tabIndex: 0,
|
|
7274
|
+
onKeyDown: (e) => {
|
|
7275
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7276
|
+
e.preventDefault();
|
|
7277
|
+
onClick();
|
|
7278
|
+
}
|
|
7279
|
+
},
|
|
7280
|
+
py: "xs",
|
|
7281
|
+
style: {
|
|
7282
|
+
cursor: "pointer",
|
|
7283
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
7284
|
+
borderRadius: "0.4vh",
|
|
7285
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7286
|
+
},
|
|
7287
|
+
onMouseEnter: (e) => {
|
|
7288
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
7289
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
7290
|
+
},
|
|
7291
|
+
onMouseLeave: (e) => {
|
|
7292
|
+
e.currentTarget.style.background = "transparent";
|
|
7293
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
7294
|
+
},
|
|
7295
|
+
children: [
|
|
7296
|
+
/* @__PURE__ */ jsx(Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
7297
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label2 })
|
|
7298
|
+
]
|
|
7299
|
+
}
|
|
7300
|
+
);
|
|
7301
|
+
}
|
|
7302
|
+
function AceGroupAddRow({
|
|
7303
|
+
placeholder,
|
|
7304
|
+
onCommit,
|
|
7305
|
+
onCancel,
|
|
7306
|
+
removeLabel
|
|
7307
|
+
}) {
|
|
7308
|
+
const [draft, setDraft] = useState("");
|
|
7309
|
+
const commit = () => {
|
|
7310
|
+
if (draft.trim()) onCommit(draft);
|
|
7311
|
+
else onCancel();
|
|
7312
|
+
};
|
|
7313
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
|
|
7314
|
+
/* @__PURE__ */ jsx(
|
|
7315
|
+
TextInput,
|
|
7316
|
+
{
|
|
7317
|
+
value: draft,
|
|
7318
|
+
onChange: (e) => setDraft(e.currentTarget.value),
|
|
7319
|
+
onKeyDown: (e) => {
|
|
7320
|
+
if (e.key === "Enter") {
|
|
7321
|
+
e.preventDefault();
|
|
7322
|
+
commit();
|
|
7323
|
+
} else if (e.key === "Escape") {
|
|
7324
|
+
e.preventDefault();
|
|
7325
|
+
onCancel();
|
|
7326
|
+
}
|
|
7327
|
+
},
|
|
7328
|
+
onBlur: commit,
|
|
7329
|
+
placeholder,
|
|
7330
|
+
size: "xs",
|
|
7331
|
+
autoFocus: true,
|
|
7332
|
+
style: { flex: 1 }
|
|
7333
|
+
}
|
|
7334
|
+
),
|
|
7335
|
+
/* @__PURE__ */ jsx(
|
|
7336
|
+
ActionIcon,
|
|
7337
|
+
{
|
|
7338
|
+
variant: "subtle",
|
|
7339
|
+
color: "red",
|
|
7340
|
+
size: "md",
|
|
7341
|
+
onClick: onCancel,
|
|
7342
|
+
title: removeLabel,
|
|
7343
|
+
"aria-label": removeLabel,
|
|
7344
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: "1.4vh" })
|
|
7345
|
+
}
|
|
7346
|
+
)
|
|
7347
|
+
] });
|
|
7348
|
+
}
|
|
7349
|
+
|
|
7350
|
+
// src/utils/gtaAnimPostFx.ts
|
|
7351
|
+
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
7352
|
+
"Wake Up / Sleep",
|
|
7353
|
+
"Character Switch",
|
|
7354
|
+
"Cinematic Push-In",
|
|
7355
|
+
"Death / Fail",
|
|
7356
|
+
"Heist",
|
|
7357
|
+
"Minigame",
|
|
7358
|
+
"Drug / Trip",
|
|
7359
|
+
"Color Filter / Tint",
|
|
7360
|
+
"Multiplayer",
|
|
7361
|
+
"Misc"
|
|
7362
|
+
];
|
|
7363
|
+
var GTA_ANIM_POST_FX = [
|
|
7364
|
+
// ── Wake Up / Sleep (community-known; not in altV docs) ────────────────────
|
|
7365
|
+
{ name: "ULP_PlayerWakeUp", label: "Player Wake Up", group: "Wake Up / Sleep" },
|
|
7366
|
+
{ name: "MinigameEndNeutral", label: "Minigame End \u2014 Neutral", group: "Wake Up / Sleep" },
|
|
7367
|
+
{ name: "MinigameEndFranklin", label: "Minigame End \u2014 Franklin", group: "Wake Up / Sleep" },
|
|
7368
|
+
{ name: "MinigameEndMichael", label: "Minigame End \u2014 Michael", group: "Wake Up / Sleep" },
|
|
7369
|
+
{ name: "MinigameEndTrevor", label: "Minigame End \u2014 Trevor", group: "Wake Up / Sleep" },
|
|
7370
|
+
// ── Character Switch (Franklin / Michael / Trevor / Neutral variants) ─────
|
|
7371
|
+
{ name: "SwitchHUDIn", group: "Character Switch" },
|
|
7372
|
+
{ name: "SwitchHUDOut", group: "Character Switch" },
|
|
7373
|
+
{ name: "SwitchHUDFranklinIn", group: "Character Switch" },
|
|
7374
|
+
{ name: "SwitchHUDFranklinOut", group: "Character Switch" },
|
|
7375
|
+
{ name: "SwitchHUDMichaelIn", group: "Character Switch" },
|
|
7376
|
+
{ name: "SwitchHUDMichaelOut", group: "Character Switch" },
|
|
7377
|
+
{ name: "SwitchHUDTrevorIn", group: "Character Switch" },
|
|
7378
|
+
{ name: "SwitchHUDTrevorOut", group: "Character Switch" },
|
|
7379
|
+
{ name: "SwitchOpenFranklin", group: "Character Switch" },
|
|
7380
|
+
{ name: "SwitchOpenFranklinIn", group: "Character Switch" },
|
|
7381
|
+
{ name: "SwitchOpenFranklinOut", group: "Character Switch" },
|
|
7382
|
+
{ name: "SwitchOpenMichaelIn", group: "Character Switch" },
|
|
7383
|
+
{ name: "SwitchOpenMichaelMid", group: "Character Switch" },
|
|
7384
|
+
{ name: "SwitchOpenMichaelOut", group: "Character Switch" },
|
|
7385
|
+
{ name: "SwitchOpenTrevorIn", group: "Character Switch" },
|
|
7386
|
+
{ name: "SwitchOpenTrevorOut", group: "Character Switch" },
|
|
7387
|
+
{ name: "SwitchOpenNeutralFIB5", group: "Character Switch" },
|
|
7388
|
+
{ name: "SwitchOpenNeutralOutHeist", group: "Character Switch" },
|
|
7389
|
+
{ name: "SwitchSceneFranklin", group: "Character Switch" },
|
|
7390
|
+
{ name: "SwitchSceneMichael", group: "Character Switch" },
|
|
7391
|
+
{ name: "SwitchSceneNeutral", group: "Character Switch" },
|
|
7392
|
+
{ name: "SwitchSceneTrevor", group: "Character Switch" },
|
|
7393
|
+
{ name: "SwitchShortFranklinIn", group: "Character Switch" },
|
|
7394
|
+
{ name: "SwitchShortFranklinMid", group: "Character Switch" },
|
|
7395
|
+
{ name: "SwitchShortMichaelIn", group: "Character Switch" },
|
|
7396
|
+
{ name: "SwitchShortMichaelMid", group: "Character Switch" },
|
|
7397
|
+
{ name: "SwitchShortNeutralIn", group: "Character Switch" },
|
|
7398
|
+
{ name: "SwitchShortNeutralMid", group: "Character Switch" },
|
|
7399
|
+
{ name: "SwitchShortTrevorIn", group: "Character Switch" },
|
|
7400
|
+
{ name: "SwitchShortTrevorMid", group: "Character Switch" },
|
|
7401
|
+
{ name: "switch_cam_1", group: "Character Switch" },
|
|
7402
|
+
{ name: "switch_cam_2", group: "Character Switch" },
|
|
7403
|
+
// ── Cinematic Push-In (slow zoom intro to a character) ────────────────────
|
|
7404
|
+
{ name: "CamPushInFranklin", group: "Cinematic Push-In" },
|
|
7405
|
+
{ name: "CamPushInMichael", group: "Cinematic Push-In" },
|
|
7406
|
+
{ name: "CamPushInTrevor", group: "Cinematic Push-In" },
|
|
7407
|
+
{ name: "CamPushInNeutral", group: "Cinematic Push-In" },
|
|
7408
|
+
{ name: "BeastIntroScene", label: "Beast Intro", group: "Cinematic Push-In" },
|
|
7409
|
+
{ name: "BeastLaunch", group: "Cinematic Push-In" },
|
|
7410
|
+
{ name: "BeastTransition", group: "Cinematic Push-In" },
|
|
7411
|
+
// ── Death / Fail (red tint, slow-mo blur) ─────────────────────────────────
|
|
7412
|
+
{ name: "DeathFailNeutralIn", group: "Death / Fail" },
|
|
7413
|
+
{ name: "DeathFailFranklinIn", group: "Death / Fail" },
|
|
7414
|
+
{ name: "DeathFailMichaelIn", group: "Death / Fail" },
|
|
7415
|
+
{ name: "DeathFailTrevorIn", group: "Death / Fail" },
|
|
7416
|
+
{ name: "DeathFailMPIn", label: "Death Fail \u2014 MP", group: "Death / Fail" },
|
|
7417
|
+
{ name: "DeathFailMPDark", label: "Death Fail \u2014 MP Dark", group: "Death / Fail" },
|
|
7418
|
+
{ name: "DeathFailOut", group: "Death / Fail" },
|
|
7419
|
+
{ name: "Rampage", group: "Death / Fail" },
|
|
7420
|
+
{ name: "RampageOut", group: "Death / Fail" },
|
|
7421
|
+
// ── Heist (celebration / locate / pass) ───────────────────────────────────
|
|
7422
|
+
{ name: "HeistCelebEnd", group: "Heist" },
|
|
7423
|
+
{ name: "HeistCelebPass", group: "Heist" },
|
|
7424
|
+
{ name: "HeistCelebPassBW", label: "Heist Celeb Pass (B/W)", group: "Heist" },
|
|
7425
|
+
{ name: "HeistCelebToast", group: "Heist" },
|
|
7426
|
+
{ name: "HeistLocate", group: "Heist" },
|
|
7427
|
+
{ name: "HeistTripSkipFade", group: "Heist" },
|
|
7428
|
+
// ── Minigame / Menu ───────────────────────────────────────────────────────
|
|
7429
|
+
{ name: "MenuMGIn", group: "Minigame" },
|
|
7430
|
+
{ name: "MenuMGHeistIn", group: "Minigame" },
|
|
7431
|
+
{ name: "MenuMGHeistIntro", group: "Minigame" },
|
|
7432
|
+
{ name: "MenuMGHeistOut", group: "Minigame" },
|
|
7433
|
+
{ name: "MenuMGHeistTint", group: "Minigame" },
|
|
7434
|
+
{ name: "MenuMGSelectionIn", group: "Minigame" },
|
|
7435
|
+
{ name: "MenuMGSelectionTint", group: "Minigame" },
|
|
7436
|
+
{ name: "MenuMGTournamentIn", group: "Minigame" },
|
|
7437
|
+
{ name: "MenuMGTournamentTint", group: "Minigame" },
|
|
7438
|
+
{ name: "MinigameTransitionIn", group: "Minigame" },
|
|
7439
|
+
{ name: "MinigameTransitionOut", group: "Minigame" },
|
|
7440
|
+
// ── Drug / Trip (psychedelic, blur, distortion) ───────────────────────────
|
|
7441
|
+
{ name: "DMT_flight", group: "Drug / Trip" },
|
|
7442
|
+
{ name: "DMT_flight_intro", group: "Drug / Trip" },
|
|
7443
|
+
{ name: "PeyoteIn", group: "Drug / Trip" },
|
|
7444
|
+
{ name: "PeyoteOut", group: "Drug / Trip" },
|
|
7445
|
+
{ name: "PeyoteEndIn", group: "Drug / Trip" },
|
|
7446
|
+
{ name: "PeyoteEndOut", group: "Drug / Trip" },
|
|
7447
|
+
{ name: "DrugsDrivingIn", group: "Drug / Trip" },
|
|
7448
|
+
{ name: "DrugsDrivingOut", group: "Drug / Trip" },
|
|
7449
|
+
{ name: "DrugsMichaelAliensFight", group: "Drug / Trip" },
|
|
7450
|
+
{ name: "DrugsMichaelAliensFightIn", group: "Drug / Trip" },
|
|
7451
|
+
{ name: "DrugsMichaelAliensFightOut", group: "Drug / Trip" },
|
|
7452
|
+
{ name: "DrugsTrevorClownsFight", group: "Drug / Trip" },
|
|
7453
|
+
{ name: "DrugsTrevorClownsFightIn", group: "Drug / Trip" },
|
|
7454
|
+
{ name: "DrugsTrevorClownsFightOut", group: "Drug / Trip" },
|
|
7455
|
+
{ name: "ChopVision", label: "Chop Vision (dog)", group: "Drug / Trip" },
|
|
7456
|
+
// ── Color Filter / Tint (one-off and biker formation filters) ─────────────
|
|
7457
|
+
{ name: "PPFilter", group: "Color Filter / Tint" },
|
|
7458
|
+
{ name: "PPFilterOut", group: "Color Filter / Tint" },
|
|
7459
|
+
{ name: "PPGreen", group: "Color Filter / Tint" },
|
|
7460
|
+
{ name: "PPGreenOut", group: "Color Filter / Tint" },
|
|
7461
|
+
{ name: "PPOrange", group: "Color Filter / Tint" },
|
|
7462
|
+
{ name: "PPOrangeOut", group: "Color Filter / Tint" },
|
|
7463
|
+
{ name: "PPPink", group: "Color Filter / Tint" },
|
|
7464
|
+
{ name: "PPPinkOut", group: "Color Filter / Tint" },
|
|
7465
|
+
{ name: "PPPurple", group: "Color Filter / Tint" },
|
|
7466
|
+
{ name: "PPPurpleOut", group: "Color Filter / Tint" },
|
|
7467
|
+
{ name: "BikerFilter", group: "Color Filter / Tint" },
|
|
7468
|
+
{ name: "BikerFilterOut", group: "Color Filter / Tint" },
|
|
7469
|
+
{ name: "BikerFormation", group: "Color Filter / Tint" },
|
|
7470
|
+
{ name: "BikerFormationOut", group: "Color Filter / Tint" },
|
|
7471
|
+
{ name: "InchOrange", group: "Color Filter / Tint" },
|
|
7472
|
+
{ name: "InchOrangeOut", group: "Color Filter / Tint" },
|
|
7473
|
+
{ name: "InchPurple", group: "Color Filter / Tint" },
|
|
7474
|
+
{ name: "InchPurpleOut", group: "Color Filter / Tint" },
|
|
7475
|
+
{ name: "InchPickup", group: "Color Filter / Tint" },
|
|
7476
|
+
{ name: "InchPickupOut", group: "Color Filter / Tint" },
|
|
7477
|
+
{ name: "TinyRacerGreen", group: "Color Filter / Tint" },
|
|
7478
|
+
{ name: "TinyRacerGreenOut", group: "Color Filter / Tint" },
|
|
7479
|
+
{ name: "TinyRacerPink", group: "Color Filter / Tint" },
|
|
7480
|
+
{ name: "TinyRacerPinkOut", group: "Color Filter / Tint" },
|
|
7481
|
+
{ name: "TinyRacerIntroCam", group: "Color Filter / Tint" },
|
|
7482
|
+
{ name: "DeadlineNeon", group: "Color Filter / Tint" },
|
|
7483
|
+
// ── Multiplayer (celeb, killstreak, race, etc.) ───────────────────────────
|
|
7484
|
+
{ name: "MP_Celeb_Win", group: "Multiplayer" },
|
|
7485
|
+
{ name: "MP_Celeb_Win_Out", group: "Multiplayer" },
|
|
7486
|
+
{ name: "MP_Celeb_Lose", group: "Multiplayer" },
|
|
7487
|
+
{ name: "MP_Celeb_Lose_Out", group: "Multiplayer" },
|
|
7488
|
+
{ name: "MP_Celeb_Preload", group: "Multiplayer" },
|
|
7489
|
+
{ name: "MP_Celeb_Preload_Fade", group: "Multiplayer" },
|
|
7490
|
+
{ name: "MP_Bull_tost", group: "Multiplayer" },
|
|
7491
|
+
{ name: "MP_Bull_tost_Out", group: "Multiplayer" },
|
|
7492
|
+
{ name: "MP_Killstreak", group: "Multiplayer" },
|
|
7493
|
+
{ name: "MP_Killstreak_Out", group: "Multiplayer" },
|
|
7494
|
+
{ name: "MP_Loser_Streak_Out", group: "Multiplayer" },
|
|
7495
|
+
{ name: "MP_OrbitalCannon", group: "Multiplayer" },
|
|
7496
|
+
{ name: "MP_Powerplay", group: "Multiplayer" },
|
|
7497
|
+
{ name: "MP_Powerplay_Out", group: "Multiplayer" },
|
|
7498
|
+
{ name: "MP_SmugglerCheckpoint", group: "Multiplayer" },
|
|
7499
|
+
{ name: "MP_TransformRaceFlash", group: "Multiplayer" },
|
|
7500
|
+
{ name: "MP_WarpCheckpoint", group: "Multiplayer" },
|
|
7501
|
+
{ name: "MP_corona_switch", group: "Multiplayer" },
|
|
7502
|
+
{ name: "MP_intro_logo", group: "Multiplayer" },
|
|
7503
|
+
{ name: "MP_job_load", group: "Multiplayer" },
|
|
7504
|
+
{ name: "MP_race_crash", group: "Multiplayer" },
|
|
7505
|
+
// ── Misc (success notifs, special weapons, sniper / pause / explosions) ───
|
|
7506
|
+
{ name: "SuccessFranklin", group: "Misc" },
|
|
7507
|
+
{ name: "SuccessMichael", group: "Misc" },
|
|
7508
|
+
{ name: "SuccessNeutral", group: "Misc" },
|
|
7509
|
+
{ name: "SuccessTrevor", group: "Misc" },
|
|
7510
|
+
{ name: "FocusIn", group: "Misc" },
|
|
7511
|
+
{ name: "FocusOut", group: "Misc" },
|
|
7512
|
+
{ name: "CrossLine", group: "Misc" },
|
|
7513
|
+
{ name: "CrossLineOut", group: "Misc" },
|
|
7514
|
+
{ name: "SniperOverlay", group: "Misc" },
|
|
7515
|
+
{ name: "ExplosionJosh3", group: "Misc" },
|
|
7516
|
+
{ name: "WeaponUpgrade", group: "Misc" },
|
|
7517
|
+
{ name: "Dont_tazeme_bro", label: "Don't Taze Me Bro", group: "Misc" },
|
|
7518
|
+
{ name: "LostTimeDay", group: "Misc" },
|
|
7519
|
+
{ name: "LostTimeNight", group: "Misc" },
|
|
7520
|
+
{ name: "PauseMenuOut", group: "Misc" },
|
|
7521
|
+
{ name: "pennedIn", group: "Misc" },
|
|
7522
|
+
{ name: "PennedInOut", group: "Misc" },
|
|
7523
|
+
{ name: "RaceTurbo", group: "Misc" },
|
|
7524
|
+
{ name: "DefaultFlash", group: "Misc" }
|
|
7525
|
+
];
|
|
7526
|
+
function formatGtaAnimPostFx(name) {
|
|
7527
|
+
const entry = GTA_ANIM_POST_FX.find((fx) => fx.name === name);
|
|
7528
|
+
return entry?.label ?? name;
|
|
7529
|
+
}
|
|
7530
|
+
function buildGroupedData2(extraNames = []) {
|
|
7531
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7532
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7533
|
+
for (const fx of GTA_ANIM_POST_FX) {
|
|
7534
|
+
if (seen.has(fx.name)) continue;
|
|
7535
|
+
seen.add(fx.name);
|
|
7536
|
+
if (!groups.has(fx.group)) groups.set(fx.group, []);
|
|
7537
|
+
groups.get(fx.group).push(fx);
|
|
7538
|
+
}
|
|
7539
|
+
const data = GTA_ANIM_POST_FX_GROUP_ORDER.flatMap((g) => {
|
|
7540
|
+
const items = groups.get(g);
|
|
7541
|
+
if (!items || items.length === 0) return [];
|
|
7542
|
+
return [
|
|
7543
|
+
{
|
|
7544
|
+
group: g,
|
|
7545
|
+
items: items.map((fx) => ({
|
|
7546
|
+
value: fx.name,
|
|
7547
|
+
label: formatGtaAnimPostFx(fx.name)
|
|
7548
|
+
}))
|
|
7549
|
+
}
|
|
7550
|
+
];
|
|
7551
|
+
});
|
|
7552
|
+
const knownNames = new Set(GTA_ANIM_POST_FX.map((fx) => fx.name));
|
|
7553
|
+
const customs = extraNames.filter((n) => n && !knownNames.has(n));
|
|
7554
|
+
if (customs.length > 0) {
|
|
7055
7555
|
data.push({
|
|
7056
7556
|
group: "Custom",
|
|
7057
7557
|
items: customs.map((n) => ({ value: n, label: n }))
|
|
@@ -7435,7 +7935,7 @@ function ScenarioSelect({
|
|
|
7435
7935
|
}
|
|
7436
7936
|
);
|
|
7437
7937
|
}
|
|
7438
|
-
var
|
|
7938
|
+
var t2 = (key, fallback) => {
|
|
7439
7939
|
const v = locale(key);
|
|
7440
7940
|
return v === key ? fallback : v;
|
|
7441
7941
|
};
|
|
@@ -7503,7 +8003,7 @@ function DiscordRoleSelect(props) {
|
|
|
7503
8003
|
return map;
|
|
7504
8004
|
}, [roles]);
|
|
7505
8005
|
if (errorCode === "NotConfigured") {
|
|
7506
|
-
const notConfiguredPlaceholder =
|
|
8006
|
+
const notConfiguredPlaceholder = t2(
|
|
7507
8007
|
"DiscordNotConfigured",
|
|
7508
8008
|
"Not configured \u2014 set in /dirk_lib"
|
|
7509
8009
|
);
|
|
@@ -7571,9 +8071,9 @@ function DiscordRoleSelect(props) {
|
|
|
7571
8071
|
e.stopPropagation();
|
|
7572
8072
|
refresh();
|
|
7573
8073
|
},
|
|
7574
|
-
title:
|
|
8074
|
+
title: t2("Refresh", "Refresh"),
|
|
7575
8075
|
loading,
|
|
7576
|
-
"aria-label":
|
|
8076
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
7577
8077
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
7578
8078
|
}
|
|
7579
8079
|
);
|
|
@@ -7583,7 +8083,7 @@ function DiscordRoleSelect(props) {
|
|
|
7583
8083
|
{
|
|
7584
8084
|
label: label2,
|
|
7585
8085
|
size,
|
|
7586
|
-
placeholder: placeholder ||
|
|
8086
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
7587
8087
|
data,
|
|
7588
8088
|
value: props.value || [],
|
|
7589
8089
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -7595,7 +8095,7 @@ function DiscordRoleSelect(props) {
|
|
|
7595
8095
|
rightSectionPointerEvents: "all",
|
|
7596
8096
|
style,
|
|
7597
8097
|
styles,
|
|
7598
|
-
nothingFoundMessage: errorCode ? `${
|
|
8098
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7599
8099
|
}
|
|
7600
8100
|
);
|
|
7601
8101
|
}
|
|
@@ -7604,7 +8104,7 @@ function DiscordRoleSelect(props) {
|
|
|
7604
8104
|
{
|
|
7605
8105
|
label: label2,
|
|
7606
8106
|
size,
|
|
7607
|
-
placeholder: placeholder ||
|
|
8107
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
7608
8108
|
data,
|
|
7609
8109
|
value: props.value || null,
|
|
7610
8110
|
onChange: (id) => props.onChange(id),
|
|
@@ -7616,11 +8116,11 @@ function DiscordRoleSelect(props) {
|
|
|
7616
8116
|
rightSectionPointerEvents: "all",
|
|
7617
8117
|
style,
|
|
7618
8118
|
styles,
|
|
7619
|
-
nothingFoundMessage: errorCode ? `${
|
|
8119
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7620
8120
|
}
|
|
7621
8121
|
);
|
|
7622
8122
|
}
|
|
7623
|
-
var
|
|
8123
|
+
var t3 = (key, fallback) => {
|
|
7624
8124
|
const v = locale(key);
|
|
7625
8125
|
return v === key ? fallback : v;
|
|
7626
8126
|
};
|
|
@@ -7641,7 +8141,7 @@ function FrameworkHint({ framework }) {
|
|
|
7641
8141
|
const theme2 = useMantineTheme();
|
|
7642
8142
|
if (!framework) return null;
|
|
7643
8143
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
7644
|
-
const text =
|
|
8144
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
7645
8145
|
return /* @__PURE__ */ jsxs(
|
|
7646
8146
|
Flex,
|
|
7647
8147
|
{
|
|
@@ -7725,9 +8225,9 @@ function AccountSelect(props) {
|
|
|
7725
8225
|
e.stopPropagation();
|
|
7726
8226
|
refresh();
|
|
7727
8227
|
},
|
|
7728
|
-
title:
|
|
8228
|
+
title: t3("Refresh", "Refresh"),
|
|
7729
8229
|
loading,
|
|
7730
|
-
"aria-label":
|
|
8230
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
7731
8231
|
children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.2vh" })
|
|
7732
8232
|
}
|
|
7733
8233
|
);
|
|
@@ -7741,14 +8241,14 @@ function AccountSelect(props) {
|
|
|
7741
8241
|
rightSection: refreshButton,
|
|
7742
8242
|
rightSectionPointerEvents: "all",
|
|
7743
8243
|
style,
|
|
7744
|
-
nothingFoundMessage:
|
|
8244
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
7745
8245
|
};
|
|
7746
8246
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
7747
8247
|
props.multi ? /* @__PURE__ */ jsx(
|
|
7748
8248
|
MultiSelect,
|
|
7749
8249
|
{
|
|
7750
8250
|
...sharedSelectProps,
|
|
7751
|
-
placeholder: placeholder ||
|
|
8251
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
7752
8252
|
value: props.value || [],
|
|
7753
8253
|
onChange: (names) => props.onChange(names),
|
|
7754
8254
|
renderOption,
|
|
@@ -7760,7 +8260,7 @@ function AccountSelect(props) {
|
|
|
7760
8260
|
Select,
|
|
7761
8261
|
{
|
|
7762
8262
|
...sharedSelectProps,
|
|
7763
|
-
placeholder: placeholder ||
|
|
8263
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
7764
8264
|
value: props.value || null,
|
|
7765
8265
|
onChange: (name) => props.onChange(name),
|
|
7766
8266
|
renderOption,
|
|
@@ -8052,175 +8552,6 @@ function WorldPositionGotoButton2({
|
|
|
8052
8552
|
}
|
|
8053
8553
|
) });
|
|
8054
8554
|
}
|
|
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
8555
|
function usePickDoor() {
|
|
8225
8556
|
const begin = useAdminToolStore((s) => s.begin);
|
|
8226
8557
|
return async () => {
|
|
@@ -8612,6 +8943,6 @@ var Vector4Schema = z.object({
|
|
|
8612
8943
|
w: z.number()
|
|
8613
8944
|
});
|
|
8614
8945
|
|
|
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 };
|
|
8946
|
+
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
8947
|
//# sourceMappingURL=index.js.map
|
|
8617
8948
|
//# sourceMappingURL=index.js.map
|