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.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var core = require('@mantine/core');
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var React4 = require('react');
|
|
6
6
|
var zustand = require('zustand');
|
|
7
|
+
var zod = require('zod');
|
|
7
8
|
var axios = require('axios');
|
|
8
9
|
var reactFontawesome = require('@fortawesome/react-fontawesome');
|
|
9
10
|
var framerMotion = require('framer-motion');
|
|
@@ -28,7 +29,6 @@ var leaflet = require('leaflet');
|
|
|
28
29
|
require('leaflet/dist/leaflet.css');
|
|
29
30
|
var reactLeaflet = require('react-leaflet');
|
|
30
31
|
var reactLeafletComponentMarker = require('@adamscybot/react-leaflet-component-marker');
|
|
31
|
-
var zod = require('zod');
|
|
32
32
|
|
|
33
33
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
34
34
|
|
|
@@ -1270,11 +1270,11 @@ var colorNames = {
|
|
|
1270
1270
|
Yellow: { r: 255, g: 255, b: 0 },
|
|
1271
1271
|
YellowGreen: { r: 154, g: 205, b: 50 }
|
|
1272
1272
|
};
|
|
1273
|
-
function colorWithAlpha(color,
|
|
1273
|
+
function colorWithAlpha(color, alpha19) {
|
|
1274
1274
|
const lowerCasedColor = color.toLowerCase();
|
|
1275
1275
|
if (colorNames[lowerCasedColor]) {
|
|
1276
1276
|
const rgb = colorNames[lowerCasedColor];
|
|
1277
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${
|
|
1277
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha19})`;
|
|
1278
1278
|
}
|
|
1279
1279
|
if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
|
|
1280
1280
|
const hex = color.slice(1);
|
|
@@ -1282,12 +1282,12 @@ function colorWithAlpha(color, alpha18) {
|
|
|
1282
1282
|
const r = bigint >> 16 & 255;
|
|
1283
1283
|
const g = bigint >> 8 & 255;
|
|
1284
1284
|
const b = bigint & 255;
|
|
1285
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
1285
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha19})`;
|
|
1286
1286
|
}
|
|
1287
1287
|
if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
|
|
1288
1288
|
const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
|
|
1289
1289
|
if (result) {
|
|
1290
|
-
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${
|
|
1290
|
+
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha19})`;
|
|
1291
1291
|
}
|
|
1292
1292
|
}
|
|
1293
1293
|
return color;
|
|
@@ -1321,6 +1321,32 @@ var openLink = (url) => {
|
|
|
1321
1321
|
window.invokeNative("openLink", url);
|
|
1322
1322
|
}
|
|
1323
1323
|
};
|
|
1324
|
+
var DEFAULT_PALETTE = [
|
|
1325
|
+
"#f0f4ff",
|
|
1326
|
+
"#d9e3ff",
|
|
1327
|
+
"#bfcfff",
|
|
1328
|
+
"#a6bbff",
|
|
1329
|
+
"#8ca7ff",
|
|
1330
|
+
"#7393ff",
|
|
1331
|
+
"#5a7fff",
|
|
1332
|
+
"#406bff",
|
|
1333
|
+
"#2547ff",
|
|
1334
|
+
"#0b33ff"
|
|
1335
|
+
];
|
|
1336
|
+
var ThemeOverrideSchema = zod.z.object({
|
|
1337
|
+
useOverride: zod.z.boolean(),
|
|
1338
|
+
primaryColor: zod.z.string(),
|
|
1339
|
+
primaryShade: zod.z.number(),
|
|
1340
|
+
customTheme: zod.z.array(zod.z.string())
|
|
1341
|
+
});
|
|
1342
|
+
var defaultThemeOverride = {
|
|
1343
|
+
useOverride: false,
|
|
1344
|
+
primaryColor: "dirk",
|
|
1345
|
+
primaryShade: 5,
|
|
1346
|
+
customTheme: DEFAULT_PALETTE
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
// src/utils/useSettings.ts
|
|
1324
1350
|
var useSettings = zustand.create(() => ({
|
|
1325
1351
|
currency: "$",
|
|
1326
1352
|
game: "fivem",
|
|
@@ -1328,18 +1354,7 @@ var useSettings = zustand.create(() => ({
|
|
|
1328
1354
|
primaryShade: 9,
|
|
1329
1355
|
itemImgPath: "",
|
|
1330
1356
|
resourceVersion: "dev",
|
|
1331
|
-
customTheme:
|
|
1332
|
-
"#f0f4ff",
|
|
1333
|
-
"#d9e3ff",
|
|
1334
|
-
"#bfcfff",
|
|
1335
|
-
"#a6bbff",
|
|
1336
|
-
"#8ca7ff",
|
|
1337
|
-
"#7393ff",
|
|
1338
|
-
"#5a7fff",
|
|
1339
|
-
"#406bff",
|
|
1340
|
-
"#2547ff",
|
|
1341
|
-
"#0b33ff"
|
|
1342
|
-
]
|
|
1357
|
+
customTheme: DEFAULT_PALETTE
|
|
1343
1358
|
}));
|
|
1344
1359
|
|
|
1345
1360
|
// src/utils/fetchNui.ts
|
|
@@ -3751,11 +3766,11 @@ function ConfirmModal({
|
|
|
3751
3766
|
placeholder: confirmText,
|
|
3752
3767
|
value: typed,
|
|
3753
3768
|
onChange: (e) => setTyped(e.currentTarget.value),
|
|
3754
|
-
styles: (
|
|
3769
|
+
styles: (t4) => ({
|
|
3755
3770
|
input: {
|
|
3756
|
-
backgroundColor: core.alpha(
|
|
3771
|
+
backgroundColor: core.alpha(t4.colors.dark[7], 0.5),
|
|
3757
3772
|
border: `0.1vh solid ${core.alpha(
|
|
3758
|
-
typed === confirmText ? "#ef4444" :
|
|
3773
|
+
typed === confirmText ? "#ef4444" : t4.colors.dark[5],
|
|
3759
3774
|
0.5
|
|
3760
3775
|
)}`,
|
|
3761
3776
|
color: "rgba(255,255,255,0.85)",
|
|
@@ -4433,7 +4448,7 @@ function useAdminState(key, initial) {
|
|
|
4433
4448
|
React4.useEffect(() => {
|
|
4434
4449
|
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
4435
4450
|
listeners.set(key, set);
|
|
4436
|
-
const handler = () => setTick((
|
|
4451
|
+
const handler = () => setTick((t4) => t4 + 1);
|
|
4437
4452
|
set.add(handler);
|
|
4438
4453
|
return () => {
|
|
4439
4454
|
set.delete(handler);
|
|
@@ -4672,6 +4687,16 @@ function mergeMantineThemeSafe(base, custom, override) {
|
|
|
4672
4687
|
}
|
|
4673
4688
|
};
|
|
4674
4689
|
}
|
|
4690
|
+
function changedTopLevelSections(changedFields) {
|
|
4691
|
+
if (!changedFields || changedFields.length === 0) return [];
|
|
4692
|
+
const sections = /* @__PURE__ */ new Set();
|
|
4693
|
+
for (const path of changedFields) {
|
|
4694
|
+
if (typeof path !== "string" || path.length === 0) continue;
|
|
4695
|
+
const dot = path.indexOf(".");
|
|
4696
|
+
sections.add(dot === -1 ? path : path.slice(0, dot));
|
|
4697
|
+
}
|
|
4698
|
+
return Array.from(sections);
|
|
4699
|
+
}
|
|
4675
4700
|
var _instance = null;
|
|
4676
4701
|
function getScriptConfigInstance() {
|
|
4677
4702
|
if (!_instance) throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
|
|
@@ -4681,15 +4706,18 @@ function createScriptConfig(defaultValue) {
|
|
|
4681
4706
|
const store2 = zustand.create(() => defaultValue);
|
|
4682
4707
|
let clientVersion = 0;
|
|
4683
4708
|
const useScriptConfigHooks = () => {
|
|
4684
|
-
useNuiEvent(
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4709
|
+
useNuiEvent(
|
|
4710
|
+
"UPDATE_SCRIPT_CONFIG",
|
|
4711
|
+
(data) => {
|
|
4712
|
+
if (!data) return;
|
|
4713
|
+
if (typeof data.clientVersion === "number") {
|
|
4714
|
+
clientVersion = data.clientVersion;
|
|
4715
|
+
}
|
|
4716
|
+
if (data.config && typeof data.config === "object") {
|
|
4717
|
+
store2.setState((prev) => ({ ...prev, ...data.config }));
|
|
4718
|
+
}
|
|
4691
4719
|
}
|
|
4692
|
-
|
|
4720
|
+
);
|
|
4693
4721
|
};
|
|
4694
4722
|
const fetchScriptConfig = async () => {
|
|
4695
4723
|
try {
|
|
@@ -4705,12 +4733,19 @@ function createScriptConfig(defaultValue) {
|
|
|
4705
4733
|
}
|
|
4706
4734
|
return null;
|
|
4707
4735
|
};
|
|
4708
|
-
const updateScriptConfig = async (newConfig) => {
|
|
4736
|
+
const updateScriptConfig = async (newConfig, changedFields) => {
|
|
4709
4737
|
store2.setState((prev) => ({ ...prev, ...newConfig }));
|
|
4710
|
-
const
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4738
|
+
const sections = changedTopLevelSections(changedFields);
|
|
4739
|
+
let payload;
|
|
4740
|
+
if (sections.length > 0) {
|
|
4741
|
+
const current = store2.getState();
|
|
4742
|
+
const delta = {};
|
|
4743
|
+
for (const key of sections) delta[key] = current[key];
|
|
4744
|
+
payload = { data: delta, expectedVersion: clientVersion, sectionReplace: true };
|
|
4745
|
+
} else {
|
|
4746
|
+
payload = { data: newConfig, expectedVersion: clientVersion };
|
|
4747
|
+
}
|
|
4748
|
+
const response = await fetchNui("UPDATE_SCRIPT_CONFIG", payload);
|
|
4714
4749
|
if (response?.meta?.client_version != null) {
|
|
4715
4750
|
clientVersion = response.meta.client_version;
|
|
4716
4751
|
}
|
|
@@ -5579,7 +5614,7 @@ function ConfigPanel(props) {
|
|
|
5579
5614
|
if (isSaving) return;
|
|
5580
5615
|
setIsSaving(true);
|
|
5581
5616
|
try {
|
|
5582
|
-
const result = await updateConfig(form.values);
|
|
5617
|
+
const result = await updateConfig(form.values, form.changedFields);
|
|
5583
5618
|
if (result?.success) {
|
|
5584
5619
|
form.reinitialize(cloneConfig(form.values));
|
|
5585
5620
|
dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
|
|
@@ -6613,24 +6648,6 @@ var MANTINE_COLOR_OPTIONS = [
|
|
|
6613
6648
|
"yellow",
|
|
6614
6649
|
"orange"
|
|
6615
6650
|
].map((value) => ({ value, label: value }));
|
|
6616
|
-
var DEFAULT_PALETTE = [
|
|
6617
|
-
"#f0f4ff",
|
|
6618
|
-
"#d9e3ff",
|
|
6619
|
-
"#bfcfff",
|
|
6620
|
-
"#a6bbff",
|
|
6621
|
-
"#8ca7ff",
|
|
6622
|
-
"#7393ff",
|
|
6623
|
-
"#5a7fff",
|
|
6624
|
-
"#406bff",
|
|
6625
|
-
"#2547ff",
|
|
6626
|
-
"#0b33ff"
|
|
6627
|
-
];
|
|
6628
|
-
var DEFAULT_VALUE = {
|
|
6629
|
-
useOverride: false,
|
|
6630
|
-
primaryColor: "dirk",
|
|
6631
|
-
primaryShade: 5,
|
|
6632
|
-
customTheme: DEFAULT_PALETTE
|
|
6633
|
-
};
|
|
6634
6651
|
function GroupLabel({ label: label2 }) {
|
|
6635
6652
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xxs", children: [
|
|
6636
6653
|
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
@@ -6645,10 +6662,10 @@ function ThemeOverrideSection({
|
|
|
6645
6662
|
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
6646
6663
|
const raw = useFormField(schemaKey);
|
|
6647
6664
|
const value = {
|
|
6648
|
-
useOverride: raw?.useOverride ??
|
|
6649
|
-
primaryColor: raw?.primaryColor ??
|
|
6650
|
-
primaryShade: raw?.primaryShade ??
|
|
6651
|
-
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme :
|
|
6665
|
+
useOverride: raw?.useOverride ?? defaultThemeOverride.useOverride,
|
|
6666
|
+
primaryColor: raw?.primaryColor ?? defaultThemeOverride.primaryColor,
|
|
6667
|
+
primaryShade: raw?.primaryShade ?? defaultThemeOverride.primaryShade,
|
|
6668
|
+
customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : defaultThemeOverride.customTheme
|
|
6652
6669
|
};
|
|
6653
6670
|
const { setValue } = useFormActions();
|
|
6654
6671
|
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
@@ -6855,212 +6872,695 @@ function SwatchTile({
|
|
|
6855
6872
|
) })
|
|
6856
6873
|
] });
|
|
6857
6874
|
}
|
|
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
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
]
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
return
|
|
7038
|
-
}
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
});
|
|
7061
|
-
const
|
|
7062
|
-
const
|
|
7063
|
-
|
|
6875
|
+
function usePlayers(opts = {}) {
|
|
6876
|
+
const {
|
|
6877
|
+
includeOffline = false,
|
|
6878
|
+
search = "",
|
|
6879
|
+
limit = 50,
|
|
6880
|
+
staleTimeMs,
|
|
6881
|
+
refetchIntervalMs
|
|
6882
|
+
} = opts;
|
|
6883
|
+
const query = reactQuery.useQuery({
|
|
6884
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6885
|
+
queryFn: async () => {
|
|
6886
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6887
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6888
|
+
const result = await fetchNui(
|
|
6889
|
+
"ADMIN_TOOL_QUERY",
|
|
6890
|
+
payload,
|
|
6891
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6892
|
+
// dev shell isn't blank.
|
|
6893
|
+
includeOffline ? [
|
|
6894
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6895
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6896
|
+
] : [
|
|
6897
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6898
|
+
]
|
|
6899
|
+
);
|
|
6900
|
+
return Array.isArray(result) ? result : [];
|
|
6901
|
+
},
|
|
6902
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6903
|
+
gcTime: 5 * 6e4,
|
|
6904
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6905
|
+
refetchOnWindowFocus: false,
|
|
6906
|
+
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
6907
|
+
});
|
|
6908
|
+
return {
|
|
6909
|
+
players: query.data ?? [],
|
|
6910
|
+
isLoading: query.isLoading,
|
|
6911
|
+
isFetching: query.isFetching,
|
|
6912
|
+
error: query.error ?? null,
|
|
6913
|
+
refresh: () => query.refetch()
|
|
6914
|
+
};
|
|
6915
|
+
}
|
|
6916
|
+
var DEBOUNCE_MS = 300;
|
|
6917
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6918
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6919
|
+
function PlayerSelect({
|
|
6920
|
+
value,
|
|
6921
|
+
onChange,
|
|
6922
|
+
includeOffline = false,
|
|
6923
|
+
limit = 50,
|
|
6924
|
+
searchable: searchableProp,
|
|
6925
|
+
placeholder,
|
|
6926
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
6927
|
+
loadingLabel = "Loading\u2026",
|
|
6928
|
+
onlineLabel = "Online",
|
|
6929
|
+
offlineLabel = "Offline",
|
|
6930
|
+
refreshLabel = "Refresh player list",
|
|
6931
|
+
...rest
|
|
6932
|
+
}) {
|
|
6933
|
+
const theme2 = core.useMantineTheme();
|
|
6934
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
6935
|
+
const [searchInput, setSearchInput] = React4.useState("");
|
|
6936
|
+
const [debouncedSearch, setDebouncedSearch] = React4.useState("");
|
|
6937
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
6938
|
+
includeOffline,
|
|
6939
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
6940
|
+
limit
|
|
6941
|
+
});
|
|
6942
|
+
const sortedPlayers = React4.useMemo(
|
|
6943
|
+
() => [...players].sort((a, b) => {
|
|
6944
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
6945
|
+
return a.charName.localeCompare(b.charName);
|
|
6946
|
+
}),
|
|
6947
|
+
[players]
|
|
6948
|
+
);
|
|
6949
|
+
const playerByCitizen = React4.useMemo(() => {
|
|
6950
|
+
const m = /* @__PURE__ */ new Map();
|
|
6951
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
6952
|
+
return m;
|
|
6953
|
+
}, [sortedPlayers]);
|
|
6954
|
+
const data = React4.useMemo(() => {
|
|
6955
|
+
const items = sortedPlayers.map((p) => ({
|
|
6956
|
+
value: p.citizenId,
|
|
6957
|
+
label: formatLabel(p)
|
|
6958
|
+
}));
|
|
6959
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
6960
|
+
items.unshift({ value, label: value });
|
|
6961
|
+
}
|
|
6962
|
+
return items;
|
|
6963
|
+
}, [sortedPlayers, value]);
|
|
6964
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
6965
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
6966
|
+
React4.useEffect(() => {
|
|
6967
|
+
if (!includeOffline) return;
|
|
6968
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
6969
|
+
const t4 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
6970
|
+
return () => clearTimeout(t4);
|
|
6971
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
6972
|
+
const renderOption = ({ option }) => {
|
|
6973
|
+
const p = playerByCitizen.get(option.value);
|
|
6974
|
+
if (!p) return option.label;
|
|
6975
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
6976
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
6977
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
6978
|
+
] });
|
|
6979
|
+
};
|
|
6980
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6981
|
+
core.Select,
|
|
6982
|
+
{
|
|
6983
|
+
...rest,
|
|
6984
|
+
data,
|
|
6985
|
+
value: value ?? null,
|
|
6986
|
+
onChange: (v) => {
|
|
6987
|
+
if (!v) return onChange(null);
|
|
6988
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
6989
|
+
onChange(player);
|
|
6990
|
+
},
|
|
6991
|
+
searchable: searchableProp ?? true,
|
|
6992
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
6993
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
6994
|
+
placeholder,
|
|
6995
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
6996
|
+
maxDropdownHeight: 300,
|
|
6997
|
+
renderOption,
|
|
6998
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
6999
|
+
rightSectionWidth: "3.5vh",
|
|
7000
|
+
rightSectionPointerEvents: "all",
|
|
7001
|
+
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7002
|
+
core.ActionIcon,
|
|
7003
|
+
{
|
|
7004
|
+
variant: "subtle",
|
|
7005
|
+
size: "sm",
|
|
7006
|
+
onClick: (e) => {
|
|
7007
|
+
e.stopPropagation();
|
|
7008
|
+
refresh();
|
|
7009
|
+
},
|
|
7010
|
+
"aria-label": refreshLabel,
|
|
7011
|
+
title: refreshLabel,
|
|
7012
|
+
style: { marginRight: "0.6vh" },
|
|
7013
|
+
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
7014
|
+
}
|
|
7015
|
+
)
|
|
7016
|
+
}
|
|
7017
|
+
);
|
|
7018
|
+
}
|
|
7019
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7020
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7021
|
+
"span",
|
|
7022
|
+
{
|
|
7023
|
+
title: online ? onlineLabel : offlineLabel,
|
|
7024
|
+
style: {
|
|
7025
|
+
display: "inline-block",
|
|
7026
|
+
width: "0.9vh",
|
|
7027
|
+
height: "0.9vh",
|
|
7028
|
+
borderRadius: "50%",
|
|
7029
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7030
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7031
|
+
flexShrink: 0
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
7034
|
+
);
|
|
7035
|
+
}
|
|
7036
|
+
function formatLabel(p) {
|
|
7037
|
+
const parts = [p.charName || p.citizenId];
|
|
7038
|
+
if (p.online) {
|
|
7039
|
+
if (p.name) parts.push(p.name);
|
|
7040
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7041
|
+
}
|
|
7042
|
+
return parts.join(" \xB7 ");
|
|
7043
|
+
}
|
|
7044
|
+
var COMMON_ACE_GROUPS = ["group.admin", "group.mod", "group.superadmin"];
|
|
7045
|
+
var t = (key, fallback) => {
|
|
7046
|
+
const v = locale(key);
|
|
7047
|
+
return v === key ? fallback : v;
|
|
7048
|
+
};
|
|
7049
|
+
var DEFAULT_VALUE = {
|
|
7050
|
+
groups: [],
|
|
7051
|
+
identifiers: []
|
|
7052
|
+
};
|
|
7053
|
+
function SectionLabel({ icon: Icon, label: label2 }) {
|
|
7054
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", mt: "xs", children: [
|
|
7055
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.4vh", color: "rgba(255,255,255,0.3)" }),
|
|
7056
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
|
|
7057
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
|
|
7058
|
+
] });
|
|
7059
|
+
}
|
|
7060
|
+
function EmptyHint({ text }) {
|
|
7061
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.25)", ta: "center", py: "xs", children: text });
|
|
7062
|
+
}
|
|
7063
|
+
function AccessOverrideSection({
|
|
7064
|
+
schemaKey = "access",
|
|
7065
|
+
title,
|
|
7066
|
+
description: description2,
|
|
7067
|
+
includeOffline = true
|
|
7068
|
+
}) {
|
|
7069
|
+
const mantineTheme = core.useMantineTheme();
|
|
7070
|
+
const color = mantineTheme.colors[mantineTheme.primaryColor][5];
|
|
7071
|
+
const raw = useFormField(schemaKey);
|
|
7072
|
+
const value = {
|
|
7073
|
+
groups: Array.isArray(raw?.groups) ? raw.groups : DEFAULT_VALUE.groups,
|
|
7074
|
+
identifiers: Array.isArray(raw?.identifiers) ? raw.identifiers : DEFAULT_VALUE.identifiers
|
|
7075
|
+
};
|
|
7076
|
+
const { setValue } = useFormActions();
|
|
7077
|
+
const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
|
|
7078
|
+
const [addingGroup, setAddingGroup] = React4.useState(false);
|
|
7079
|
+
const [addingPlayer, setAddingPlayer] = React4.useState(false);
|
|
7080
|
+
const commitGroup = (name) => {
|
|
7081
|
+
const g = name.trim();
|
|
7082
|
+
if (!g) return;
|
|
7083
|
+
if (!value.groups.includes(g)) set("groups", [...value.groups, g]);
|
|
7084
|
+
setAddingGroup(false);
|
|
7085
|
+
};
|
|
7086
|
+
const setGroup = (index, name) => {
|
|
7087
|
+
const next = [...value.groups];
|
|
7088
|
+
next[index] = name;
|
|
7089
|
+
set("groups", next);
|
|
7090
|
+
};
|
|
7091
|
+
const quickAddGroup = (name) => {
|
|
7092
|
+
if (value.groups.includes(name)) return;
|
|
7093
|
+
set("groups", [...value.groups, name]);
|
|
7094
|
+
};
|
|
7095
|
+
const removeGroup = (index) => set("groups", value.groups.filter((_, i) => i !== index));
|
|
7096
|
+
const commitIdentifier = (id) => {
|
|
7097
|
+
if (!id) return;
|
|
7098
|
+
set("identifiers", [...value.identifiers, id]);
|
|
7099
|
+
setAddingPlayer(false);
|
|
7100
|
+
};
|
|
7101
|
+
const setIdentifier = (index, id) => {
|
|
7102
|
+
const next = [...value.identifiers];
|
|
7103
|
+
next[index] = id;
|
|
7104
|
+
set("identifiers", next.filter((x) => x !== ""));
|
|
7105
|
+
};
|
|
7106
|
+
const removeIdentifier = (index) => set("identifiers", value.identifiers.filter((_, i) => i !== index));
|
|
7107
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7108
|
+
core.Flex,
|
|
7109
|
+
{
|
|
7110
|
+
direction: "column",
|
|
7111
|
+
gap: "xs",
|
|
7112
|
+
p: "sm",
|
|
7113
|
+
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
7114
|
+
children: [
|
|
7115
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7116
|
+
AdminPageTitle,
|
|
7117
|
+
{
|
|
7118
|
+
icon: lucideReact.ShieldCheck,
|
|
7119
|
+
title: title || t("Access", "Access"),
|
|
7120
|
+
color
|
|
7121
|
+
}
|
|
7122
|
+
),
|
|
7123
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: description2 || t(
|
|
7124
|
+
"AccessOverrideDesc",
|
|
7125
|
+
"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."
|
|
7126
|
+
) }),
|
|
7127
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.Users, label: t("AccessGroups", "Admin groups (ACE)") }),
|
|
7128
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Flex, { gap: "xs", wrap: "wrap", children: COMMON_ACE_GROUPS.map((g) => {
|
|
7129
|
+
const added = value.groups.includes(g);
|
|
7130
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7131
|
+
core.Flex,
|
|
7132
|
+
{
|
|
7133
|
+
align: "center",
|
|
7134
|
+
gap: "xxs",
|
|
7135
|
+
onClick: added ? void 0 : () => quickAddGroup(g),
|
|
7136
|
+
role: "button",
|
|
7137
|
+
tabIndex: added ? -1 : 0,
|
|
7138
|
+
"aria-disabled": added,
|
|
7139
|
+
onKeyDown: (e) => {
|
|
7140
|
+
if (added) return;
|
|
7141
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7142
|
+
e.preventDefault();
|
|
7143
|
+
quickAddGroup(g);
|
|
7144
|
+
}
|
|
7145
|
+
},
|
|
7146
|
+
px: "xs",
|
|
7147
|
+
py: "xxs",
|
|
7148
|
+
style: {
|
|
7149
|
+
cursor: added ? "default" : "pointer",
|
|
7150
|
+
opacity: added ? 0.4 : 1,
|
|
7151
|
+
background: core.alpha(color, 0.12),
|
|
7152
|
+
border: `0.1vh solid ${core.alpha(color, 0.4)}`,
|
|
7153
|
+
borderRadius: "0.4vh",
|
|
7154
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7155
|
+
},
|
|
7156
|
+
onMouseEnter: (e) => {
|
|
7157
|
+
if (added) return;
|
|
7158
|
+
e.currentTarget.style.background = core.alpha(color, 0.22);
|
|
7159
|
+
},
|
|
7160
|
+
onMouseLeave: (e) => {
|
|
7161
|
+
if (added) return;
|
|
7162
|
+
e.currentTarget.style.background = core.alpha(color, 0.12);
|
|
7163
|
+
},
|
|
7164
|
+
children: [
|
|
7165
|
+
!added && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: "1.2vh", color }),
|
|
7166
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", lts: "0.04em", c: color, children: g })
|
|
7167
|
+
]
|
|
7168
|
+
},
|
|
7169
|
+
g
|
|
7170
|
+
);
|
|
7171
|
+
}) }),
|
|
7172
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
7173
|
+
value.groups.length === 0 && !addingGroup && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7174
|
+
EmptyHint,
|
|
7175
|
+
{
|
|
7176
|
+
text: t("AccessNoGroups", "No ACE groups added. e.g. group.admin")
|
|
7177
|
+
}
|
|
7178
|
+
),
|
|
7179
|
+
value.groups.map((name, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7180
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7181
|
+
core.TextInput,
|
|
7182
|
+
{
|
|
7183
|
+
value: name,
|
|
7184
|
+
onChange: (e) => setGroup(i, e.currentTarget.value),
|
|
7185
|
+
placeholder: t("AccessGroupPlaceholder", "ACE group or permission, e.g. group.admin"),
|
|
7186
|
+
size: "xs",
|
|
7187
|
+
style: { flex: 1 }
|
|
7188
|
+
}
|
|
7189
|
+
),
|
|
7190
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7191
|
+
core.ActionIcon,
|
|
7192
|
+
{
|
|
7193
|
+
variant: "subtle",
|
|
7194
|
+
color: "red",
|
|
7195
|
+
size: "md",
|
|
7196
|
+
onClick: () => removeGroup(i),
|
|
7197
|
+
title: t("Remove", "Remove"),
|
|
7198
|
+
"aria-label": t("Remove", "Remove"),
|
|
7199
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7200
|
+
}
|
|
7201
|
+
)
|
|
7202
|
+
] }, i)),
|
|
7203
|
+
addingGroup && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7204
|
+
AceGroupAddRow,
|
|
7205
|
+
{
|
|
7206
|
+
placeholder: t("AccessGroupPlaceholder", "ACE group or permission, e.g. group.admin"),
|
|
7207
|
+
onCommit: commitGroup,
|
|
7208
|
+
onCancel: () => setAddingGroup(false),
|
|
7209
|
+
removeLabel: t("Remove", "Remove")
|
|
7210
|
+
}
|
|
7211
|
+
)
|
|
7212
|
+
] }),
|
|
7213
|
+
!addingGroup && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddGroup", "Add group"), onClick: () => setAddingGroup(true) }),
|
|
7214
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { icon: lucideReact.UserRound, label: t("AccessPlayers", "Players") }),
|
|
7215
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "xxs", children: [
|
|
7216
|
+
value.identifiers.length === 0 && !addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(EmptyHint, { text: t("AccessNoPlayers", "No players added.") }),
|
|
7217
|
+
value.identifiers.map((id, i) => /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7218
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7219
|
+
PlayerSelect,
|
|
7220
|
+
{
|
|
7221
|
+
value: id || null,
|
|
7222
|
+
onChange: (p) => setIdentifier(i, p?.citizenId ?? ""),
|
|
7223
|
+
includeOffline,
|
|
7224
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7225
|
+
style: { flex: 1 },
|
|
7226
|
+
size: "xs"
|
|
7227
|
+
}
|
|
7228
|
+
),
|
|
7229
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7230
|
+
core.ActionIcon,
|
|
7231
|
+
{
|
|
7232
|
+
variant: "subtle",
|
|
7233
|
+
color: "red",
|
|
7234
|
+
size: "md",
|
|
7235
|
+
onClick: () => removeIdentifier(i),
|
|
7236
|
+
title: t("Remove", "Remove"),
|
|
7237
|
+
"aria-label": t("Remove", "Remove"),
|
|
7238
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7239
|
+
}
|
|
7240
|
+
)
|
|
7241
|
+
] }, i)),
|
|
7242
|
+
addingPlayer && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7244
|
+
PlayerSelect,
|
|
7245
|
+
{
|
|
7246
|
+
value: null,
|
|
7247
|
+
onChange: (p) => commitIdentifier(p?.citizenId ?? ""),
|
|
7248
|
+
includeOffline,
|
|
7249
|
+
placeholder: t("AccessPickPlayer", "Pick a player\u2026"),
|
|
7250
|
+
style: { flex: 1 },
|
|
7251
|
+
size: "xs"
|
|
7252
|
+
}
|
|
7253
|
+
),
|
|
7254
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7255
|
+
core.ActionIcon,
|
|
7256
|
+
{
|
|
7257
|
+
variant: "subtle",
|
|
7258
|
+
color: "red",
|
|
7259
|
+
size: "md",
|
|
7260
|
+
onClick: () => setAddingPlayer(false),
|
|
7261
|
+
title: t("Remove", "Remove"),
|
|
7262
|
+
"aria-label": t("Remove", "Remove"),
|
|
7263
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7264
|
+
}
|
|
7265
|
+
)
|
|
7266
|
+
] })
|
|
7267
|
+
] }),
|
|
7268
|
+
!addingPlayer && /* @__PURE__ */ jsxRuntime.jsx(AddRowButton, { label: t("AccessAddPlayer", "Add player"), onClick: () => setAddingPlayer(true) })
|
|
7269
|
+
]
|
|
7270
|
+
}
|
|
7271
|
+
);
|
|
7272
|
+
}
|
|
7273
|
+
function AddRowButton({ label: label2, onClick }) {
|
|
7274
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7275
|
+
core.Flex,
|
|
7276
|
+
{
|
|
7277
|
+
align: "center",
|
|
7278
|
+
justify: "center",
|
|
7279
|
+
gap: "xs",
|
|
7280
|
+
onClick,
|
|
7281
|
+
role: "button",
|
|
7282
|
+
tabIndex: 0,
|
|
7283
|
+
onKeyDown: (e) => {
|
|
7284
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7285
|
+
e.preventDefault();
|
|
7286
|
+
onClick();
|
|
7287
|
+
}
|
|
7288
|
+
},
|
|
7289
|
+
py: "xs",
|
|
7290
|
+
style: {
|
|
7291
|
+
cursor: "pointer",
|
|
7292
|
+
border: "0.1vh dashed rgba(255,255,255,0.12)",
|
|
7293
|
+
borderRadius: "0.4vh",
|
|
7294
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
7295
|
+
},
|
|
7296
|
+
onMouseEnter: (e) => {
|
|
7297
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.03)";
|
|
7298
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.2)";
|
|
7299
|
+
},
|
|
7300
|
+
onMouseLeave: (e) => {
|
|
7301
|
+
e.currentTarget.style.background = "transparent";
|
|
7302
|
+
e.currentTarget.style.borderColor = "rgba(255,255,255,0.12)";
|
|
7303
|
+
},
|
|
7304
|
+
children: [
|
|
7305
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
|
|
7306
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "rgba(255,255,255,0.4)", children: label2 })
|
|
7307
|
+
]
|
|
7308
|
+
}
|
|
7309
|
+
);
|
|
7310
|
+
}
|
|
7311
|
+
function AceGroupAddRow({
|
|
7312
|
+
placeholder,
|
|
7313
|
+
onCommit,
|
|
7314
|
+
onCancel,
|
|
7315
|
+
removeLabel
|
|
7316
|
+
}) {
|
|
7317
|
+
const [draft, setDraft] = React4.useState("");
|
|
7318
|
+
const commit = () => {
|
|
7319
|
+
if (draft.trim()) onCommit(draft);
|
|
7320
|
+
else onCancel();
|
|
7321
|
+
};
|
|
7322
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xs", children: [
|
|
7323
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7324
|
+
core.TextInput,
|
|
7325
|
+
{
|
|
7326
|
+
value: draft,
|
|
7327
|
+
onChange: (e) => setDraft(e.currentTarget.value),
|
|
7328
|
+
onKeyDown: (e) => {
|
|
7329
|
+
if (e.key === "Enter") {
|
|
7330
|
+
e.preventDefault();
|
|
7331
|
+
commit();
|
|
7332
|
+
} else if (e.key === "Escape") {
|
|
7333
|
+
e.preventDefault();
|
|
7334
|
+
onCancel();
|
|
7335
|
+
}
|
|
7336
|
+
},
|
|
7337
|
+
onBlur: commit,
|
|
7338
|
+
placeholder,
|
|
7339
|
+
size: "xs",
|
|
7340
|
+
autoFocus: true,
|
|
7341
|
+
style: { flex: 1 }
|
|
7342
|
+
}
|
|
7343
|
+
),
|
|
7344
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7345
|
+
core.ActionIcon,
|
|
7346
|
+
{
|
|
7347
|
+
variant: "subtle",
|
|
7348
|
+
color: "red",
|
|
7349
|
+
size: "md",
|
|
7350
|
+
onClick: onCancel,
|
|
7351
|
+
title: removeLabel,
|
|
7352
|
+
"aria-label": removeLabel,
|
|
7353
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: "1.4vh" })
|
|
7354
|
+
}
|
|
7355
|
+
)
|
|
7356
|
+
] });
|
|
7357
|
+
}
|
|
7358
|
+
|
|
7359
|
+
// src/utils/gtaAnimPostFx.ts
|
|
7360
|
+
var GTA_ANIM_POST_FX_GROUP_ORDER = [
|
|
7361
|
+
"Wake Up / Sleep",
|
|
7362
|
+
"Character Switch",
|
|
7363
|
+
"Cinematic Push-In",
|
|
7364
|
+
"Death / Fail",
|
|
7365
|
+
"Heist",
|
|
7366
|
+
"Minigame",
|
|
7367
|
+
"Drug / Trip",
|
|
7368
|
+
"Color Filter / Tint",
|
|
7369
|
+
"Multiplayer",
|
|
7370
|
+
"Misc"
|
|
7371
|
+
];
|
|
7372
|
+
var GTA_ANIM_POST_FX = [
|
|
7373
|
+
// ── Wake Up / Sleep (community-known; not in altV docs) ────────────────────
|
|
7374
|
+
{ name: "ULP_PlayerWakeUp", label: "Player Wake Up", group: "Wake Up / Sleep" },
|
|
7375
|
+
{ name: "MinigameEndNeutral", label: "Minigame End \u2014 Neutral", group: "Wake Up / Sleep" },
|
|
7376
|
+
{ name: "MinigameEndFranklin", label: "Minigame End \u2014 Franklin", group: "Wake Up / Sleep" },
|
|
7377
|
+
{ name: "MinigameEndMichael", label: "Minigame End \u2014 Michael", group: "Wake Up / Sleep" },
|
|
7378
|
+
{ name: "MinigameEndTrevor", label: "Minigame End \u2014 Trevor", group: "Wake Up / Sleep" },
|
|
7379
|
+
// ── Character Switch (Franklin / Michael / Trevor / Neutral variants) ─────
|
|
7380
|
+
{ name: "SwitchHUDIn", group: "Character Switch" },
|
|
7381
|
+
{ name: "SwitchHUDOut", group: "Character Switch" },
|
|
7382
|
+
{ name: "SwitchHUDFranklinIn", group: "Character Switch" },
|
|
7383
|
+
{ name: "SwitchHUDFranklinOut", group: "Character Switch" },
|
|
7384
|
+
{ name: "SwitchHUDMichaelIn", group: "Character Switch" },
|
|
7385
|
+
{ name: "SwitchHUDMichaelOut", group: "Character Switch" },
|
|
7386
|
+
{ name: "SwitchHUDTrevorIn", group: "Character Switch" },
|
|
7387
|
+
{ name: "SwitchHUDTrevorOut", group: "Character Switch" },
|
|
7388
|
+
{ name: "SwitchOpenFranklin", group: "Character Switch" },
|
|
7389
|
+
{ name: "SwitchOpenFranklinIn", group: "Character Switch" },
|
|
7390
|
+
{ name: "SwitchOpenFranklinOut", group: "Character Switch" },
|
|
7391
|
+
{ name: "SwitchOpenMichaelIn", group: "Character Switch" },
|
|
7392
|
+
{ name: "SwitchOpenMichaelMid", group: "Character Switch" },
|
|
7393
|
+
{ name: "SwitchOpenMichaelOut", group: "Character Switch" },
|
|
7394
|
+
{ name: "SwitchOpenTrevorIn", group: "Character Switch" },
|
|
7395
|
+
{ name: "SwitchOpenTrevorOut", group: "Character Switch" },
|
|
7396
|
+
{ name: "SwitchOpenNeutralFIB5", group: "Character Switch" },
|
|
7397
|
+
{ name: "SwitchOpenNeutralOutHeist", group: "Character Switch" },
|
|
7398
|
+
{ name: "SwitchSceneFranklin", group: "Character Switch" },
|
|
7399
|
+
{ name: "SwitchSceneMichael", group: "Character Switch" },
|
|
7400
|
+
{ name: "SwitchSceneNeutral", group: "Character Switch" },
|
|
7401
|
+
{ name: "SwitchSceneTrevor", group: "Character Switch" },
|
|
7402
|
+
{ name: "SwitchShortFranklinIn", group: "Character Switch" },
|
|
7403
|
+
{ name: "SwitchShortFranklinMid", group: "Character Switch" },
|
|
7404
|
+
{ name: "SwitchShortMichaelIn", group: "Character Switch" },
|
|
7405
|
+
{ name: "SwitchShortMichaelMid", group: "Character Switch" },
|
|
7406
|
+
{ name: "SwitchShortNeutralIn", group: "Character Switch" },
|
|
7407
|
+
{ name: "SwitchShortNeutralMid", group: "Character Switch" },
|
|
7408
|
+
{ name: "SwitchShortTrevorIn", group: "Character Switch" },
|
|
7409
|
+
{ name: "SwitchShortTrevorMid", group: "Character Switch" },
|
|
7410
|
+
{ name: "switch_cam_1", group: "Character Switch" },
|
|
7411
|
+
{ name: "switch_cam_2", group: "Character Switch" },
|
|
7412
|
+
// ── Cinematic Push-In (slow zoom intro to a character) ────────────────────
|
|
7413
|
+
{ name: "CamPushInFranklin", group: "Cinematic Push-In" },
|
|
7414
|
+
{ name: "CamPushInMichael", group: "Cinematic Push-In" },
|
|
7415
|
+
{ name: "CamPushInTrevor", group: "Cinematic Push-In" },
|
|
7416
|
+
{ name: "CamPushInNeutral", group: "Cinematic Push-In" },
|
|
7417
|
+
{ name: "BeastIntroScene", label: "Beast Intro", group: "Cinematic Push-In" },
|
|
7418
|
+
{ name: "BeastLaunch", group: "Cinematic Push-In" },
|
|
7419
|
+
{ name: "BeastTransition", group: "Cinematic Push-In" },
|
|
7420
|
+
// ── Death / Fail (red tint, slow-mo blur) ─────────────────────────────────
|
|
7421
|
+
{ name: "DeathFailNeutralIn", group: "Death / Fail" },
|
|
7422
|
+
{ name: "DeathFailFranklinIn", group: "Death / Fail" },
|
|
7423
|
+
{ name: "DeathFailMichaelIn", group: "Death / Fail" },
|
|
7424
|
+
{ name: "DeathFailTrevorIn", group: "Death / Fail" },
|
|
7425
|
+
{ name: "DeathFailMPIn", label: "Death Fail \u2014 MP", group: "Death / Fail" },
|
|
7426
|
+
{ name: "DeathFailMPDark", label: "Death Fail \u2014 MP Dark", group: "Death / Fail" },
|
|
7427
|
+
{ name: "DeathFailOut", group: "Death / Fail" },
|
|
7428
|
+
{ name: "Rampage", group: "Death / Fail" },
|
|
7429
|
+
{ name: "RampageOut", group: "Death / Fail" },
|
|
7430
|
+
// ── Heist (celebration / locate / pass) ───────────────────────────────────
|
|
7431
|
+
{ name: "HeistCelebEnd", group: "Heist" },
|
|
7432
|
+
{ name: "HeistCelebPass", group: "Heist" },
|
|
7433
|
+
{ name: "HeistCelebPassBW", label: "Heist Celeb Pass (B/W)", group: "Heist" },
|
|
7434
|
+
{ name: "HeistCelebToast", group: "Heist" },
|
|
7435
|
+
{ name: "HeistLocate", group: "Heist" },
|
|
7436
|
+
{ name: "HeistTripSkipFade", group: "Heist" },
|
|
7437
|
+
// ── Minigame / Menu ───────────────────────────────────────────────────────
|
|
7438
|
+
{ name: "MenuMGIn", group: "Minigame" },
|
|
7439
|
+
{ name: "MenuMGHeistIn", group: "Minigame" },
|
|
7440
|
+
{ name: "MenuMGHeistIntro", group: "Minigame" },
|
|
7441
|
+
{ name: "MenuMGHeistOut", group: "Minigame" },
|
|
7442
|
+
{ name: "MenuMGHeistTint", group: "Minigame" },
|
|
7443
|
+
{ name: "MenuMGSelectionIn", group: "Minigame" },
|
|
7444
|
+
{ name: "MenuMGSelectionTint", group: "Minigame" },
|
|
7445
|
+
{ name: "MenuMGTournamentIn", group: "Minigame" },
|
|
7446
|
+
{ name: "MenuMGTournamentTint", group: "Minigame" },
|
|
7447
|
+
{ name: "MinigameTransitionIn", group: "Minigame" },
|
|
7448
|
+
{ name: "MinigameTransitionOut", group: "Minigame" },
|
|
7449
|
+
// ── Drug / Trip (psychedelic, blur, distortion) ───────────────────────────
|
|
7450
|
+
{ name: "DMT_flight", group: "Drug / Trip" },
|
|
7451
|
+
{ name: "DMT_flight_intro", group: "Drug / Trip" },
|
|
7452
|
+
{ name: "PeyoteIn", group: "Drug / Trip" },
|
|
7453
|
+
{ name: "PeyoteOut", group: "Drug / Trip" },
|
|
7454
|
+
{ name: "PeyoteEndIn", group: "Drug / Trip" },
|
|
7455
|
+
{ name: "PeyoteEndOut", group: "Drug / Trip" },
|
|
7456
|
+
{ name: "DrugsDrivingIn", group: "Drug / Trip" },
|
|
7457
|
+
{ name: "DrugsDrivingOut", group: "Drug / Trip" },
|
|
7458
|
+
{ name: "DrugsMichaelAliensFight", group: "Drug / Trip" },
|
|
7459
|
+
{ name: "DrugsMichaelAliensFightIn", group: "Drug / Trip" },
|
|
7460
|
+
{ name: "DrugsMichaelAliensFightOut", group: "Drug / Trip" },
|
|
7461
|
+
{ name: "DrugsTrevorClownsFight", group: "Drug / Trip" },
|
|
7462
|
+
{ name: "DrugsTrevorClownsFightIn", group: "Drug / Trip" },
|
|
7463
|
+
{ name: "DrugsTrevorClownsFightOut", group: "Drug / Trip" },
|
|
7464
|
+
{ name: "ChopVision", label: "Chop Vision (dog)", group: "Drug / Trip" },
|
|
7465
|
+
// ── Color Filter / Tint (one-off and biker formation filters) ─────────────
|
|
7466
|
+
{ name: "PPFilter", group: "Color Filter / Tint" },
|
|
7467
|
+
{ name: "PPFilterOut", group: "Color Filter / Tint" },
|
|
7468
|
+
{ name: "PPGreen", group: "Color Filter / Tint" },
|
|
7469
|
+
{ name: "PPGreenOut", group: "Color Filter / Tint" },
|
|
7470
|
+
{ name: "PPOrange", group: "Color Filter / Tint" },
|
|
7471
|
+
{ name: "PPOrangeOut", group: "Color Filter / Tint" },
|
|
7472
|
+
{ name: "PPPink", group: "Color Filter / Tint" },
|
|
7473
|
+
{ name: "PPPinkOut", group: "Color Filter / Tint" },
|
|
7474
|
+
{ name: "PPPurple", group: "Color Filter / Tint" },
|
|
7475
|
+
{ name: "PPPurpleOut", group: "Color Filter / Tint" },
|
|
7476
|
+
{ name: "BikerFilter", group: "Color Filter / Tint" },
|
|
7477
|
+
{ name: "BikerFilterOut", group: "Color Filter / Tint" },
|
|
7478
|
+
{ name: "BikerFormation", group: "Color Filter / Tint" },
|
|
7479
|
+
{ name: "BikerFormationOut", group: "Color Filter / Tint" },
|
|
7480
|
+
{ name: "InchOrange", group: "Color Filter / Tint" },
|
|
7481
|
+
{ name: "InchOrangeOut", group: "Color Filter / Tint" },
|
|
7482
|
+
{ name: "InchPurple", group: "Color Filter / Tint" },
|
|
7483
|
+
{ name: "InchPurpleOut", group: "Color Filter / Tint" },
|
|
7484
|
+
{ name: "InchPickup", group: "Color Filter / Tint" },
|
|
7485
|
+
{ name: "InchPickupOut", group: "Color Filter / Tint" },
|
|
7486
|
+
{ name: "TinyRacerGreen", group: "Color Filter / Tint" },
|
|
7487
|
+
{ name: "TinyRacerGreenOut", group: "Color Filter / Tint" },
|
|
7488
|
+
{ name: "TinyRacerPink", group: "Color Filter / Tint" },
|
|
7489
|
+
{ name: "TinyRacerPinkOut", group: "Color Filter / Tint" },
|
|
7490
|
+
{ name: "TinyRacerIntroCam", group: "Color Filter / Tint" },
|
|
7491
|
+
{ name: "DeadlineNeon", group: "Color Filter / Tint" },
|
|
7492
|
+
// ── Multiplayer (celeb, killstreak, race, etc.) ───────────────────────────
|
|
7493
|
+
{ name: "MP_Celeb_Win", group: "Multiplayer" },
|
|
7494
|
+
{ name: "MP_Celeb_Win_Out", group: "Multiplayer" },
|
|
7495
|
+
{ name: "MP_Celeb_Lose", group: "Multiplayer" },
|
|
7496
|
+
{ name: "MP_Celeb_Lose_Out", group: "Multiplayer" },
|
|
7497
|
+
{ name: "MP_Celeb_Preload", group: "Multiplayer" },
|
|
7498
|
+
{ name: "MP_Celeb_Preload_Fade", group: "Multiplayer" },
|
|
7499
|
+
{ name: "MP_Bull_tost", group: "Multiplayer" },
|
|
7500
|
+
{ name: "MP_Bull_tost_Out", group: "Multiplayer" },
|
|
7501
|
+
{ name: "MP_Killstreak", group: "Multiplayer" },
|
|
7502
|
+
{ name: "MP_Killstreak_Out", group: "Multiplayer" },
|
|
7503
|
+
{ name: "MP_Loser_Streak_Out", group: "Multiplayer" },
|
|
7504
|
+
{ name: "MP_OrbitalCannon", group: "Multiplayer" },
|
|
7505
|
+
{ name: "MP_Powerplay", group: "Multiplayer" },
|
|
7506
|
+
{ name: "MP_Powerplay_Out", group: "Multiplayer" },
|
|
7507
|
+
{ name: "MP_SmugglerCheckpoint", group: "Multiplayer" },
|
|
7508
|
+
{ name: "MP_TransformRaceFlash", group: "Multiplayer" },
|
|
7509
|
+
{ name: "MP_WarpCheckpoint", group: "Multiplayer" },
|
|
7510
|
+
{ name: "MP_corona_switch", group: "Multiplayer" },
|
|
7511
|
+
{ name: "MP_intro_logo", group: "Multiplayer" },
|
|
7512
|
+
{ name: "MP_job_load", group: "Multiplayer" },
|
|
7513
|
+
{ name: "MP_race_crash", group: "Multiplayer" },
|
|
7514
|
+
// ── Misc (success notifs, special weapons, sniper / pause / explosions) ───
|
|
7515
|
+
{ name: "SuccessFranklin", group: "Misc" },
|
|
7516
|
+
{ name: "SuccessMichael", group: "Misc" },
|
|
7517
|
+
{ name: "SuccessNeutral", group: "Misc" },
|
|
7518
|
+
{ name: "SuccessTrevor", group: "Misc" },
|
|
7519
|
+
{ name: "FocusIn", group: "Misc" },
|
|
7520
|
+
{ name: "FocusOut", group: "Misc" },
|
|
7521
|
+
{ name: "CrossLine", group: "Misc" },
|
|
7522
|
+
{ name: "CrossLineOut", group: "Misc" },
|
|
7523
|
+
{ name: "SniperOverlay", group: "Misc" },
|
|
7524
|
+
{ name: "ExplosionJosh3", group: "Misc" },
|
|
7525
|
+
{ name: "WeaponUpgrade", group: "Misc" },
|
|
7526
|
+
{ name: "Dont_tazeme_bro", label: "Don't Taze Me Bro", group: "Misc" },
|
|
7527
|
+
{ name: "LostTimeDay", group: "Misc" },
|
|
7528
|
+
{ name: "LostTimeNight", group: "Misc" },
|
|
7529
|
+
{ name: "PauseMenuOut", group: "Misc" },
|
|
7530
|
+
{ name: "pennedIn", group: "Misc" },
|
|
7531
|
+
{ name: "PennedInOut", group: "Misc" },
|
|
7532
|
+
{ name: "RaceTurbo", group: "Misc" },
|
|
7533
|
+
{ name: "DefaultFlash", group: "Misc" }
|
|
7534
|
+
];
|
|
7535
|
+
function formatGtaAnimPostFx(name) {
|
|
7536
|
+
const entry = GTA_ANIM_POST_FX.find((fx) => fx.name === name);
|
|
7537
|
+
return entry?.label ?? name;
|
|
7538
|
+
}
|
|
7539
|
+
function buildGroupedData2(extraNames = []) {
|
|
7540
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7541
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7542
|
+
for (const fx of GTA_ANIM_POST_FX) {
|
|
7543
|
+
if (seen.has(fx.name)) continue;
|
|
7544
|
+
seen.add(fx.name);
|
|
7545
|
+
if (!groups.has(fx.group)) groups.set(fx.group, []);
|
|
7546
|
+
groups.get(fx.group).push(fx);
|
|
7547
|
+
}
|
|
7548
|
+
const data = GTA_ANIM_POST_FX_GROUP_ORDER.flatMap((g) => {
|
|
7549
|
+
const items = groups.get(g);
|
|
7550
|
+
if (!items || items.length === 0) return [];
|
|
7551
|
+
return [
|
|
7552
|
+
{
|
|
7553
|
+
group: g,
|
|
7554
|
+
items: items.map((fx) => ({
|
|
7555
|
+
value: fx.name,
|
|
7556
|
+
label: formatGtaAnimPostFx(fx.name)
|
|
7557
|
+
}))
|
|
7558
|
+
}
|
|
7559
|
+
];
|
|
7560
|
+
});
|
|
7561
|
+
const knownNames = new Set(GTA_ANIM_POST_FX.map((fx) => fx.name));
|
|
7562
|
+
const customs = extraNames.filter((n) => n && !knownNames.has(n));
|
|
7563
|
+
if (customs.length > 0) {
|
|
7064
7564
|
data.push({
|
|
7065
7565
|
group: "Custom",
|
|
7066
7566
|
items: customs.map((n) => ({ value: n, label: n }))
|
|
@@ -7444,7 +7944,7 @@ function ScenarioSelect({
|
|
|
7444
7944
|
}
|
|
7445
7945
|
);
|
|
7446
7946
|
}
|
|
7447
|
-
var
|
|
7947
|
+
var t2 = (key, fallback) => {
|
|
7448
7948
|
const v = locale(key);
|
|
7449
7949
|
return v === key ? fallback : v;
|
|
7450
7950
|
};
|
|
@@ -7512,7 +8012,7 @@ function DiscordRoleSelect(props) {
|
|
|
7512
8012
|
return map;
|
|
7513
8013
|
}, [roles]);
|
|
7514
8014
|
if (errorCode === "NotConfigured") {
|
|
7515
|
-
const notConfiguredPlaceholder =
|
|
8015
|
+
const notConfiguredPlaceholder = t2(
|
|
7516
8016
|
"DiscordNotConfigured",
|
|
7517
8017
|
"Not configured \u2014 set in /dirk_lib"
|
|
7518
8018
|
);
|
|
@@ -7580,9 +8080,9 @@ function DiscordRoleSelect(props) {
|
|
|
7580
8080
|
e.stopPropagation();
|
|
7581
8081
|
refresh();
|
|
7582
8082
|
},
|
|
7583
|
-
title:
|
|
8083
|
+
title: t2("Refresh", "Refresh"),
|
|
7584
8084
|
loading,
|
|
7585
|
-
"aria-label":
|
|
8085
|
+
"aria-label": t2("Refresh", "Refresh"),
|
|
7586
8086
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
7587
8087
|
}
|
|
7588
8088
|
);
|
|
@@ -7592,7 +8092,7 @@ function DiscordRoleSelect(props) {
|
|
|
7592
8092
|
{
|
|
7593
8093
|
label: label2,
|
|
7594
8094
|
size,
|
|
7595
|
-
placeholder: placeholder ||
|
|
8095
|
+
placeholder: placeholder || t2("PickRoles", "Pick roles..."),
|
|
7596
8096
|
data,
|
|
7597
8097
|
value: props.value || [],
|
|
7598
8098
|
onChange: (ids) => props.onChange(ids),
|
|
@@ -7604,7 +8104,7 @@ function DiscordRoleSelect(props) {
|
|
|
7604
8104
|
rightSectionPointerEvents: "all",
|
|
7605
8105
|
style,
|
|
7606
8106
|
styles,
|
|
7607
|
-
nothingFoundMessage: errorCode ? `${
|
|
8107
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7608
8108
|
}
|
|
7609
8109
|
);
|
|
7610
8110
|
}
|
|
@@ -7613,7 +8113,7 @@ function DiscordRoleSelect(props) {
|
|
|
7613
8113
|
{
|
|
7614
8114
|
label: label2,
|
|
7615
8115
|
size,
|
|
7616
|
-
placeholder: placeholder ||
|
|
8116
|
+
placeholder: placeholder || t2("PickRole", "Pick a role..."),
|
|
7617
8117
|
data,
|
|
7618
8118
|
value: props.value || null,
|
|
7619
8119
|
onChange: (id) => props.onChange(id),
|
|
@@ -7625,11 +8125,11 @@ function DiscordRoleSelect(props) {
|
|
|
7625
8125
|
rightSectionPointerEvents: "all",
|
|
7626
8126
|
style,
|
|
7627
8127
|
styles,
|
|
7628
|
-
nothingFoundMessage: errorCode ? `${
|
|
8128
|
+
nothingFoundMessage: errorCode ? `${t2("Error", "Error")} (${errorCode})` : t2("NoRoles", "No roles found")
|
|
7629
8129
|
}
|
|
7630
8130
|
);
|
|
7631
8131
|
}
|
|
7632
|
-
var
|
|
8132
|
+
var t3 = (key, fallback) => {
|
|
7633
8133
|
const v = locale(key);
|
|
7634
8134
|
return v === key ? fallback : v;
|
|
7635
8135
|
};
|
|
@@ -7650,7 +8150,7 @@ function FrameworkHint({ framework }) {
|
|
|
7650
8150
|
const theme2 = core.useMantineTheme();
|
|
7651
8151
|
if (!framework) return null;
|
|
7652
8152
|
const hintKey = `AccountFrameworkHint_${framework}`;
|
|
7653
|
-
const text =
|
|
8153
|
+
const text = t3(hintKey, FRAMEWORK_HINTS[framework] || FRAMEWORK_HINTS.unknown);
|
|
7654
8154
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7655
8155
|
core.Flex,
|
|
7656
8156
|
{
|
|
@@ -7734,9 +8234,9 @@ function AccountSelect(props) {
|
|
|
7734
8234
|
e.stopPropagation();
|
|
7735
8235
|
refresh();
|
|
7736
8236
|
},
|
|
7737
|
-
title:
|
|
8237
|
+
title: t3("Refresh", "Refresh"),
|
|
7738
8238
|
loading,
|
|
7739
|
-
"aria-label":
|
|
8239
|
+
"aria-label": t3("Refresh", "Refresh"),
|
|
7740
8240
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.2vh" })
|
|
7741
8241
|
}
|
|
7742
8242
|
);
|
|
@@ -7750,14 +8250,14 @@ function AccountSelect(props) {
|
|
|
7750
8250
|
rightSection: refreshButton,
|
|
7751
8251
|
rightSectionPointerEvents: "all",
|
|
7752
8252
|
style,
|
|
7753
|
-
nothingFoundMessage:
|
|
8253
|
+
nothingFoundMessage: t3("NoAccounts", "No accounts available")
|
|
7754
8254
|
};
|
|
7755
8255
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: "0.3vh", style, children: [
|
|
7756
8256
|
props.multi ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7757
8257
|
core.MultiSelect,
|
|
7758
8258
|
{
|
|
7759
8259
|
...sharedSelectProps,
|
|
7760
|
-
placeholder: placeholder ||
|
|
8260
|
+
placeholder: placeholder || t3("PickAccounts", "Pick accounts (or type custom)..."),
|
|
7761
8261
|
value: props.value || [],
|
|
7762
8262
|
onChange: (names) => props.onChange(names),
|
|
7763
8263
|
renderOption,
|
|
@@ -7769,7 +8269,7 @@ function AccountSelect(props) {
|
|
|
7769
8269
|
core.Select,
|
|
7770
8270
|
{
|
|
7771
8271
|
...sharedSelectProps,
|
|
7772
|
-
placeholder: placeholder ||
|
|
8272
|
+
placeholder: placeholder || t3("PickAccount", "Pick an account..."),
|
|
7773
8273
|
value: props.value || null,
|
|
7774
8274
|
onChange: (name) => props.onChange(name),
|
|
7775
8275
|
renderOption,
|
|
@@ -8061,175 +8561,6 @@ function WorldPositionGotoButton2({
|
|
|
8061
8561
|
}
|
|
8062
8562
|
) });
|
|
8063
8563
|
}
|
|
8064
|
-
function usePlayers(opts = {}) {
|
|
8065
|
-
const {
|
|
8066
|
-
includeOffline = false,
|
|
8067
|
-
search = "",
|
|
8068
|
-
limit = 50,
|
|
8069
|
-
staleTimeMs,
|
|
8070
|
-
refetchIntervalMs
|
|
8071
|
-
} = opts;
|
|
8072
|
-
const query = reactQuery.useQuery({
|
|
8073
|
-
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
8074
|
-
queryFn: async () => {
|
|
8075
|
-
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
8076
|
-
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
8077
|
-
const result = await fetchNui(
|
|
8078
|
-
"ADMIN_TOOL_QUERY",
|
|
8079
|
-
payload,
|
|
8080
|
-
// Browser-dev fallback. Returns a couple of mock players so the
|
|
8081
|
-
// dev shell isn't blank.
|
|
8082
|
-
includeOffline ? [
|
|
8083
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
8084
|
-
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
8085
|
-
] : [
|
|
8086
|
-
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
8087
|
-
]
|
|
8088
|
-
);
|
|
8089
|
-
return Array.isArray(result) ? result : [];
|
|
8090
|
-
},
|
|
8091
|
-
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
8092
|
-
gcTime: 5 * 6e4,
|
|
8093
|
-
refetchInterval: refetchIntervalMs ?? false,
|
|
8094
|
-
refetchOnWindowFocus: false,
|
|
8095
|
-
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
8096
|
-
});
|
|
8097
|
-
return {
|
|
8098
|
-
players: query.data ?? [],
|
|
8099
|
-
isLoading: query.isLoading,
|
|
8100
|
-
isFetching: query.isFetching,
|
|
8101
|
-
error: query.error ?? null,
|
|
8102
|
-
refresh: () => query.refetch()
|
|
8103
|
-
};
|
|
8104
|
-
}
|
|
8105
|
-
var DEBOUNCE_MS = 300;
|
|
8106
|
-
var ONLINE_COLOR = "#3FA83F";
|
|
8107
|
-
var OFFLINE_COLOR = "#E54141";
|
|
8108
|
-
function PlayerSelect({
|
|
8109
|
-
value,
|
|
8110
|
-
onChange,
|
|
8111
|
-
includeOffline = false,
|
|
8112
|
-
limit = 50,
|
|
8113
|
-
searchable: searchableProp,
|
|
8114
|
-
placeholder,
|
|
8115
|
-
nothingFoundMessage: nothingFoundMessageProp,
|
|
8116
|
-
loadingLabel = "Loading\u2026",
|
|
8117
|
-
onlineLabel = "Online",
|
|
8118
|
-
offlineLabel = "Offline",
|
|
8119
|
-
refreshLabel = "Refresh player list",
|
|
8120
|
-
...rest
|
|
8121
|
-
}) {
|
|
8122
|
-
const theme2 = core.useMantineTheme();
|
|
8123
|
-
const color = theme2.colors[theme2.primaryColor][5];
|
|
8124
|
-
const [searchInput, setSearchInput] = React4.useState("");
|
|
8125
|
-
const [debouncedSearch, setDebouncedSearch] = React4.useState("");
|
|
8126
|
-
const { players, isFetching, refresh } = usePlayers({
|
|
8127
|
-
includeOffline,
|
|
8128
|
-
search: includeOffline ? debouncedSearch : void 0,
|
|
8129
|
-
limit
|
|
8130
|
-
});
|
|
8131
|
-
const sortedPlayers = React4.useMemo(
|
|
8132
|
-
() => [...players].sort((a, b) => {
|
|
8133
|
-
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
8134
|
-
return a.charName.localeCompare(b.charName);
|
|
8135
|
-
}),
|
|
8136
|
-
[players]
|
|
8137
|
-
);
|
|
8138
|
-
const playerByCitizen = React4.useMemo(() => {
|
|
8139
|
-
const m = /* @__PURE__ */ new Map();
|
|
8140
|
-
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
8141
|
-
return m;
|
|
8142
|
-
}, [sortedPlayers]);
|
|
8143
|
-
const data = React4.useMemo(() => {
|
|
8144
|
-
const items = sortedPlayers.map((p) => ({
|
|
8145
|
-
value: p.citizenId,
|
|
8146
|
-
label: formatLabel(p)
|
|
8147
|
-
}));
|
|
8148
|
-
if (value && !items.some((i) => i.value === value)) {
|
|
8149
|
-
items.unshift({ value, label: value });
|
|
8150
|
-
}
|
|
8151
|
-
return items;
|
|
8152
|
-
}, [sortedPlayers, value]);
|
|
8153
|
-
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
8154
|
-
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
8155
|
-
React4.useEffect(() => {
|
|
8156
|
-
if (!includeOffline) return;
|
|
8157
|
-
if (selectedLabel && searchInput === selectedLabel) return;
|
|
8158
|
-
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
8159
|
-
return () => clearTimeout(t3);
|
|
8160
|
-
}, [searchInput, includeOffline, selectedLabel]);
|
|
8161
|
-
const renderOption = ({ option }) => {
|
|
8162
|
-
const p = playerByCitizen.get(option.value);
|
|
8163
|
-
if (!p) return option.label;
|
|
8164
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
8165
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
8166
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
8167
|
-
] });
|
|
8168
|
-
};
|
|
8169
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8170
|
-
core.Select,
|
|
8171
|
-
{
|
|
8172
|
-
...rest,
|
|
8173
|
-
data,
|
|
8174
|
-
value: value ?? null,
|
|
8175
|
-
onChange: (v) => {
|
|
8176
|
-
if (!v) return onChange(null);
|
|
8177
|
-
const player = playerByCitizen.get(v) ?? null;
|
|
8178
|
-
onChange(player);
|
|
8179
|
-
},
|
|
8180
|
-
searchable: searchableProp ?? true,
|
|
8181
|
-
searchValue: includeOffline ? searchInput : void 0,
|
|
8182
|
-
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
8183
|
-
placeholder,
|
|
8184
|
-
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
8185
|
-
maxDropdownHeight: 300,
|
|
8186
|
-
renderOption,
|
|
8187
|
-
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
8188
|
-
rightSectionWidth: "3.5vh",
|
|
8189
|
-
rightSectionPointerEvents: "all",
|
|
8190
|
-
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8191
|
-
core.ActionIcon,
|
|
8192
|
-
{
|
|
8193
|
-
variant: "subtle",
|
|
8194
|
-
size: "sm",
|
|
8195
|
-
onClick: (e) => {
|
|
8196
|
-
e.stopPropagation();
|
|
8197
|
-
refresh();
|
|
8198
|
-
},
|
|
8199
|
-
"aria-label": refreshLabel,
|
|
8200
|
-
title: refreshLabel,
|
|
8201
|
-
style: { marginRight: "0.6vh" },
|
|
8202
|
-
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
8203
|
-
}
|
|
8204
|
-
)
|
|
8205
|
-
}
|
|
8206
|
-
);
|
|
8207
|
-
}
|
|
8208
|
-
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
8209
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8210
|
-
"span",
|
|
8211
|
-
{
|
|
8212
|
-
title: online ? onlineLabel : offlineLabel,
|
|
8213
|
-
style: {
|
|
8214
|
-
display: "inline-block",
|
|
8215
|
-
width: "0.9vh",
|
|
8216
|
-
height: "0.9vh",
|
|
8217
|
-
borderRadius: "50%",
|
|
8218
|
-
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
8219
|
-
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
8220
|
-
flexShrink: 0
|
|
8221
|
-
}
|
|
8222
|
-
}
|
|
8223
|
-
);
|
|
8224
|
-
}
|
|
8225
|
-
function formatLabel(p) {
|
|
8226
|
-
const parts = [p.charName || p.citizenId];
|
|
8227
|
-
if (p.online) {
|
|
8228
|
-
if (p.name) parts.push(p.name);
|
|
8229
|
-
if (p.id != null) parts.push(`#${p.id}`);
|
|
8230
|
-
}
|
|
8231
|
-
return parts.join(" \xB7 ");
|
|
8232
|
-
}
|
|
8233
8564
|
function usePickDoor() {
|
|
8234
8565
|
const begin = useAdminToolStore((s) => s.begin);
|
|
8235
8566
|
return async () => {
|
|
@@ -8621,6 +8952,7 @@ var Vector4Schema = zod.z.object({
|
|
|
8621
8952
|
w: zod.z.number()
|
|
8622
8953
|
});
|
|
8623
8954
|
|
|
8955
|
+
exports.AccessOverrideSection = AccessOverrideSection;
|
|
8624
8956
|
exports.AccountSelect = AccountSelect;
|
|
8625
8957
|
exports.AdminPageTitle = AdminPageTitle;
|
|
8626
8958
|
exports.AnimPostFxSelect = AnimPostFxSelect;
|
|
@@ -8635,6 +8967,7 @@ exports.ConfirmModal = ConfirmModal;
|
|
|
8635
8967
|
exports.ControlMultiSelect = ControlMultiSelect;
|
|
8636
8968
|
exports.ControlSelect = ControlSelect;
|
|
8637
8969
|
exports.Counter = Counter;
|
|
8970
|
+
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|
|
8638
8971
|
exports.DirkProvider = DirkProvider;
|
|
8639
8972
|
exports.DiscordRoleSelect = DiscordRoleSelect;
|
|
8640
8973
|
exports.DoorPickerButton = DoorPickerButton;
|
|
@@ -8675,6 +9008,7 @@ exports.SegmentedProgress = SegmentedProgress;
|
|
|
8675
9008
|
exports.SelectItem = SelectItem;
|
|
8676
9009
|
exports.SwitchPanel = SwitchPanel;
|
|
8677
9010
|
exports.TestBed = TestBed;
|
|
9011
|
+
exports.ThemeOverrideSchema = ThemeOverrideSchema;
|
|
8678
9012
|
exports.ThemeOverrideSection = ThemeOverrideSection;
|
|
8679
9013
|
exports.Title = Title;
|
|
8680
9014
|
exports.TornEdgeSVGFilter = TornEdgeSVGFilter;
|
|
@@ -8695,6 +9029,7 @@ exports.copyToClipboard = copyToClipboard;
|
|
|
8695
9029
|
exports.createFormStore = createFormStore;
|
|
8696
9030
|
exports.createScriptConfig = createScriptConfig;
|
|
8697
9031
|
exports.createSkill = createSkill;
|
|
9032
|
+
exports.defaultThemeOverride = defaultThemeOverride;
|
|
8698
9033
|
exports.dirkQueryClient = dirkQueryClient;
|
|
8699
9034
|
exports.ensureFrameworkGroups = ensureFrameworkGroups;
|
|
8700
9035
|
exports.extractDefaults = extractDefaults;
|