dirk-cfx-react 1.1.87 → 1.1.90
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 +922 -57
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +192 -2
- package/dist/components/index.d.ts +192 -2
- package/dist/components/index.js +913 -62
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/index.cjs +159 -26
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +16 -1
- package/dist/hooks/index.d.ts +16 -1
- package/dist/hooks/index.js +157 -28
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +1487 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1390 -397
- package/dist/index.js.map +1 -1
- package/dist/providers/index.cjs +162 -6
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +3 -1
- package/dist/providers/index.d.ts +3 -1
- package/dist/providers/index.js +163 -8
- package/dist/providers/index.js.map +1 -1
- package/dist/usePlayers-BlGBBevs.d.cts +37 -0
- package/dist/usePlayers-BlGBBevs.d.ts +37 -0
- package/dist/utils/index.cjs +45 -13
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +2 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +45 -14
- package/dist/utils/index.js.map +1 -1
- package/package.json +123 -117
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@mantine/core');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var
|
|
5
|
+
var React4 = require('react');
|
|
6
6
|
var zustand = require('zustand');
|
|
7
7
|
var axios = require('axios');
|
|
8
8
|
var reactFontawesome = require('@fortawesome/react-fontawesome');
|
|
@@ -12,7 +12,6 @@ var clickSoundUrl = require('./click_sound-PNCRRTM4.mp3');
|
|
|
12
12
|
var hoverSoundUrl = require('./hover_sound-NBUA222C.mp3');
|
|
13
13
|
var notifications = require('@mantine/notifications');
|
|
14
14
|
var reactQuery = require('@tanstack/react-query');
|
|
15
|
-
var colorsGenerator = require('@mantine/colors-generator');
|
|
16
15
|
require('@mantine/core/styles.css');
|
|
17
16
|
require('@mantine/notifications/styles.css');
|
|
18
17
|
require('./styles/fonts.css');
|
|
@@ -23,11 +22,17 @@ var fontawesomeSvgCore = require('@fortawesome/fontawesome-svg-core');
|
|
|
23
22
|
var freeBrandsSvgIcons = require('@fortawesome/free-brands-svg-icons');
|
|
24
23
|
var freeRegularSvgIcons = require('@fortawesome/free-regular-svg-icons');
|
|
25
24
|
var freeSolidSvgIcons = require('@fortawesome/free-solid-svg-icons');
|
|
25
|
+
var colorsGenerator = require('@mantine/colors-generator');
|
|
26
|
+
var reactDom = require('react-dom');
|
|
27
|
+
var leaflet = require('leaflet');
|
|
28
|
+
require('leaflet/dist/leaflet.css');
|
|
29
|
+
var reactLeaflet = require('react-leaflet');
|
|
30
|
+
var reactLeafletComponentMarker = require('@adamscybot/react-leaflet-component-marker');
|
|
26
31
|
var zod = require('zod');
|
|
27
32
|
|
|
28
33
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
34
|
|
|
30
|
-
var
|
|
35
|
+
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
31
36
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
32
37
|
var clickSoundUrl__default = /*#__PURE__*/_interopDefault(clickSoundUrl);
|
|
33
38
|
var hoverSoundUrl__default = /*#__PURE__*/_interopDefault(hoverSoundUrl);
|
|
@@ -976,6 +981,18 @@ var BLIP_COLOR_DATA = BLIP_COLORS.map(([id, label2]) => ({
|
|
|
976
981
|
}));
|
|
977
982
|
var blipEntryMap = new Map(BLIP_ENTRIES.map(([id, name, ext]) => [String(id), { id, name, ext }]));
|
|
978
983
|
var blipColorMap = new Map(BLIP_COLORS.map(([id, label2, hex]) => [String(id), { id, label: label2, hex }]));
|
|
984
|
+
function getBlipEntry(spriteId) {
|
|
985
|
+
if (spriteId == null) return void 0;
|
|
986
|
+
return blipEntryMap.get(String(spriteId));
|
|
987
|
+
}
|
|
988
|
+
function getBlipColor(colorId) {
|
|
989
|
+
if (colorId == null) return void 0;
|
|
990
|
+
return blipColorMap.get(String(colorId));
|
|
991
|
+
}
|
|
992
|
+
function blipUrlForSprite(spriteId) {
|
|
993
|
+
const entry = getBlipEntry(spriteId);
|
|
994
|
+
return entry ? blipUrl(entry.name, entry.ext) : null;
|
|
995
|
+
}
|
|
979
996
|
var renderBlipOption = ({ option }) => {
|
|
980
997
|
const entry = blipEntryMap.get(option.value);
|
|
981
998
|
if (!entry) return option.label;
|
|
@@ -1253,11 +1270,11 @@ var colorNames = {
|
|
|
1253
1270
|
Yellow: { r: 255, g: 255, b: 0 },
|
|
1254
1271
|
YellowGreen: { r: 154, g: 205, b: 50 }
|
|
1255
1272
|
};
|
|
1256
|
-
function colorWithAlpha(color,
|
|
1273
|
+
function colorWithAlpha(color, alpha18) {
|
|
1257
1274
|
const lowerCasedColor = color.toLowerCase();
|
|
1258
1275
|
if (colorNames[lowerCasedColor]) {
|
|
1259
1276
|
const rgb = colorNames[lowerCasedColor];
|
|
1260
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${
|
|
1277
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha18})`;
|
|
1261
1278
|
}
|
|
1262
1279
|
if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
|
|
1263
1280
|
const hex = color.slice(1);
|
|
@@ -1265,12 +1282,12 @@ function colorWithAlpha(color, alpha12) {
|
|
|
1265
1282
|
const r = bigint >> 16 & 255;
|
|
1266
1283
|
const g = bigint >> 8 & 255;
|
|
1267
1284
|
const b = bigint & 255;
|
|
1268
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
1285
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha18})`;
|
|
1269
1286
|
}
|
|
1270
1287
|
if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
|
|
1271
1288
|
const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
|
|
1272
1289
|
if (result) {
|
|
1273
|
-
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${
|
|
1290
|
+
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha18})`;
|
|
1274
1291
|
}
|
|
1275
1292
|
}
|
|
1276
1293
|
return color;
|
|
@@ -1369,7 +1386,7 @@ async function runFetches() {
|
|
|
1369
1386
|
);
|
|
1370
1387
|
}
|
|
1371
1388
|
var useAutoFetcher = () => {
|
|
1372
|
-
|
|
1389
|
+
React4.useEffect(() => {
|
|
1373
1390
|
if (isEnvBrowser()) return;
|
|
1374
1391
|
runFetches().catch(() => {
|
|
1375
1392
|
});
|
|
@@ -1406,11 +1423,35 @@ function reportMissingLocale(key) {
|
|
|
1406
1423
|
fetchNui("REPORT_MISSING_LOCALE", { key }).catch(() => {
|
|
1407
1424
|
});
|
|
1408
1425
|
}
|
|
1426
|
+
var PACKAGE_DEFAULTS = {
|
|
1427
|
+
"OccupantsDesc": "Here you can view and manage the occupants of your traphouse. These occupants can be used mainly for selling drugs to the NPCs surrounding your traphouse. However they have other uses to so be careful who you add as an occupant.",
|
|
1428
|
+
"cfgpanel_discard": "Discard",
|
|
1429
|
+
"cfgpanel_manual_edit": "Manual Edit",
|
|
1430
|
+
"cfgpanel_reset_defaults": "Reset Defaults",
|
|
1431
|
+
"cfgpanel_version": "Version",
|
|
1432
|
+
"cfgpanel_back_title": "Back to script list",
|
|
1433
|
+
"cfgpanel_undo": "Undo",
|
|
1434
|
+
"cfgpanel_redo": "Redo",
|
|
1435
|
+
"cfgpanel_save": "Save",
|
|
1436
|
+
"cfgpanel_saving": "Saving...",
|
|
1437
|
+
"cfgpanel_history": "History",
|
|
1438
|
+
"cfgpanel_reset_title": "Reset to Defaults",
|
|
1439
|
+
"cfgpanel_reset_desc": "This will permanently reset ALL config back to the defaults. Every value you have configured will be overwritten. This cannot be undone.",
|
|
1440
|
+
"cfgpanel_reset_confirm": "Reset Config",
|
|
1441
|
+
"cfgpanel_discard_title": "Discard Unsaved Changes?",
|
|
1442
|
+
"cfgpanel_discard_desc_back": "You have unsaved changes. Going back now will discard them.",
|
|
1443
|
+
"cfgpanel_discard_desc_close": "You have unsaved changes. Closing now will discard them.",
|
|
1444
|
+
"cfgpanel_discard_confirm_back": "Go Back Without Saving",
|
|
1445
|
+
"cfgpanel_discard_confirm_close": "Close Without Saving",
|
|
1446
|
+
"cfgpanel_json_title": "Config JSON",
|
|
1447
|
+
"cfgpanel_cancel": "Cancel",
|
|
1448
|
+
"cfgpanel_apply": "Apply",
|
|
1449
|
+
"cfgpanel_history_title": "Config History",
|
|
1450
|
+
"cfgpanel_close": "Close"
|
|
1451
|
+
};
|
|
1409
1452
|
var localeStore = zustand.create((set, get) => {
|
|
1410
1453
|
return {
|
|
1411
|
-
locales: {
|
|
1412
|
-
"OccupantsDesc": "Here you can view and manage the occupants of your traphouse. These occupants can be used mainly for selling drugs to the NPCs surrounding your traphouse. However they have other uses to so be careful who you add as an occupant."
|
|
1413
|
-
},
|
|
1454
|
+
locales: { ...PACKAGE_DEFAULTS },
|
|
1414
1455
|
locale: (key, ...args) => {
|
|
1415
1456
|
const exists = get().locales[key];
|
|
1416
1457
|
if (!exists) reportMissingLocale(key);
|
|
@@ -1424,7 +1465,7 @@ var localeStore = zustand.create((set, get) => {
|
|
|
1424
1465
|
});
|
|
1425
1466
|
var locale = localeStore.getState().locale;
|
|
1426
1467
|
registerInitialFetch("GET_LOCALES", void 0).then((data) => {
|
|
1427
|
-
localeStore.setState({ locales: data });
|
|
1468
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...data } });
|
|
1428
1469
|
}).catch(() => {
|
|
1429
1470
|
});
|
|
1430
1471
|
if (typeof window !== "undefined") {
|
|
@@ -1432,7 +1473,8 @@ if (typeof window !== "undefined") {
|
|
|
1432
1473
|
const msg = event.data;
|
|
1433
1474
|
if (!msg || msg.action !== "UPDATE_DIRK_LIB_LOCALES") return;
|
|
1434
1475
|
if (!msg.data || typeof msg.data !== "object") return;
|
|
1435
|
-
|
|
1476
|
+
if (Object.keys(msg.data).length === 0) return;
|
|
1477
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...msg.data } });
|
|
1436
1478
|
});
|
|
1437
1479
|
}
|
|
1438
1480
|
|
|
@@ -1865,7 +1907,7 @@ function createSkill(defaultSettings) {
|
|
|
1865
1907
|
}));
|
|
1866
1908
|
const useSkill = (xp) => {
|
|
1867
1909
|
const { settings, levelMap } = useStore4();
|
|
1868
|
-
return
|
|
1910
|
+
return React4.useMemo(() => {
|
|
1869
1911
|
const currentLevel = getLevelFromXP(xp, levelMap, settings);
|
|
1870
1912
|
const nextLevel = Math.min(currentLevel + 1, settings.maxLevel);
|
|
1871
1913
|
const currentLevelXP = levelMap[currentLevel.toString()] || 0;
|
|
@@ -1958,15 +2000,21 @@ var useFrameworkGroups = zustand.create(() => ({
|
|
|
1958
2000
|
gangs: [],
|
|
1959
2001
|
loaded: false
|
|
1960
2002
|
}));
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2003
|
+
var frameworkGroupsRequested = false;
|
|
2004
|
+
function ensureFrameworkGroups() {
|
|
2005
|
+
if (frameworkGroupsRequested) return;
|
|
2006
|
+
frameworkGroupsRequested = true;
|
|
2007
|
+
fetchNui("GET_FRAMEWORK_GROUPS", void 0).then((data) => {
|
|
2008
|
+
useFrameworkGroups.setState({
|
|
2009
|
+
jobs: Array.isArray(data?.jobs) ? data.jobs : [],
|
|
2010
|
+
gangs: Array.isArray(data?.gangs) ? data.gangs : [],
|
|
2011
|
+
loaded: true
|
|
2012
|
+
});
|
|
2013
|
+
}).catch(() => {
|
|
2014
|
+
frameworkGroupsRequested = false;
|
|
2015
|
+
useFrameworkGroups.setState({ loaded: true });
|
|
1966
2016
|
});
|
|
1967
|
-
}
|
|
1968
|
-
useFrameworkGroups.setState({ loaded: true });
|
|
1969
|
-
});
|
|
2017
|
+
}
|
|
1970
2018
|
function selectAllGroups(state) {
|
|
1971
2019
|
return [...state.jobs, ...state.gangs];
|
|
1972
2020
|
}
|
|
@@ -2455,8 +2503,8 @@ var FloatingParticles = ({
|
|
|
2455
2503
|
mouseRepelStrength = 50,
|
|
2456
2504
|
backgroundColor = "transparent"
|
|
2457
2505
|
}) => {
|
|
2458
|
-
const containerRef =
|
|
2459
|
-
const [particles, setParticles] =
|
|
2506
|
+
const containerRef = React4.useRef(null);
|
|
2507
|
+
const [particles, setParticles] = React4.useState([]);
|
|
2460
2508
|
const mouseX = framerMotion.useMotionValue(0);
|
|
2461
2509
|
const mouseY = framerMotion.useMotionValue(0);
|
|
2462
2510
|
const durationMap = {
|
|
@@ -2469,7 +2517,7 @@ var FloatingParticles = ({
|
|
|
2469
2517
|
const x = Math.sin(seed) * 1e4;
|
|
2470
2518
|
return x - Math.floor(x);
|
|
2471
2519
|
};
|
|
2472
|
-
|
|
2520
|
+
React4.useEffect(() => {
|
|
2473
2521
|
if (!containerRef.current) return;
|
|
2474
2522
|
const bounds = containerRef.current.getBoundingClientRect();
|
|
2475
2523
|
const newParticles = [...Array(particleCount)].map((_, i) => {
|
|
@@ -2490,7 +2538,7 @@ var FloatingParticles = ({
|
|
|
2490
2538
|
});
|
|
2491
2539
|
setParticles(newParticles);
|
|
2492
2540
|
}, [particleCount, icons.length, duration.base, duration.variance]);
|
|
2493
|
-
|
|
2541
|
+
React4.useEffect(() => {
|
|
2494
2542
|
if (!containerRef.current) return;
|
|
2495
2543
|
const handleMouseMove = (e) => {
|
|
2496
2544
|
const bounds = containerRef.current.getBoundingClientRect();
|
|
@@ -2539,7 +2587,7 @@ var FloatingParticles = ({
|
|
|
2539
2587
|
container.removeEventListener("mouseleave", handleMouseLeave);
|
|
2540
2588
|
};
|
|
2541
2589
|
}, [mouseX, mouseY, mouseRepelDistance, mouseRepelStrength]);
|
|
2542
|
-
|
|
2590
|
+
React4.useEffect(() => {
|
|
2543
2591
|
const handleResize = () => {
|
|
2544
2592
|
if (!containerRef.current) return;
|
|
2545
2593
|
const bounds = containerRef.current.getBoundingClientRect();
|
|
@@ -2975,23 +3023,23 @@ function Segment(props) {
|
|
|
2975
3023
|
}
|
|
2976
3024
|
);
|
|
2977
3025
|
}
|
|
2978
|
-
var NavigationContext =
|
|
3026
|
+
var NavigationContext = React4.createContext(null);
|
|
2979
3027
|
function useNavigation(selector) {
|
|
2980
|
-
const navigation =
|
|
3028
|
+
const navigation = React4.useContext(NavigationContext);
|
|
2981
3029
|
if (!navigation) {
|
|
2982
3030
|
throw new Error("useNavigation must be used within a NavigationProvider");
|
|
2983
3031
|
}
|
|
2984
3032
|
return zustand.useStore(navigation, selector);
|
|
2985
3033
|
}
|
|
2986
3034
|
function useNavigationStore() {
|
|
2987
|
-
const navigation =
|
|
3035
|
+
const navigation = React4.useContext(NavigationContext);
|
|
2988
3036
|
if (!navigation) {
|
|
2989
3037
|
throw new Error("useNavigationStore must be used within a NavigationProvider");
|
|
2990
3038
|
}
|
|
2991
3039
|
return navigation;
|
|
2992
3040
|
}
|
|
2993
3041
|
function NavigationProvider({ children, defaultPage }) {
|
|
2994
|
-
const storeRef =
|
|
3042
|
+
const storeRef = React4.useRef(
|
|
2995
3043
|
zustand.create(() => ({
|
|
2996
3044
|
pageId: defaultPage || "home"
|
|
2997
3045
|
}))
|
|
@@ -3000,7 +3048,7 @@ function NavigationProvider({ children, defaultPage }) {
|
|
|
3000
3048
|
}
|
|
3001
3049
|
function NavBar(props) {
|
|
3002
3050
|
const pageId = useNavigation((state) => state.pageId);
|
|
3003
|
-
const
|
|
3051
|
+
const store2 = useNavigationStore();
|
|
3004
3052
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3005
3053
|
SegmentedControl,
|
|
3006
3054
|
{
|
|
@@ -3009,7 +3057,7 @@ function NavBar(props) {
|
|
|
3009
3057
|
value: pageId,
|
|
3010
3058
|
items: props.items,
|
|
3011
3059
|
onChange: (value) => {
|
|
3012
|
-
|
|
3060
|
+
store2.setState({ pageId: value });
|
|
3013
3061
|
}
|
|
3014
3062
|
}
|
|
3015
3063
|
);
|
|
@@ -3343,7 +3391,7 @@ function Modal({
|
|
|
3343
3391
|
children
|
|
3344
3392
|
}) {
|
|
3345
3393
|
const theme2 = core.useMantineTheme();
|
|
3346
|
-
const pointerDownOnOverlay =
|
|
3394
|
+
const pointerDownOnOverlay = React4.useRef(false);
|
|
3347
3395
|
return /* @__PURE__ */ jsxRuntime.jsx(core.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3348
3396
|
framerMotion.motion.div,
|
|
3349
3397
|
{
|
|
@@ -3524,9 +3572,9 @@ function PromptModal(props) {
|
|
|
3524
3572
|
}
|
|
3525
3573
|
);
|
|
3526
3574
|
}
|
|
3527
|
-
var ModalContext =
|
|
3575
|
+
var ModalContext = React4.createContext(null);
|
|
3528
3576
|
function useModal(selector) {
|
|
3529
|
-
const modal =
|
|
3577
|
+
const modal = React4.useContext(ModalContext);
|
|
3530
3578
|
if (!modal) {
|
|
3531
3579
|
throw new Error("useModal must be used within a ModalProvider");
|
|
3532
3580
|
}
|
|
@@ -3554,7 +3602,7 @@ function StoreModal() {
|
|
|
3554
3602
|
) });
|
|
3555
3603
|
}
|
|
3556
3604
|
function ModalProvider({ children }) {
|
|
3557
|
-
const storeRef =
|
|
3605
|
+
const storeRef = React4.useRef(
|
|
3558
3606
|
zustand.create(() => ({
|
|
3559
3607
|
active: null
|
|
3560
3608
|
}))
|
|
@@ -3565,7 +3613,7 @@ function ModalProvider({ children }) {
|
|
|
3565
3613
|
] });
|
|
3566
3614
|
}
|
|
3567
3615
|
function useModalActions() {
|
|
3568
|
-
const modal =
|
|
3616
|
+
const modal = React4.useContext(ModalContext);
|
|
3569
3617
|
if (!modal) throw new Error("useModalActions must be used within a ModalProvider");
|
|
3570
3618
|
const showModal = (openModal) => {
|
|
3571
3619
|
modal.setState({ active: openModal });
|
|
@@ -3585,7 +3633,7 @@ function ConfirmModal({
|
|
|
3585
3633
|
zIndex = 200
|
|
3586
3634
|
}) {
|
|
3587
3635
|
const theme2 = core.useMantineTheme();
|
|
3588
|
-
const [typed, setTyped] =
|
|
3636
|
+
const [typed, setTyped] = React4.useState("");
|
|
3589
3637
|
const canConfirm = !confirmText || typed === confirmText;
|
|
3590
3638
|
return /* @__PURE__ */ jsxRuntime.jsx(core.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3591
3639
|
framerMotion.motion.div,
|
|
@@ -3852,14 +3900,14 @@ function MissingItemsBanner() {
|
|
|
3852
3900
|
const loaded = useMissingItemsAudit((s) => s.loaded);
|
|
3853
3901
|
const inFlight = useMissingItemsAudit((s) => s.inFlight);
|
|
3854
3902
|
const refresh = useMissingItemsAudit((s) => s.refresh);
|
|
3855
|
-
const [expanded, setExpanded] =
|
|
3856
|
-
const [activeTab, setActiveTab] =
|
|
3857
|
-
const [hoveredTab, setHoveredTab] =
|
|
3858
|
-
const [copied, setCopied] =
|
|
3859
|
-
|
|
3903
|
+
const [expanded, setExpanded] = React4.useState(false);
|
|
3904
|
+
const [activeTab, setActiveTab] = React4.useState("ox");
|
|
3905
|
+
const [hoveredTab, setHoveredTab] = React4.useState(null);
|
|
3906
|
+
const [copied, setCopied] = React4.useState(null);
|
|
3907
|
+
React4.useEffect(() => {
|
|
3860
3908
|
if (!loaded) refresh();
|
|
3861
3909
|
}, [loaded, refresh]);
|
|
3862
|
-
const handleCopy =
|
|
3910
|
+
const handleCopy = React4.useCallback((tab) => {
|
|
3863
3911
|
if (!audit) return;
|
|
3864
3912
|
const text = audit.snippets[tab] ?? "";
|
|
3865
3913
|
navigator.clipboard.writeText(text).then(() => {
|
|
@@ -3868,7 +3916,7 @@ function MissingItemsBanner() {
|
|
|
3868
3916
|
}).catch(() => {
|
|
3869
3917
|
});
|
|
3870
3918
|
}, [audit]);
|
|
3871
|
-
const handleRefresh =
|
|
3919
|
+
const handleRefresh = React4.useCallback((e) => {
|
|
3872
3920
|
e.stopPropagation();
|
|
3873
3921
|
refresh();
|
|
3874
3922
|
}, [refresh]);
|
|
@@ -4000,7 +4048,7 @@ function CodeView({
|
|
|
4000
4048
|
warnColor
|
|
4001
4049
|
}) {
|
|
4002
4050
|
const theme2 = core.useMantineTheme();
|
|
4003
|
-
const [hovered, setHovered] =
|
|
4051
|
+
const [hovered, setHovered] = React4.useState(false);
|
|
4004
4052
|
const lines = code === "" ? [""] : code.split("\n");
|
|
4005
4053
|
const lineNumWidth = String(lines.length).length;
|
|
4006
4054
|
const copyBg = copied ? core.alpha("#22c55e", 0.15) : hovered ? core.alpha(warnColor, 0.18) : core.alpha(warnColor, 0.1);
|
|
@@ -4303,42 +4351,42 @@ function createFormStore(initialValues, validationRules, onSubmit) {
|
|
|
4303
4351
|
}
|
|
4304
4352
|
}));
|
|
4305
4353
|
}
|
|
4306
|
-
var FormContext =
|
|
4354
|
+
var FormContext = React4.createContext(null);
|
|
4307
4355
|
function FormProvider({
|
|
4308
4356
|
initialValues,
|
|
4309
4357
|
validate,
|
|
4310
4358
|
onSubmit,
|
|
4311
4359
|
children
|
|
4312
4360
|
}) {
|
|
4313
|
-
const storeRef =
|
|
4361
|
+
const storeRef = React4.useRef(
|
|
4314
4362
|
createFormStore(initialValues, validate, onSubmit)
|
|
4315
4363
|
);
|
|
4316
4364
|
return /* @__PURE__ */ jsxRuntime.jsx(FormContext.Provider, { value: storeRef.current, children });
|
|
4317
4365
|
}
|
|
4318
4366
|
function useForm() {
|
|
4319
|
-
const
|
|
4320
|
-
if (!
|
|
4367
|
+
const store2 = React4.useContext(FormContext);
|
|
4368
|
+
if (!store2) {
|
|
4321
4369
|
throw new Error("useForm must be used inside <FormProvider>");
|
|
4322
4370
|
}
|
|
4323
|
-
const state = zustand.useStore(
|
|
4324
|
-
const changedFields =
|
|
4371
|
+
const state = zustand.useStore(store2);
|
|
4372
|
+
const changedFields = React4.useMemo(() => {
|
|
4325
4373
|
return collectChangedPaths(state.values, state.initialValues);
|
|
4326
4374
|
}, [state.values, state.initialValues]);
|
|
4327
4375
|
return { ...state, changedFields, changedCount: changedFields.length };
|
|
4328
4376
|
}
|
|
4329
4377
|
function useFormField(path) {
|
|
4330
|
-
const
|
|
4331
|
-
if (!
|
|
4378
|
+
const store2 = React4.useContext(FormContext);
|
|
4379
|
+
if (!store2) {
|
|
4332
4380
|
throw new Error("useFormField must be used inside <FormProvider>");
|
|
4333
4381
|
}
|
|
4334
|
-
return zustand.useStore(
|
|
4382
|
+
return zustand.useStore(store2, (s) => getNested(s.values, path));
|
|
4335
4383
|
}
|
|
4336
4384
|
function useFormFields(...paths) {
|
|
4337
|
-
const
|
|
4338
|
-
if (!
|
|
4385
|
+
const store2 = React4.useContext(FormContext);
|
|
4386
|
+
if (!store2) {
|
|
4339
4387
|
throw new Error("useFormFields must be used inside <FormProvider>");
|
|
4340
4388
|
}
|
|
4341
|
-
return zustand.useStore(
|
|
4389
|
+
return zustand.useStore(store2, (s) => {
|
|
4342
4390
|
const result = {};
|
|
4343
4391
|
for (const path of paths) {
|
|
4344
4392
|
result[path] = getNested(s.values, path);
|
|
@@ -4347,18 +4395,18 @@ function useFormFields(...paths) {
|
|
|
4347
4395
|
});
|
|
4348
4396
|
}
|
|
4349
4397
|
function useFormError(path) {
|
|
4350
|
-
const
|
|
4351
|
-
if (!
|
|
4398
|
+
const store2 = React4.useContext(FormContext);
|
|
4399
|
+
if (!store2) {
|
|
4352
4400
|
throw new Error("useFormError must be used inside <FormProvider>");
|
|
4353
4401
|
}
|
|
4354
|
-
return zustand.useStore(
|
|
4402
|
+
return zustand.useStore(store2, (s) => s.errors[path]);
|
|
4355
4403
|
}
|
|
4356
4404
|
function useFormErrors(...paths) {
|
|
4357
|
-
const
|
|
4358
|
-
if (!
|
|
4405
|
+
const store2 = React4.useContext(FormContext);
|
|
4406
|
+
if (!store2) {
|
|
4359
4407
|
throw new Error("useFormErrors must be used inside <FormProvider>");
|
|
4360
4408
|
}
|
|
4361
|
-
return zustand.useStore(
|
|
4409
|
+
return zustand.useStore(store2, (s) => {
|
|
4362
4410
|
const result = {};
|
|
4363
4411
|
for (const path of paths) {
|
|
4364
4412
|
result[path] = s.errors[path];
|
|
@@ -4367,18 +4415,229 @@ function useFormErrors(...paths) {
|
|
|
4367
4415
|
});
|
|
4368
4416
|
}
|
|
4369
4417
|
function useFormActions() {
|
|
4370
|
-
const
|
|
4371
|
-
if (!
|
|
4418
|
+
const store2 = React4.useContext(FormContext);
|
|
4419
|
+
if (!store2) {
|
|
4372
4420
|
throw new Error("useFormActions must be used inside <FormProvider>");
|
|
4373
4421
|
}
|
|
4374
|
-
return
|
|
4422
|
+
return store2.getState();
|
|
4423
|
+
}
|
|
4424
|
+
var store = /* @__PURE__ */ new Map();
|
|
4425
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
4426
|
+
function notify(key) {
|
|
4427
|
+
const ls = listeners.get(key);
|
|
4428
|
+
if (!ls) return;
|
|
4429
|
+
ls.forEach((fn) => fn());
|
|
4430
|
+
}
|
|
4431
|
+
function useAdminState(key, initial) {
|
|
4432
|
+
const [, setTick] = React4.useState(0);
|
|
4433
|
+
React4.useEffect(() => {
|
|
4434
|
+
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
4435
|
+
listeners.set(key, set);
|
|
4436
|
+
const handler = () => setTick((t3) => t3 + 1);
|
|
4437
|
+
set.add(handler);
|
|
4438
|
+
return () => {
|
|
4439
|
+
set.delete(handler);
|
|
4440
|
+
if (set.size === 0) listeners.delete(key);
|
|
4441
|
+
};
|
|
4442
|
+
}, [key]);
|
|
4443
|
+
const value = store.has(key) ? store.get(key) : initial;
|
|
4444
|
+
const setValue = (v) => {
|
|
4445
|
+
const next = typeof v === "function" ? v(value) : v;
|
|
4446
|
+
store.set(key, next);
|
|
4447
|
+
notify(key);
|
|
4448
|
+
};
|
|
4449
|
+
return [value, setValue];
|
|
4450
|
+
}
|
|
4451
|
+
function clearAdminState(key) {
|
|
4452
|
+
if (key) {
|
|
4453
|
+
store.delete(key);
|
|
4454
|
+
notify(key);
|
|
4455
|
+
} else {
|
|
4456
|
+
const keys = Array.from(store.keys());
|
|
4457
|
+
store.clear();
|
|
4458
|
+
keys.forEach(notify);
|
|
4459
|
+
}
|
|
4375
4460
|
}
|
|
4461
|
+
var label = {
|
|
4462
|
+
fontSize: "var(--mantine-font-size-xs)",
|
|
4463
|
+
fontFamily: "Akrobat Bold",
|
|
4464
|
+
letterSpacing: "0.05em",
|
|
4465
|
+
textTransform: "uppercase"
|
|
4466
|
+
};
|
|
4467
|
+
var error = {
|
|
4468
|
+
fontSize: "var(--mantine-font-size-xs)",
|
|
4469
|
+
fontFamily: "Akrobat Regular"
|
|
4470
|
+
};
|
|
4471
|
+
var description = {
|
|
4472
|
+
fontSize: "var(--mantine-font-size-xs)"
|
|
4473
|
+
};
|
|
4474
|
+
var genericInputStyles = {
|
|
4475
|
+
styles: {
|
|
4476
|
+
label,
|
|
4477
|
+
error,
|
|
4478
|
+
description,
|
|
4479
|
+
input: {
|
|
4480
|
+
background: "rgba(255,255,255,0.04)",
|
|
4481
|
+
border: "0.1vh solid rgba(255,255,255,0.08)",
|
|
4482
|
+
color: "rgba(255,255,255,0.85)",
|
|
4483
|
+
minHeight: "4vh"
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
};
|
|
4487
|
+
var theme = core.createTheme({
|
|
4488
|
+
primaryColor: "dirk",
|
|
4489
|
+
primaryShade: 9,
|
|
4490
|
+
defaultRadius: "xs",
|
|
4491
|
+
fontFamily: "Akrobat Regular, sans-serif",
|
|
4492
|
+
radius: {
|
|
4493
|
+
xxs: "0.3vh",
|
|
4494
|
+
xs: "0.5vh",
|
|
4495
|
+
sm: "0.75vh",
|
|
4496
|
+
md: "1vh",
|
|
4497
|
+
lg: "1.5vh",
|
|
4498
|
+
xl: "2vh",
|
|
4499
|
+
xxl: "3vh"
|
|
4500
|
+
},
|
|
4501
|
+
fontSizes: {
|
|
4502
|
+
xxs: "1.2vh",
|
|
4503
|
+
xs: "1.5vh",
|
|
4504
|
+
sm: "1.8vh",
|
|
4505
|
+
md: "2.2vh",
|
|
4506
|
+
lg: "2.8vh",
|
|
4507
|
+
xl: "3.3vh",
|
|
4508
|
+
xxl: "3.8vh"
|
|
4509
|
+
},
|
|
4510
|
+
lineHeights: {
|
|
4511
|
+
xxs: "1.4vh",
|
|
4512
|
+
xs: "1.8vh",
|
|
4513
|
+
sm: "2.2vh",
|
|
4514
|
+
md: "2.8vh",
|
|
4515
|
+
lg: "3.3vh",
|
|
4516
|
+
xl: "3.8vh"
|
|
4517
|
+
},
|
|
4518
|
+
spacing: {
|
|
4519
|
+
xxs: "0.5vh",
|
|
4520
|
+
xs: "0.75vh",
|
|
4521
|
+
sm: "1.5vh",
|
|
4522
|
+
md: "2vh",
|
|
4523
|
+
lg: "3vh",
|
|
4524
|
+
xl: "4vh",
|
|
4525
|
+
xxl: "5vh"
|
|
4526
|
+
},
|
|
4527
|
+
components: {
|
|
4528
|
+
Progress: {
|
|
4529
|
+
styles: {
|
|
4530
|
+
label: {
|
|
4531
|
+
fontFamily: "Akrobat Bold",
|
|
4532
|
+
letterSpacing: "0.05em",
|
|
4533
|
+
textTransform: "uppercase"
|
|
4534
|
+
},
|
|
4535
|
+
root: {
|
|
4536
|
+
backgroundColor: "rgba(77, 77, 77, 0.4)"
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
},
|
|
4540
|
+
Input: genericInputStyles,
|
|
4541
|
+
TextInput: genericInputStyles,
|
|
4542
|
+
NumberInput: genericInputStyles,
|
|
4543
|
+
Select: genericInputStyles,
|
|
4544
|
+
MultiSelect: genericInputStyles,
|
|
4545
|
+
Textarea: genericInputStyles,
|
|
4546
|
+
ColorInput: genericInputStyles,
|
|
4547
|
+
DateInput: genericInputStyles,
|
|
4548
|
+
// Mantine's <Button> defaults to rem-based heights (xs ≈ 1.875rem)
|
|
4549
|
+
// which doesn't match this theme's vh-based input min-heights, so
|
|
4550
|
+
// `<Button size="xs">` rendered next to `<TextInput size="xs">` ends
|
|
4551
|
+
// up visibly shorter. Pin the button heights to the same vh values
|
|
4552
|
+
// the inputs use so xs-everything lines up out of the box.
|
|
4553
|
+
Button: {
|
|
4554
|
+
styles: {
|
|
4555
|
+
label: {
|
|
4556
|
+
fontFamily: "Akrobat Bold",
|
|
4557
|
+
letterSpacing: "0.05em",
|
|
4558
|
+
textTransform: "uppercase"
|
|
4559
|
+
},
|
|
4560
|
+
root: {
|
|
4561
|
+
// Mantine maps these to --button-height per size; setting them
|
|
4562
|
+
// directly here keeps native Button sizing logic intact.
|
|
4563
|
+
}
|
|
4564
|
+
},
|
|
4565
|
+
vars: (_theme, props) => {
|
|
4566
|
+
const heights = {
|
|
4567
|
+
xs: "4vh",
|
|
4568
|
+
sm: "4.5vh",
|
|
4569
|
+
md: "5vh",
|
|
4570
|
+
lg: "5.5vh",
|
|
4571
|
+
xl: "6vh"
|
|
4572
|
+
};
|
|
4573
|
+
const h = heights[props.size ?? "sm"] ?? "4.5vh";
|
|
4574
|
+
return {
|
|
4575
|
+
root: {
|
|
4576
|
+
"--button-height": h
|
|
4577
|
+
}
|
|
4578
|
+
};
|
|
4579
|
+
}
|
|
4580
|
+
},
|
|
4581
|
+
Pill: {
|
|
4582
|
+
styles: (theme2) => ({
|
|
4583
|
+
root: {
|
|
4584
|
+
display: "inline-flex",
|
|
4585
|
+
alignItems: "center",
|
|
4586
|
+
justifyContent: "space-between",
|
|
4587
|
+
backgroundColor: "rgba(76, 76, 76, 0.3)",
|
|
4588
|
+
height: "fit-content",
|
|
4589
|
+
textTransform: "uppercase",
|
|
4590
|
+
letterSpacing: "0.05em",
|
|
4591
|
+
fontFamily: "Akrobat Bold",
|
|
4592
|
+
fontSize: "1.25vh",
|
|
4593
|
+
borderRadius: theme2.defaultRadius,
|
|
4594
|
+
paddingBottom: "0.5vh",
|
|
4595
|
+
paddingTop: "0.5vh"
|
|
4596
|
+
}
|
|
4597
|
+
})
|
|
4598
|
+
},
|
|
4599
|
+
// Mantine's <Tooltip> defaults to a white card with black text — looks
|
|
4600
|
+
// jarring against every dirk consumer's dark configurator. Every script
|
|
4601
|
+
// used to hand-paste this dark style block per Tooltip; centralised here
|
|
4602
|
+
// so consumers get the right look automatically and never need to think
|
|
4603
|
+
// about it again.
|
|
4604
|
+
Tooltip: {
|
|
4605
|
+
styles: (theme2) => ({
|
|
4606
|
+
tooltip: {
|
|
4607
|
+
background: core.alpha(theme2.colors.dark[7], 0.95),
|
|
4608
|
+
border: "0.1vh solid rgba(255,255,255,0.1)",
|
|
4609
|
+
color: "rgba(255,255,255,0.75)",
|
|
4610
|
+
fontFamily: "Akrobat Bold",
|
|
4611
|
+
fontSize: "1.3vh",
|
|
4612
|
+
lineHeight: 1.3,
|
|
4613
|
+
padding: "0.6vh 0.8vh",
|
|
4614
|
+
letterSpacing: "0.03em"
|
|
4615
|
+
}
|
|
4616
|
+
})
|
|
4617
|
+
}
|
|
4618
|
+
},
|
|
4619
|
+
colors: {
|
|
4620
|
+
dirk: [
|
|
4621
|
+
"#ffffff",
|
|
4622
|
+
"#f3fce9",
|
|
4623
|
+
"#dbf5bd",
|
|
4624
|
+
"#c3ee91",
|
|
4625
|
+
"#ace765",
|
|
4626
|
+
"#94e039",
|
|
4627
|
+
"#7ac61f",
|
|
4628
|
+
"#5f9a18",
|
|
4629
|
+
"#29420a",
|
|
4630
|
+
"#446e11"
|
|
4631
|
+
]
|
|
4632
|
+
}
|
|
4633
|
+
});
|
|
4634
|
+
var theme_default = theme;
|
|
4376
4635
|
var useNuiEvent = (action, handler) => {
|
|
4377
|
-
const savedHandler =
|
|
4378
|
-
|
|
4636
|
+
const savedHandler = React4.useRef(noop);
|
|
4637
|
+
React4.useEffect(() => {
|
|
4379
4638
|
savedHandler.current = handler;
|
|
4380
4639
|
}, [handler]);
|
|
4381
|
-
|
|
4640
|
+
React4.useEffect(() => {
|
|
4382
4641
|
const eventListener = (event) => {
|
|
4383
4642
|
const { action: eventAction, data } = event.data;
|
|
4384
4643
|
if (savedHandler.current) {
|
|
@@ -4391,13 +4650,35 @@ var useNuiEvent = (action, handler) => {
|
|
|
4391
4650
|
return () => window.removeEventListener("message", eventListener);
|
|
4392
4651
|
}, [action]);
|
|
4393
4652
|
};
|
|
4653
|
+
|
|
4654
|
+
// src/utils/mergeMantineTheme.ts
|
|
4655
|
+
var isValidColorScale = (v) => Array.isArray(v) && v.length === 10 && v.every((shade) => typeof shade === "string");
|
|
4656
|
+
function mergeMantineThemeSafe(base, custom, override) {
|
|
4657
|
+
const colors = { ...base.colors };
|
|
4658
|
+
if (custom && isValidColorScale(custom)) {
|
|
4659
|
+
colors["custom"] = custom;
|
|
4660
|
+
} else if (!colors["custom"]) {
|
|
4661
|
+
const fallback = base.colors && base.colors.dirk;
|
|
4662
|
+
if (fallback && isValidColorScale(fallback)) {
|
|
4663
|
+
colors["custom"] = fallback;
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
return {
|
|
4667
|
+
...base,
|
|
4668
|
+
...override,
|
|
4669
|
+
colors: {
|
|
4670
|
+
...colors,
|
|
4671
|
+
...override?.colors ?? {}
|
|
4672
|
+
}
|
|
4673
|
+
};
|
|
4674
|
+
}
|
|
4394
4675
|
var _instance = null;
|
|
4395
4676
|
function getScriptConfigInstance() {
|
|
4396
4677
|
if (!_instance) throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
|
|
4397
4678
|
return _instance;
|
|
4398
4679
|
}
|
|
4399
4680
|
function createScriptConfig(defaultValue) {
|
|
4400
|
-
const
|
|
4681
|
+
const store2 = zustand.create(() => defaultValue);
|
|
4401
4682
|
let clientVersion = 0;
|
|
4402
4683
|
const useScriptConfigHooks = () => {
|
|
4403
4684
|
useNuiEvent("UPDATE_SCRIPT_CONFIG", (data) => {
|
|
@@ -4406,7 +4687,7 @@ function createScriptConfig(defaultValue) {
|
|
|
4406
4687
|
clientVersion = data.clientVersion;
|
|
4407
4688
|
}
|
|
4408
4689
|
if (data.config && typeof data.config === "object") {
|
|
4409
|
-
|
|
4690
|
+
store2.setState((prev) => ({ ...prev, ...data.config }));
|
|
4410
4691
|
}
|
|
4411
4692
|
});
|
|
4412
4693
|
};
|
|
@@ -4414,7 +4695,7 @@ function createScriptConfig(defaultValue) {
|
|
|
4414
4695
|
try {
|
|
4415
4696
|
const response = await fetchNui("GET_FULL_SCRIPT_CONFIG");
|
|
4416
4697
|
if (response?.success && response.data?.config) {
|
|
4417
|
-
|
|
4698
|
+
store2.setState(() => response.data.config);
|
|
4418
4699
|
if (typeof response.data.clientVersion === "number") {
|
|
4419
4700
|
clientVersion = response.data.clientVersion;
|
|
4420
4701
|
}
|
|
@@ -4425,7 +4706,7 @@ function createScriptConfig(defaultValue) {
|
|
|
4425
4706
|
return null;
|
|
4426
4707
|
};
|
|
4427
4708
|
const updateScriptConfig = async (newConfig) => {
|
|
4428
|
-
|
|
4709
|
+
store2.setState((prev) => ({ ...prev, ...newConfig }));
|
|
4429
4710
|
const response = await fetchNui("UPDATE_SCRIPT_CONFIG", {
|
|
4430
4711
|
data: newConfig,
|
|
4431
4712
|
expectedVersion: clientVersion
|
|
@@ -4434,7 +4715,7 @@ function createScriptConfig(defaultValue) {
|
|
|
4434
4715
|
clientVersion = response.meta.client_version;
|
|
4435
4716
|
}
|
|
4436
4717
|
if (response?.success === false && response?.meta?.latestData) {
|
|
4437
|
-
|
|
4718
|
+
store2.setState((prev) => ({ ...prev, ...response.meta.latestData }));
|
|
4438
4719
|
}
|
|
4439
4720
|
return response;
|
|
4440
4721
|
};
|
|
@@ -4446,28 +4727,251 @@ function createScriptConfig(defaultValue) {
|
|
|
4446
4727
|
if (response?.success) {
|
|
4447
4728
|
const fresh = await fetchScriptConfig();
|
|
4448
4729
|
if (fresh) {
|
|
4449
|
-
|
|
4730
|
+
store2.setState(() => fresh);
|
|
4450
4731
|
}
|
|
4451
4732
|
}
|
|
4452
4733
|
return response;
|
|
4453
4734
|
};
|
|
4454
4735
|
_instance = {
|
|
4455
|
-
store,
|
|
4736
|
+
store: store2,
|
|
4456
4737
|
updateConfig: updateScriptConfig,
|
|
4457
4738
|
resetConfig,
|
|
4458
4739
|
getHistory: getScriptConfigHistory,
|
|
4459
4740
|
fetchConfig: fetchScriptConfig
|
|
4460
4741
|
};
|
|
4461
|
-
return { store, updateScriptConfig, resetConfig, getScriptConfigHistory, useScriptConfigHooks, fetchScriptConfig };
|
|
4742
|
+
return { store: store2, updateScriptConfig, resetConfig, getScriptConfigHistory, useScriptConfigHooks, fetchScriptConfig };
|
|
4743
|
+
}
|
|
4744
|
+
var DirkErrorBoundary = class extends React4__default.default.Component {
|
|
4745
|
+
constructor() {
|
|
4746
|
+
super(...arguments);
|
|
4747
|
+
__publicField(this, "state", { error: null, stack: void 0 });
|
|
4748
|
+
}
|
|
4749
|
+
static getDerivedStateFromError(error2) {
|
|
4750
|
+
return { error: error2 };
|
|
4751
|
+
}
|
|
4752
|
+
componentDidCatch(error2, info) {
|
|
4753
|
+
console.group("\u{1F525} Dirk UI Crash");
|
|
4754
|
+
console.error("Error:", error2);
|
|
4755
|
+
console.error("Component Stack:", info.componentStack);
|
|
4756
|
+
console.groupEnd();
|
|
4757
|
+
}
|
|
4758
|
+
render() {
|
|
4759
|
+
if (!this.state.error) return this.props.children;
|
|
4760
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4761
|
+
core.Box,
|
|
4762
|
+
{
|
|
4763
|
+
style: {
|
|
4764
|
+
position: "fixed",
|
|
4765
|
+
inset: 0,
|
|
4766
|
+
width: "100vw",
|
|
4767
|
+
height: "100vh",
|
|
4768
|
+
background: "rgba(10, 10, 12, 0.92)",
|
|
4769
|
+
display: "flex",
|
|
4770
|
+
alignItems: "center",
|
|
4771
|
+
justifyContent: "center",
|
|
4772
|
+
padding: "2rem",
|
|
4773
|
+
zIndex: 999999
|
|
4774
|
+
},
|
|
4775
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4776
|
+
core.Box,
|
|
4777
|
+
{
|
|
4778
|
+
maw: 900,
|
|
4779
|
+
w: "100%",
|
|
4780
|
+
p: "lg",
|
|
4781
|
+
style: {
|
|
4782
|
+
background: "rgba(20,20,24,0.75)",
|
|
4783
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
4784
|
+
borderRadius: "10px",
|
|
4785
|
+
boxShadow: "0 10px 40px rgba(0,0,0,0.6)"
|
|
4786
|
+
},
|
|
4787
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(core.Stack, { gap: "sm", children: [
|
|
4788
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Title, { order: 2, c: "red.5", children: "Dirk UI Crash" }),
|
|
4789
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { c: "dimmed", size: "sm", children: "The interface encountered a fatal error and stopped rendering." }),
|
|
4790
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Code, { block: true, style: { maxHeight: 150, overflow: "auto" }, children: this.state.error?.message }),
|
|
4791
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", c: "dimmed", children: "Check console for full stack trace" })
|
|
4792
|
+
] })
|
|
4793
|
+
}
|
|
4794
|
+
)
|
|
4795
|
+
}
|
|
4796
|
+
);
|
|
4797
|
+
}
|
|
4798
|
+
};
|
|
4799
|
+
var useAdminToolStore = zustand.create((set, get) => ({
|
|
4800
|
+
active: null,
|
|
4801
|
+
begin: (spec) => new Promise((resolve) => {
|
|
4802
|
+
const prev = get().active;
|
|
4803
|
+
if (prev) prev.resolve(null);
|
|
4804
|
+
set({ active: { ...spec, resolve } });
|
|
4805
|
+
}),
|
|
4806
|
+
resolveActive: (value) => {
|
|
4807
|
+
const cur = get().active;
|
|
4808
|
+
if (!cur) return;
|
|
4809
|
+
cur.resolve(value);
|
|
4810
|
+
set({ active: null });
|
|
4811
|
+
},
|
|
4812
|
+
cancelActive: () => {
|
|
4813
|
+
const cur = get().active;
|
|
4814
|
+
if (!cur) return;
|
|
4815
|
+
cur.resolve(null);
|
|
4816
|
+
set({ active: null });
|
|
4817
|
+
}
|
|
4818
|
+
}));
|
|
4819
|
+
|
|
4820
|
+
// src/components/AdminTools/AdminOverlays.tsx
|
|
4821
|
+
var listenerInstalled = false;
|
|
4822
|
+
function installNuiListener() {
|
|
4823
|
+
if (listenerInstalled || typeof window === "undefined") return;
|
|
4824
|
+
listenerInstalled = true;
|
|
4825
|
+
window.addEventListener("message", (e) => {
|
|
4826
|
+
const msg = e?.data;
|
|
4827
|
+
if (!msg || typeof msg !== "object" || typeof msg.action !== "string") return;
|
|
4828
|
+
const action = msg.action;
|
|
4829
|
+
const cur = useAdminToolStore.getState().active;
|
|
4830
|
+
if (!cur) return;
|
|
4831
|
+
if (action === `${cur.id}_RESULT`) {
|
|
4832
|
+
useAdminToolStore.getState().resolveActive(msg.data ?? null);
|
|
4833
|
+
} else if (action === `${cur.id}_CANCELLED`) {
|
|
4834
|
+
useAdminToolStore.getState().cancelActive();
|
|
4835
|
+
}
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
var BODY_HIDE_STYLE_ID = "dirk-instruction-panel-style";
|
|
4839
|
+
var BODY_HIDE_ATTR = "data-dirk-instruction-active";
|
|
4840
|
+
var OVERLAY_ATTR = "data-dirk-instruction-overlay";
|
|
4841
|
+
function ensureBodyHideStyle() {
|
|
4842
|
+
if (typeof document === "undefined") return;
|
|
4843
|
+
if (document.getElementById(BODY_HIDE_STYLE_ID)) return;
|
|
4844
|
+
const el = document.createElement("style");
|
|
4845
|
+
el.id = BODY_HIDE_STYLE_ID;
|
|
4846
|
+
el.textContent = `
|
|
4847
|
+
body[${BODY_HIDE_ATTR}] > *:not([${OVERLAY_ATTR}]) {
|
|
4848
|
+
visibility: hidden !important;
|
|
4849
|
+
opacity: 0 !important;
|
|
4850
|
+
pointer-events: none !important;
|
|
4851
|
+
}
|
|
4852
|
+
`;
|
|
4853
|
+
document.head.appendChild(el);
|
|
4854
|
+
}
|
|
4855
|
+
function AdminOverlays() {
|
|
4856
|
+
const active = useAdminToolStore((s) => s.active);
|
|
4857
|
+
React4.useEffect(() => {
|
|
4858
|
+
installNuiListener();
|
|
4859
|
+
}, []);
|
|
4860
|
+
React4.useEffect(() => {
|
|
4861
|
+
if (!active || typeof document === "undefined") return;
|
|
4862
|
+
ensureBodyHideStyle();
|
|
4863
|
+
document.body.setAttribute(BODY_HIDE_ATTR, "");
|
|
4864
|
+
return () => {
|
|
4865
|
+
document.body.removeAttribute(BODY_HIDE_ATTR);
|
|
4866
|
+
};
|
|
4867
|
+
}, [active]);
|
|
4868
|
+
return null;
|
|
4462
4869
|
}
|
|
4463
|
-
|
|
4870
|
+
fontawesomeSvgCore.library.add(freeSolidSvgIcons.fas, freeRegularSvgIcons.far, freeBrandsSvgIcons.fab);
|
|
4871
|
+
var dirkQueryClient = new reactQuery.QueryClient({
|
|
4464
4872
|
defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
|
|
4465
4873
|
});
|
|
4466
|
-
function
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4874
|
+
function DirkProvider({ children, overideResourceName, themeOverride }) {
|
|
4875
|
+
const {
|
|
4876
|
+
primaryColor,
|
|
4877
|
+
primaryShade,
|
|
4878
|
+
customTheme,
|
|
4879
|
+
game
|
|
4880
|
+
} = useSettings();
|
|
4881
|
+
localeStore((s) => s.locales);
|
|
4882
|
+
const [scTheme, setScTheme] = React4.useState(null);
|
|
4883
|
+
React4.useLayoutEffect(() => {
|
|
4884
|
+
useSettings.setState({
|
|
4885
|
+
overideResourceName
|
|
4886
|
+
});
|
|
4887
|
+
}, [overideResourceName]);
|
|
4888
|
+
React4.useEffect(() => {
|
|
4889
|
+
fetchNui("NUI_READY").catch(() => {
|
|
4890
|
+
});
|
|
4891
|
+
Promise.all([
|
|
4892
|
+
fetchNui("GET_SETTINGS"),
|
|
4893
|
+
fetchNui("GET_RESOURCE_VERSION", void 0, { version: "dev" })
|
|
4894
|
+
]).then(([data, resourceInfo]) => {
|
|
4895
|
+
useSettings.setState({
|
|
4896
|
+
...data,
|
|
4897
|
+
resourceVersion: resourceInfo?.version || "dev"
|
|
4898
|
+
});
|
|
4899
|
+
}).catch((err) => {
|
|
4900
|
+
console.error("Failed to fetch initial settings within dirk-cfx-react:", err);
|
|
4901
|
+
});
|
|
4902
|
+
}, []);
|
|
4903
|
+
useNuiEvent("UPDATE_DIRK_LIB_SETTINGS", (data) => {
|
|
4904
|
+
if (!data || typeof data !== "object") return;
|
|
4905
|
+
useSettings.setState(data);
|
|
4906
|
+
});
|
|
4907
|
+
useNuiEvent(
|
|
4908
|
+
"UPDATE_SCRIPT_CONFIG",
|
|
4909
|
+
(data) => {
|
|
4910
|
+
if (!data || !data.config || typeof data.config !== "object") return;
|
|
4911
|
+
try {
|
|
4912
|
+
const inst = getScriptConfigInstance();
|
|
4913
|
+
inst.store.setState((prev) => ({ ...prev, ...data.config }));
|
|
4914
|
+
} catch {
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
);
|
|
4918
|
+
React4.useEffect(() => {
|
|
4919
|
+
let unsubscribe;
|
|
4920
|
+
try {
|
|
4921
|
+
const inst = getScriptConfigInstance();
|
|
4922
|
+
setScTheme(inst.store.getState()?.theme ?? null);
|
|
4923
|
+
const subscribable = inst.store;
|
|
4924
|
+
if (typeof subscribable.subscribe === "function") {
|
|
4925
|
+
unsubscribe = subscribable.subscribe((s) => {
|
|
4926
|
+
setScTheme(s?.theme ?? null);
|
|
4927
|
+
});
|
|
4928
|
+
}
|
|
4929
|
+
inst.fetchConfig?.().then((full) => {
|
|
4930
|
+
if (full && typeof full === "object") {
|
|
4931
|
+
setScTheme(full.theme ?? null);
|
|
4932
|
+
}
|
|
4933
|
+
}).catch(() => {
|
|
4934
|
+
});
|
|
4935
|
+
} catch {
|
|
4936
|
+
}
|
|
4937
|
+
return () => {
|
|
4938
|
+
unsubscribe?.();
|
|
4939
|
+
};
|
|
4940
|
+
}, []);
|
|
4941
|
+
const overrideActive = scTheme?.useOverride === true;
|
|
4942
|
+
const effectivePrimaryColor = overrideActive ? scTheme.primaryColor ?? primaryColor : primaryColor;
|
|
4943
|
+
const effectivePrimaryShade = overrideActive ? scTheme.primaryShade ?? primaryShade : primaryShade;
|
|
4944
|
+
const effectiveCustomTheme = overrideActive ? scTheme.customTheme ?? customTheme : customTheme;
|
|
4945
|
+
const mergedTheme = React4.useMemo(
|
|
4946
|
+
() => mergeMantineThemeSafe(
|
|
4947
|
+
{ ...theme_default, primaryColor: effectivePrimaryColor, primaryShade: effectivePrimaryShade },
|
|
4948
|
+
effectiveCustomTheme,
|
|
4949
|
+
themeOverride
|
|
4950
|
+
),
|
|
4951
|
+
[effectivePrimaryColor, effectivePrimaryShade, effectiveCustomTheme, themeOverride]
|
|
4952
|
+
);
|
|
4953
|
+
React4.useEffect(() => {
|
|
4954
|
+
document.body.style.fontFamily = game === "rdr3" ? '"Red Dead", sans-serif' : '"Akrobat Regular", sans-serif';
|
|
4955
|
+
}, [game]);
|
|
4956
|
+
const content = isEnvBrowser() ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4957
|
+
core.BackgroundImage,
|
|
4958
|
+
{
|
|
4959
|
+
w: "100vw",
|
|
4960
|
+
h: "100vh",
|
|
4961
|
+
src: game === "fivem" ? "https://i.ytimg.com/vi/TOxuNbXrO28/maxresdefault.jpg" : "https://raw.githubusercontent.com/Jump-On-Studios/RedM-jo_libs/refs/heads/main/source-repositories/Menu/public/assets/images/background_dev.jpg",
|
|
4962
|
+
children
|
|
4963
|
+
}
|
|
4964
|
+
) : children;
|
|
4965
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: dirkQueryClient, children: /* @__PURE__ */ jsxRuntime.jsx(core.MantineProvider, { theme: mergedTheme, defaultColorScheme: "dark", children: /* @__PURE__ */ jsxRuntime.jsxs(DirkErrorBoundary, { children: [
|
|
4966
|
+
content,
|
|
4967
|
+
/* @__PURE__ */ jsxRuntime.jsx(AdminOverlays, {})
|
|
4968
|
+
] }) }) });
|
|
4969
|
+
}
|
|
4970
|
+
function NavItemButton({
|
|
4971
|
+
icon: Icon,
|
|
4972
|
+
label: label2,
|
|
4973
|
+
active,
|
|
4974
|
+
onClick
|
|
4471
4975
|
}) {
|
|
4472
4976
|
const theme2 = core.useMantineTheme();
|
|
4473
4977
|
const color = theme2.colors[theme2.primaryColor][5];
|
|
@@ -4511,8 +5015,8 @@ function ConfigJsonModal({
|
|
|
4511
5015
|
const theme2 = core.useMantineTheme();
|
|
4512
5016
|
const color = theme2.colors[theme2.primaryColor][5];
|
|
4513
5017
|
const form = useForm();
|
|
4514
|
-
const [json, setJson] =
|
|
4515
|
-
const [error2, setError] =
|
|
5018
|
+
const [json, setJson] = React4.useState(() => JSON.stringify(form.values, null, 2));
|
|
5019
|
+
const [error2, setError] = React4.useState(null);
|
|
4516
5020
|
const handleSave = () => {
|
|
4517
5021
|
try {
|
|
4518
5022
|
const parsed = JSON.parse(json);
|
|
@@ -4541,7 +5045,7 @@ function ConfigJsonModal({
|
|
|
4541
5045
|
setError(e.message);
|
|
4542
5046
|
}
|
|
4543
5047
|
};
|
|
4544
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "
|
|
5048
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: locale("cfgpanel_json_title"), icon: lucideReact.Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
|
|
4545
5049
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
|
|
4546
5050
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4547
5051
|
core.JsonInput,
|
|
@@ -4569,7 +5073,7 @@ function ConfigJsonModal({
|
|
|
4569
5073
|
style: { background: "transparent", border: `0.1vh solid ${theme2.colors.dark[6]}`, borderRadius: theme2.radius.xs, padding: `${theme2.spacing.xxs} ${theme2.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme2.spacing.xxs },
|
|
4570
5074
|
children: [
|
|
4571
5075
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { color: "rgba(255,255,255,0.4)" }),
|
|
4572
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
5076
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: locale("cfgpanel_cancel") })
|
|
4573
5077
|
]
|
|
4574
5078
|
}
|
|
4575
5079
|
),
|
|
@@ -4582,7 +5086,7 @@ function ConfigJsonModal({
|
|
|
4582
5086
|
style: { background: core.alpha(color, 0.14), border: `0.1vh solid ${core.alpha(color, 0.4)}`, borderRadius: theme2.radius.xs, padding: `${theme2.spacing.xxs} ${theme2.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme2.spacing.xxs },
|
|
4583
5087
|
children: [
|
|
4584
5088
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { color }),
|
|
4585
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: "
|
|
5089
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: locale("cfgpanel_apply") })
|
|
4586
5090
|
]
|
|
4587
5091
|
}
|
|
4588
5092
|
)
|
|
@@ -4689,14 +5193,14 @@ function ConfigHistoryModal({
|
|
|
4689
5193
|
const { getHistory } = getScriptConfigInstance();
|
|
4690
5194
|
const theme2 = core.useMantineTheme();
|
|
4691
5195
|
const color = theme2.colors[theme2.primaryColor][5];
|
|
4692
|
-
const [queryInput, setQueryInput] =
|
|
4693
|
-
const [pathInput, setPathInput] =
|
|
4694
|
-
const [adminInput, setAdminInput] =
|
|
4695
|
-
const [query, setQuery] =
|
|
4696
|
-
const [path, setPath] =
|
|
4697
|
-
const [admin, setAdmin] =
|
|
4698
|
-
const [expandedKey, setExpandedKey] =
|
|
4699
|
-
const filters =
|
|
5196
|
+
const [queryInput, setQueryInput] = React4.useState("");
|
|
5197
|
+
const [pathInput, setPathInput] = React4.useState("");
|
|
5198
|
+
const [adminInput, setAdminInput] = React4.useState("");
|
|
5199
|
+
const [query, setQuery] = React4.useState("");
|
|
5200
|
+
const [path, setPath] = React4.useState("");
|
|
5201
|
+
const [admin, setAdmin] = React4.useState("");
|
|
5202
|
+
const [expandedKey, setExpandedKey] = React4.useState(null);
|
|
5203
|
+
const filters = React4.useMemo(() => ({ query, path, admin }), [query, path, admin]);
|
|
4700
5204
|
const historyQuery = reactQuery.useInfiniteQuery({
|
|
4701
5205
|
queryKey: ["scriptConfigHistory", filters],
|
|
4702
5206
|
initialPageParam: 0,
|
|
@@ -4723,7 +5227,7 @@ function ConfigHistoryModal({
|
|
|
4723
5227
|
historyQuery.fetchNextPage();
|
|
4724
5228
|
}
|
|
4725
5229
|
};
|
|
4726
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "
|
|
5230
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: locale("cfgpanel_history_title"), icon: lucideReact.History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
|
|
4727
5231
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
|
|
4728
5232
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${core.alpha(theme2.colors.dark[7], 0.8)}` }, children: [
|
|
4729
5233
|
/* @__PURE__ */ jsxRuntime.jsx(core.TextInput, { leftSection: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: "1.4vh" }), placeholder: "Search path/admin/value", value: queryInput, onChange: (e) => setQueryInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
|
|
@@ -4766,7 +5270,7 @@ function ConfigHistoryModal({
|
|
|
4766
5270
|
style: { background: "transparent", border: `0.1vh solid ${theme2.colors.dark[6]}`, borderRadius: theme2.radius.xs, padding: `${theme2.spacing.xxs} ${theme2.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme2.spacing.xxs },
|
|
4767
5271
|
children: [
|
|
4768
5272
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { color: "rgba(255,255,255,0.4)", size: "1.5vh" }),
|
|
4769
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
5273
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: locale("cfgpanel_close") })
|
|
4770
5274
|
]
|
|
4771
5275
|
}
|
|
4772
5276
|
) })
|
|
@@ -4791,12 +5295,12 @@ function ConfigPanelInner({
|
|
|
4791
5295
|
const theme2 = core.useMantineTheme();
|
|
4792
5296
|
const color = theme2.colors[theme2.primaryColor][5];
|
|
4793
5297
|
const version = useSettings((s) => s.resourceVersion);
|
|
4794
|
-
const [activeTab, setActiveTab] =
|
|
4795
|
-
const firstMountRef =
|
|
4796
|
-
const [jsonOpen, setJsonOpen] =
|
|
4797
|
-
const [historyOpen, setHistoryOpen] =
|
|
4798
|
-
const [resetOpen, setResetOpen] =
|
|
4799
|
-
const [pendingAction, setPendingAction] =
|
|
5298
|
+
const [activeTab, setActiveTab] = useAdminState("__dirkConfigPanel:activeTab", navItems[0]?.id ?? "");
|
|
5299
|
+
const firstMountRef = React4.useRef(true);
|
|
5300
|
+
const [jsonOpen, setJsonOpen] = React4.useState(false);
|
|
5301
|
+
const [historyOpen, setHistoryOpen] = React4.useState(false);
|
|
5302
|
+
const [resetOpen, setResetOpen] = React4.useState(false);
|
|
5303
|
+
const [pendingAction, setPendingAction] = React4.useState(null);
|
|
4800
5304
|
const changedCount = form.changedCount ?? 0;
|
|
4801
5305
|
const isDirty = changedCount > 0;
|
|
4802
5306
|
const goBack = () => fetchNui("CONFIG_PANEL_BACK");
|
|
@@ -4807,7 +5311,7 @@ function ConfigPanelInner({
|
|
|
4807
5311
|
}
|
|
4808
5312
|
goBack();
|
|
4809
5313
|
};
|
|
4810
|
-
|
|
5314
|
+
React4.useEffect(() => {
|
|
4811
5315
|
function handleKeyDown(e) {
|
|
4812
5316
|
if (e.key !== "Escape") return;
|
|
4813
5317
|
if (isDirty) {
|
|
@@ -4826,16 +5330,16 @@ function ConfigPanelInner({
|
|
|
4826
5330
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4827
5331
|
ConfirmModal,
|
|
4828
5332
|
{
|
|
4829
|
-
title: "
|
|
4830
|
-
description: "
|
|
4831
|
-
confirmLabel: "
|
|
5333
|
+
title: locale("cfgpanel_reset_title"),
|
|
5334
|
+
description: locale("cfgpanel_reset_desc"),
|
|
5335
|
+
confirmLabel: locale("cfgpanel_reset_confirm"),
|
|
4832
5336
|
confirmText: resetConfirmText,
|
|
4833
5337
|
onConfirm: async () => {
|
|
4834
5338
|
setResetOpen(false);
|
|
4835
5339
|
const result = await resetConfig();
|
|
4836
5340
|
if (result?.success) {
|
|
4837
|
-
const { store } = getScriptConfigInstance();
|
|
4838
|
-
form.reinitialize(cloneConfig(
|
|
5341
|
+
const { store: store2 } = getScriptConfigInstance();
|
|
5342
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
4839
5343
|
notifications.notifications.show({
|
|
4840
5344
|
color: "green",
|
|
4841
5345
|
title: locale("ConfigResetSuccessTitle"),
|
|
@@ -4860,9 +5364,9 @@ function ConfigPanelInner({
|
|
|
4860
5364
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: pendingAction !== null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4861
5365
|
ConfirmModal,
|
|
4862
5366
|
{
|
|
4863
|
-
title: "
|
|
4864
|
-
description: pendingAction === "back" ? "
|
|
4865
|
-
confirmLabel: pendingAction === "back" ? "
|
|
5367
|
+
title: locale("cfgpanel_discard_title"),
|
|
5368
|
+
description: pendingAction === "back" ? locale("cfgpanel_discard_desc_back") : locale("cfgpanel_discard_desc_close"),
|
|
5369
|
+
confirmLabel: pendingAction === "back" ? locale("cfgpanel_discard_confirm_back") : locale("cfgpanel_discard_confirm_close"),
|
|
4866
5370
|
onConfirm: () => {
|
|
4867
5371
|
const action = pendingAction;
|
|
4868
5372
|
setPendingAction(null);
|
|
@@ -4900,7 +5404,7 @@ function ConfigPanelInner({
|
|
|
4900
5404
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4901
5405
|
framerMotion.motion.button,
|
|
4902
5406
|
{
|
|
4903
|
-
title: "
|
|
5407
|
+
title: locale("cfgpanel_back_title"),
|
|
4904
5408
|
onClick: handleBack,
|
|
4905
5409
|
whileHover: { background: core.alpha(color, 0.16), borderColor: core.alpha(color, 0.45) },
|
|
4906
5410
|
whileTap: { scale: 0.95 },
|
|
@@ -4928,7 +5432,7 @@ function ConfigPanelInner({
|
|
|
4928
5432
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4929
5433
|
framerMotion.motion.button,
|
|
4930
5434
|
{
|
|
4931
|
-
title: "
|
|
5435
|
+
title: locale("cfgpanel_undo"),
|
|
4932
5436
|
onClick: () => form.canBack && form.back(),
|
|
4933
5437
|
disabled: !form.canBack,
|
|
4934
5438
|
whileHover: form.canBack ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4940,7 +5444,7 @@ function ConfigPanelInner({
|
|
|
4940
5444
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4941
5445
|
framerMotion.motion.button,
|
|
4942
5446
|
{
|
|
4943
|
-
title: "
|
|
5447
|
+
title: locale("cfgpanel_redo"),
|
|
4944
5448
|
onClick: () => form.canForward && form.forward(),
|
|
4945
5449
|
disabled: !form.canForward,
|
|
4946
5450
|
whileHover: form.canForward ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4952,7 +5456,7 @@ function ConfigPanelInner({
|
|
|
4952
5456
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4953
5457
|
framerMotion.motion.button,
|
|
4954
5458
|
{
|
|
4955
|
-
title: isSaving ? "
|
|
5459
|
+
title: isSaving ? locale("cfgpanel_saving") : isDirty ? `${locale("cfgpanel_save")} (${changedCount})` : locale("cfgpanel_save"),
|
|
4956
5460
|
onClick: () => isDirty && !isSaving && form.submit(),
|
|
4957
5461
|
disabled: !isDirty || isSaving,
|
|
4958
5462
|
whileHover: isDirty && !isSaving ? { background: core.alpha(color, 0.25), borderColor: core.alpha(color, 0.5) } : void 0,
|
|
@@ -4964,7 +5468,7 @@ function ConfigPanelInner({
|
|
|
4964
5468
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4965
5469
|
framerMotion.motion.button,
|
|
4966
5470
|
{
|
|
4967
|
-
title: "
|
|
5471
|
+
title: locale("cfgpanel_history"),
|
|
4968
5472
|
onClick: () => setHistoryOpen(true),
|
|
4969
5473
|
whileHover: { background: core.alpha("#22d3ee", 0.16), borderColor: core.alpha("#22d3ee", 0.5) },
|
|
4970
5474
|
whileTap: { scale: 0.97 },
|
|
@@ -4985,7 +5489,7 @@ function ConfigPanelInner({
|
|
|
4985
5489
|
style: { width: "100%", background: "transparent", border: `0.1vh solid ${isDirty ? core.alpha("#f97316", 0.35) : core.alpha(theme2.colors.dark[5], 0.3)}`, borderRadius: theme2.radius.xs, padding: "0.65vh 0.8vh", cursor: isDirty ? "pointer" : "default", display: "flex", alignItems: "center", gap: "0.55vh", opacity: isDirty ? 1 : 0.35, transition: "opacity 0.2s" },
|
|
4986
5490
|
children: [
|
|
4987
5491
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { color: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", size: "1.6vh" }),
|
|
4988
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", children: "
|
|
5492
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", children: locale("cfgpanel_discard") })
|
|
4989
5493
|
]
|
|
4990
5494
|
}
|
|
4991
5495
|
),
|
|
@@ -4999,7 +5503,7 @@ function ConfigPanelInner({
|
|
|
4999
5503
|
style: { width: "100%", background: core.alpha(color, 0.07), border: `0.1vh solid ${core.alpha(color, 0.28)}`, borderRadius: theme2.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
5000
5504
|
children: [
|
|
5001
5505
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { color, size: "1.6vh" }),
|
|
5002
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: "
|
|
5506
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("cfgpanel_manual_edit") })
|
|
5003
5507
|
]
|
|
5004
5508
|
}
|
|
5005
5509
|
),
|
|
@@ -5012,12 +5516,13 @@ function ConfigPanelInner({
|
|
|
5012
5516
|
style: { width: "100%", background: core.alpha("#ef4444", 0.07), border: `0.1vh solid ${core.alpha("#ef4444", 0.25)}`, borderRadius: theme2.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
5013
5517
|
children: [
|
|
5014
5518
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { color: "#ef4444", size: "1.6vh" }),
|
|
5015
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: "
|
|
5519
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: locale("cfgpanel_reset_defaults") })
|
|
5016
5520
|
]
|
|
5017
5521
|
}
|
|
5018
5522
|
),
|
|
5019
5523
|
version && /* @__PURE__ */ jsxRuntime.jsxs(core.Text, { size: "0.95vh", c: "dimmed", ta: "center", style: { letterSpacing: "0.04em", opacity: 0.8 }, children: [
|
|
5020
|
-
"
|
|
5524
|
+
locale("cfgpanel_version"),
|
|
5525
|
+
" ",
|
|
5021
5526
|
version
|
|
5022
5527
|
] })
|
|
5023
5528
|
] })
|
|
@@ -5048,7 +5553,7 @@ function cloneConfig(value) {
|
|
|
5048
5553
|
function ServerOnlyFetcher() {
|
|
5049
5554
|
const { fetchConfig } = getScriptConfigInstance();
|
|
5050
5555
|
const { reinitialize } = useFormActions();
|
|
5051
|
-
|
|
5556
|
+
React4.useEffect(() => {
|
|
5052
5557
|
let cancelled = false;
|
|
5053
5558
|
fetchConfig().then((full) => {
|
|
5054
5559
|
if (!cancelled && full) reinitialize(full);
|
|
@@ -5063,13 +5568,13 @@ function ServerOnlyFetcher() {
|
|
|
5063
5568
|
var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
|
|
5064
5569
|
function ConfigPanel(props) {
|
|
5065
5570
|
const { open, onClose = defaultOnClose } = props;
|
|
5066
|
-
const { store, updateConfig } = getScriptConfigInstance();
|
|
5067
|
-
const [isSaving, setIsSaving] =
|
|
5571
|
+
const { store: store2, updateConfig } = getScriptConfigInstance();
|
|
5572
|
+
const [isSaving, setIsSaving] = React4.useState(false);
|
|
5068
5573
|
if (!open) return null;
|
|
5069
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5574
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5070
5575
|
FormProvider,
|
|
5071
5576
|
{
|
|
5072
|
-
initialValues: cloneConfig(
|
|
5577
|
+
initialValues: cloneConfig(store2.getState()),
|
|
5073
5578
|
onSubmit: async (form) => {
|
|
5074
5579
|
if (isSaving) return;
|
|
5075
5580
|
setIsSaving(true);
|
|
@@ -5077,7 +5582,7 @@ function ConfigPanel(props) {
|
|
|
5077
5582
|
const result = await updateConfig(form.values);
|
|
5078
5583
|
if (result?.success) {
|
|
5079
5584
|
form.reinitialize(cloneConfig(form.values));
|
|
5080
|
-
|
|
5585
|
+
dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
|
|
5081
5586
|
useMissingItemsAudit.getState().refresh();
|
|
5082
5587
|
notifications.notifications.show({
|
|
5083
5588
|
color: "green",
|
|
@@ -5087,7 +5592,7 @@ function ConfigPanel(props) {
|
|
|
5087
5592
|
});
|
|
5088
5593
|
return;
|
|
5089
5594
|
}
|
|
5090
|
-
form.reinitialize(cloneConfig(
|
|
5595
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
5091
5596
|
const err = result?._error || "Unknown";
|
|
5092
5597
|
console.warn(`[ConfigPanel] config save failed: ${err}`);
|
|
5093
5598
|
const titleKey = err === "NoPermission" ? "ConfigSaveNoPermissionTitle" : err === "VersionConflict" ? "ConfigSaveVersionConflictTitle" : err === "NotReady" ? "ConfigSaveNotReadyTitle" : "ConfigSaveFailedTitle";
|
|
@@ -5118,9 +5623,9 @@ function ConfigPanel(props) {
|
|
|
5118
5623
|
}
|
|
5119
5624
|
var MISSING_COLOR = "#f59e0b";
|
|
5120
5625
|
function LazyImage({ src, style }) {
|
|
5121
|
-
const [visible, setVisible] =
|
|
5122
|
-
const ref =
|
|
5123
|
-
|
|
5626
|
+
const [visible, setVisible] = React4.useState(false);
|
|
5627
|
+
const ref = React4.useRef(null);
|
|
5628
|
+
React4.useEffect(() => {
|
|
5124
5629
|
const observer = new IntersectionObserver(([entry]) => {
|
|
5125
5630
|
if (entry.isIntersecting) {
|
|
5126
5631
|
setVisible(true);
|
|
@@ -5135,7 +5640,7 @@ function LazyImage({ src, style }) {
|
|
|
5135
5640
|
function SelectItem(props) {
|
|
5136
5641
|
const invItems = useItems();
|
|
5137
5642
|
const isMissing = !!props.value && !invItems[props.value];
|
|
5138
|
-
const formattedItems =
|
|
5643
|
+
const formattedItems = React4.useMemo(() => {
|
|
5139
5644
|
const seen = /* @__PURE__ */ new Set();
|
|
5140
5645
|
const list = useItemsList(props.excludeItemNames ?? []).filter((item) => {
|
|
5141
5646
|
if (seen.has(item.name)) return false;
|
|
@@ -5225,9 +5730,9 @@ function PositionPicker(props) {
|
|
|
5225
5730
|
} = props;
|
|
5226
5731
|
const theme2 = core.useMantineTheme();
|
|
5227
5732
|
const color = theme2.colors[theme2.primaryColor][5];
|
|
5228
|
-
const [previewing, setPreviewing] =
|
|
5229
|
-
const previewingRef =
|
|
5230
|
-
|
|
5733
|
+
const [previewing, setPreviewing] = React4.useState(false);
|
|
5734
|
+
const previewingRef = React4.useRef(false);
|
|
5735
|
+
React4.useEffect(() => {
|
|
5231
5736
|
return () => {
|
|
5232
5737
|
if (previewingRef.current) {
|
|
5233
5738
|
fetchNui(stopPreviewEvent, { relativeTo }).catch(() => {
|
|
@@ -5565,7 +6070,7 @@ function Vector4DeleteButton({
|
|
|
5565
6070
|
}
|
|
5566
6071
|
);
|
|
5567
6072
|
}
|
|
5568
|
-
var GroupSelectContext =
|
|
6073
|
+
var GroupSelectContext = React4.createContext(null);
|
|
5569
6074
|
function GroupSelect({
|
|
5570
6075
|
value,
|
|
5571
6076
|
onChange,
|
|
@@ -5581,9 +6086,12 @@ function filterByType(jobs, gangs, type) {
|
|
|
5581
6086
|
return [...jobs, ...gangs];
|
|
5582
6087
|
}
|
|
5583
6088
|
function GroupName(props) {
|
|
5584
|
-
const ctx =
|
|
6089
|
+
const ctx = React4.useContext(GroupSelectContext);
|
|
5585
6090
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
5586
6091
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
6092
|
+
React4.useEffect(() => {
|
|
6093
|
+
ensureFrameworkGroups();
|
|
6094
|
+
}, []);
|
|
5587
6095
|
const inCompound = ctx !== null;
|
|
5588
6096
|
const currentValue = inCompound ? ctx.value.name : props.value;
|
|
5589
6097
|
const filterType = inCompound ? ctx.type : props.type;
|
|
@@ -5617,12 +6125,15 @@ function GroupName(props) {
|
|
|
5617
6125
|
);
|
|
5618
6126
|
}
|
|
5619
6127
|
function GroupRank(props) {
|
|
5620
|
-
const ctx =
|
|
6128
|
+
const ctx = React4.useContext(GroupSelectContext);
|
|
5621
6129
|
if (ctx === null) {
|
|
5622
6130
|
throw new Error("<GroupRank> must be a child of <GroupSelect>");
|
|
5623
6131
|
}
|
|
5624
6132
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
5625
6133
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
6134
|
+
React4.useEffect(() => {
|
|
6135
|
+
ensureFrameworkGroups();
|
|
6136
|
+
}, []);
|
|
5626
6137
|
const all = [...jobs, ...gangs];
|
|
5627
6138
|
const selectedGroup = all.find((g) => g.name === ctx.value.name) ?? null;
|
|
5628
6139
|
const grades = selectedGroup?.grades ?? [];
|
|
@@ -5653,9 +6164,9 @@ function GroupRank(props) {
|
|
|
5653
6164
|
}
|
|
5654
6165
|
GroupSelect.Name = GroupName;
|
|
5655
6166
|
GroupSelect.Rank = GroupRank;
|
|
5656
|
-
var KeyBindContext =
|
|
6167
|
+
var KeyBindContext = React4.createContext(null);
|
|
5657
6168
|
function useKeyBindContext() {
|
|
5658
|
-
const ctx =
|
|
6169
|
+
const ctx = React4.useContext(KeyBindContext);
|
|
5659
6170
|
if (!ctx) {
|
|
5660
6171
|
throw new Error("FiveMKeyBindInput.* must be used inside <FiveMKeyBindInput>");
|
|
5661
6172
|
}
|
|
@@ -5814,7 +6325,7 @@ function AsyncSaveButton({
|
|
|
5814
6325
|
style
|
|
5815
6326
|
}) {
|
|
5816
6327
|
const theme2 = core.useMantineTheme();
|
|
5817
|
-
const [state, setState] =
|
|
6328
|
+
const [state, setState] = React4.useState("idle");
|
|
5818
6329
|
const handleClick = async () => {
|
|
5819
6330
|
if (state === "pending") return;
|
|
5820
6331
|
setState("pending");
|
|
@@ -5954,10 +6465,10 @@ function TestBed({
|
|
|
5954
6465
|
title = "TestBed",
|
|
5955
6466
|
placement = "top-left"
|
|
5956
6467
|
}) {
|
|
5957
|
-
const [open, setOpen] =
|
|
5958
|
-
const itemsRef =
|
|
6468
|
+
const [open, setOpen] = React4.useState(false);
|
|
6469
|
+
const itemsRef = React4.useRef(items);
|
|
5959
6470
|
itemsRef.current = items;
|
|
5960
|
-
|
|
6471
|
+
React4.useEffect(() => {
|
|
5961
6472
|
if (!isEnvBrowser() || disablePersistence) return;
|
|
5962
6473
|
const persisted = loadPersistedState(storageKey);
|
|
5963
6474
|
itemsRef.current.forEach((item) => {
|
|
@@ -6294,7 +6805,7 @@ function SwatchTile({
|
|
|
6294
6805
|
isPrimary,
|
|
6295
6806
|
onChange
|
|
6296
6807
|
}) {
|
|
6297
|
-
const [opened, setOpened] =
|
|
6808
|
+
const [opened, setOpened] = React4.useState(false);
|
|
6298
6809
|
return /* @__PURE__ */ jsxRuntime.jsxs(core.Popover, { opened, onChange: setOpened, position: "bottom", withArrow: true, zIndex: 1e4, children: [
|
|
6299
6810
|
/* @__PURE__ */ jsxRuntime.jsx(core.Popover.Target, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6300
6811
|
"button",
|
|
@@ -6964,9 +7475,9 @@ var NOT_CONFIGURED_TINT = "rgba(255,184,0,0.35)";
|
|
|
6964
7475
|
var NOT_CONFIGURED_FILL = "rgba(255,184,0,0.05)";
|
|
6965
7476
|
function DiscordRoleSelect(props) {
|
|
6966
7477
|
const { endpoint, label: label2, size = "xs", placeholder, disabled, style, styles } = props;
|
|
6967
|
-
const [roles, setRoles] =
|
|
6968
|
-
const [loading, setLoading] =
|
|
6969
|
-
const [errorCode, setErrorCode] =
|
|
7478
|
+
const [roles, setRoles] = React4.useState(null);
|
|
7479
|
+
const [loading, setLoading] = React4.useState(false);
|
|
7480
|
+
const [errorCode, setErrorCode] = React4.useState(null);
|
|
6970
7481
|
const refresh = async () => {
|
|
6971
7482
|
setLoading(true);
|
|
6972
7483
|
try {
|
|
@@ -6992,10 +7503,10 @@ function DiscordRoleSelect(props) {
|
|
|
6992
7503
|
setLoading(false);
|
|
6993
7504
|
}
|
|
6994
7505
|
};
|
|
6995
|
-
|
|
7506
|
+
React4.useEffect(() => {
|
|
6996
7507
|
refresh();
|
|
6997
7508
|
}, [endpoint]);
|
|
6998
|
-
const rolesById =
|
|
7509
|
+
const rolesById = React4.useMemo(() => {
|
|
6999
7510
|
const map = {};
|
|
7000
7511
|
for (const r of roles ?? []) map[r.id] = r;
|
|
7001
7512
|
return map;
|
|
@@ -7161,9 +7672,9 @@ function FrameworkHint({ framework }) {
|
|
|
7161
7672
|
}
|
|
7162
7673
|
function AccountSelect(props) {
|
|
7163
7674
|
const { endpoint, label: label2, size = "xs", placeholder, disabled, style, styles, hideFrameworkHint } = props;
|
|
7164
|
-
const [accounts, setAccounts] =
|
|
7165
|
-
const [framework, setFramework] =
|
|
7166
|
-
const [loading, setLoading] =
|
|
7675
|
+
const [accounts, setAccounts] = React4.useState(null);
|
|
7676
|
+
const [framework, setFramework] = React4.useState(void 0);
|
|
7677
|
+
const [loading, setLoading] = React4.useState(false);
|
|
7167
7678
|
const refresh = async () => {
|
|
7168
7679
|
setLoading(true);
|
|
7169
7680
|
try {
|
|
@@ -7188,10 +7699,10 @@ function AccountSelect(props) {
|
|
|
7188
7699
|
setLoading(false);
|
|
7189
7700
|
}
|
|
7190
7701
|
};
|
|
7191
|
-
|
|
7702
|
+
React4.useEffect(() => {
|
|
7192
7703
|
refresh();
|
|
7193
7704
|
}, [endpoint]);
|
|
7194
|
-
const accountsByName =
|
|
7705
|
+
const accountsByName = React4.useMemo(() => {
|
|
7195
7706
|
const map = {};
|
|
7196
7707
|
for (const a of accounts ?? []) map[a.name] = a;
|
|
7197
7708
|
if (props.multi) {
|
|
@@ -7268,349 +7779,831 @@ function AccountSelect(props) {
|
|
|
7268
7779
|
!hideFrameworkHint && /* @__PURE__ */ jsxRuntime.jsx(FrameworkHint, { framework })
|
|
7269
7780
|
] });
|
|
7270
7781
|
}
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7782
|
+
var BODY_HIDE_STYLE_ID2 = "dirk-instruction-panel-style";
|
|
7783
|
+
var BODY_HIDE_ATTR2 = "data-dirk-instruction-active";
|
|
7784
|
+
var OVERLAY_ATTR2 = "data-dirk-instruction-overlay";
|
|
7785
|
+
function ensureBodyHideStyle2() {
|
|
7786
|
+
if (document.getElementById(BODY_HIDE_STYLE_ID2)) return;
|
|
7787
|
+
const el = document.createElement("style");
|
|
7788
|
+
el.id = BODY_HIDE_STYLE_ID2;
|
|
7789
|
+
el.textContent = `
|
|
7790
|
+
body[${BODY_HIDE_ATTR2}] > *:not([${OVERLAY_ATTR2}]) {
|
|
7791
|
+
visibility: hidden !important;
|
|
7792
|
+
opacity: 0 !important;
|
|
7793
|
+
pointer-events: none !important;
|
|
7794
|
+
}
|
|
7795
|
+
`;
|
|
7796
|
+
document.head.appendChild(el);
|
|
7274
7797
|
}
|
|
7275
|
-
function
|
|
7798
|
+
function InstructionPanel({
|
|
7799
|
+
visible,
|
|
7800
|
+
title,
|
|
7801
|
+
hint,
|
|
7802
|
+
keys,
|
|
7803
|
+
icon: Icon = lucideReact.MapPin,
|
|
7804
|
+
hideRestOfAdmin = true
|
|
7805
|
+
}) {
|
|
7806
|
+
const theme2 = core.useMantineTheme();
|
|
7807
|
+
const pc = theme2.colors[theme2.primaryColor];
|
|
7808
|
+
React4.useEffect(() => {
|
|
7809
|
+
if (!visible || !hideRestOfAdmin) return;
|
|
7810
|
+
ensureBodyHideStyle2();
|
|
7811
|
+
document.body.setAttribute(BODY_HIDE_ATTR2, "");
|
|
7812
|
+
return () => {
|
|
7813
|
+
document.body.removeAttribute(BODY_HIDE_ATTR2);
|
|
7814
|
+
};
|
|
7815
|
+
}, [visible, hideRestOfAdmin]);
|
|
7816
|
+
if (!visible) return null;
|
|
7817
|
+
return reactDom.createPortal(
|
|
7818
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7819
|
+
"div",
|
|
7820
|
+
{
|
|
7821
|
+
...{ [OVERLAY_ATTR2]: "" },
|
|
7822
|
+
style: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: 1e4 },
|
|
7823
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7824
|
+
framerMotion.motion.div,
|
|
7825
|
+
{
|
|
7826
|
+
initial: { opacity: 0, y: 12, scale: 0.92 },
|
|
7827
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
7828
|
+
exit: { opacity: 0, y: 12, scale: 0.92 },
|
|
7829
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
7830
|
+
style: { position: "absolute", bottom: "3vh", right: "3vh", userSelect: "none" },
|
|
7831
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7832
|
+
core.Flex,
|
|
7833
|
+
{
|
|
7834
|
+
direction: "column",
|
|
7835
|
+
gap: "0.8vh",
|
|
7836
|
+
style: {
|
|
7837
|
+
background: core.alpha(theme2.colors.dark[9], 0.55),
|
|
7838
|
+
border: "0.1vh solid rgba(255,255,255,0.07)",
|
|
7839
|
+
borderRadius: theme2.radius.sm,
|
|
7840
|
+
boxShadow: "0 0.74vh 2.96vh rgba(0,0,0,0.5)",
|
|
7841
|
+
padding: "1.4vh 1.6vh",
|
|
7842
|
+
minWidth: "22vh",
|
|
7843
|
+
maxWidth: "28vh"
|
|
7844
|
+
},
|
|
7845
|
+
children: [
|
|
7846
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
|
|
7847
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.6vh", color: pc[6], strokeWidth: 2.5 }),
|
|
7848
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7849
|
+
core.Text,
|
|
7850
|
+
{
|
|
7851
|
+
style: {
|
|
7852
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
7853
|
+
fontSize: "1.7vh",
|
|
7854
|
+
fontWeight: 700,
|
|
7855
|
+
letterSpacing: "0.14em",
|
|
7856
|
+
textTransform: "uppercase",
|
|
7857
|
+
color: pc[6],
|
|
7858
|
+
textShadow: `0 0 0.8vh ${core.alpha(pc[7], 0.5)}, 0 0 1.6vh ${core.alpha(pc[9], 0.3)}`
|
|
7859
|
+
},
|
|
7860
|
+
children: title
|
|
7861
|
+
}
|
|
7862
|
+
)
|
|
7863
|
+
] }),
|
|
7864
|
+
(hint || keys && keys.length > 0) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
7865
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7866
|
+
core.Text,
|
|
7867
|
+
{
|
|
7868
|
+
style: {
|
|
7869
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
7870
|
+
fontSize: "1.05vh",
|
|
7871
|
+
color: "rgba(255,255,255,0.45)",
|
|
7872
|
+
letterSpacing: "0.06em",
|
|
7873
|
+
textTransform: "uppercase",
|
|
7874
|
+
lineHeight: 1.4
|
|
7875
|
+
},
|
|
7876
|
+
children: hint
|
|
7877
|
+
}
|
|
7878
|
+
),
|
|
7879
|
+
keys && keys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7880
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
7881
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Flex, { direction: "column", gap: "0.5vh", children: keys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsx(InstructionKeyRow, { keyLabel: k.key, action: k.action }, i)) })
|
|
7882
|
+
] })
|
|
7883
|
+
]
|
|
7884
|
+
}
|
|
7885
|
+
)
|
|
7886
|
+
},
|
|
7887
|
+
"instruction-card"
|
|
7888
|
+
) })
|
|
7889
|
+
}
|
|
7890
|
+
),
|
|
7891
|
+
document.body
|
|
7892
|
+
);
|
|
7893
|
+
}
|
|
7894
|
+
function renderKeyContent(keyLabel) {
|
|
7895
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
7896
|
+
if (normalized === "LMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "left" });
|
|
7897
|
+
if (normalized === "RMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "right" });
|
|
7898
|
+
if (normalized === "BACKSPACE" || keyLabel === "\u232B") return /* @__PURE__ */ jsxRuntime.jsx(BackspaceIcon, {});
|
|
7276
7899
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7277
|
-
|
|
7900
|
+
core.Text,
|
|
7278
7901
|
{
|
|
7279
|
-
style: {
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
numOctaves: "5",
|
|
7288
|
-
seed: "9",
|
|
7289
|
-
result: "noise1"
|
|
7290
|
-
}
|
|
7291
|
-
),
|
|
7292
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7293
|
-
"feTurbulence",
|
|
7294
|
-
{
|
|
7295
|
-
type: "fractalNoise",
|
|
7296
|
-
baseFrequency: "0.08 0.12",
|
|
7297
|
-
numOctaves: "2",
|
|
7298
|
-
seed: "3",
|
|
7299
|
-
result: "noise2"
|
|
7300
|
-
}
|
|
7301
|
-
),
|
|
7302
|
-
/* @__PURE__ */ jsxRuntime.jsx("feBlend", { in: "noise1", in2: "noise2", mode: "multiply", result: "combinedNoise" }),
|
|
7303
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7304
|
-
"feDisplacementMap",
|
|
7305
|
-
{
|
|
7306
|
-
in: "SourceGraphic",
|
|
7307
|
-
in2: "combinedNoise",
|
|
7308
|
-
scale: "52",
|
|
7309
|
-
xChannelSelector: "R",
|
|
7310
|
-
yChannelSelector: "G",
|
|
7311
|
-
result: "displaced"
|
|
7312
|
-
}
|
|
7313
|
-
),
|
|
7314
|
-
/* @__PURE__ */ jsxRuntime.jsx("feGaussianBlur", { stdDeviation: "0.8", in: "displaced", result: "blurred" }),
|
|
7315
|
-
/* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: "blurred", result: "alphaFade", children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "gamma", amplitude: "1", exponent: "1.3", offset: "-0.05" }) }),
|
|
7316
|
-
/* @__PURE__ */ jsxRuntime.jsx("feMorphology", { operator: "erode", radius: "0.4", in: "alphaFade", result: "eroded" }),
|
|
7317
|
-
/* @__PURE__ */ jsxRuntime.jsx("feMerge", { children: /* @__PURE__ */ jsxRuntime.jsx("feMergeNode", { in: "eroded" }) })
|
|
7318
|
-
] }) })
|
|
7902
|
+
style: {
|
|
7903
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
7904
|
+
fontSize: "1.2vh",
|
|
7905
|
+
color: "rgba(255,255,255,0.85)",
|
|
7906
|
+
lineHeight: 1,
|
|
7907
|
+
padding: "0 0.3vh"
|
|
7908
|
+
},
|
|
7909
|
+
children: keyLabel
|
|
7319
7910
|
}
|
|
7320
7911
|
);
|
|
7321
7912
|
}
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
sm: "0.75vh",
|
|
7357
|
-
md: "1vh",
|
|
7358
|
-
lg: "1.5vh",
|
|
7359
|
-
xl: "2vh",
|
|
7360
|
-
xxl: "3vh"
|
|
7361
|
-
},
|
|
7362
|
-
fontSizes: {
|
|
7363
|
-
xxs: "1.2vh",
|
|
7364
|
-
xs: "1.5vh",
|
|
7365
|
-
sm: "1.8vh",
|
|
7366
|
-
md: "2.2vh",
|
|
7367
|
-
lg: "2.8vh",
|
|
7368
|
-
xl: "3.3vh",
|
|
7369
|
-
xxl: "3.8vh"
|
|
7370
|
-
},
|
|
7371
|
-
lineHeights: {
|
|
7372
|
-
xxs: "1.4vh",
|
|
7373
|
-
xs: "1.8vh",
|
|
7374
|
-
sm: "2.2vh",
|
|
7375
|
-
md: "2.8vh",
|
|
7376
|
-
lg: "3.3vh",
|
|
7377
|
-
xl: "3.8vh"
|
|
7378
|
-
},
|
|
7379
|
-
spacing: {
|
|
7380
|
-
xxs: "0.5vh",
|
|
7381
|
-
xs: "0.75vh",
|
|
7382
|
-
sm: "1.5vh",
|
|
7383
|
-
md: "2vh",
|
|
7384
|
-
lg: "3vh",
|
|
7385
|
-
xl: "4vh",
|
|
7386
|
-
xxl: "5vh"
|
|
7387
|
-
},
|
|
7388
|
-
components: {
|
|
7389
|
-
Progress: {
|
|
7390
|
-
styles: {
|
|
7391
|
-
label: {
|
|
7392
|
-
fontFamily: "Akrobat Bold",
|
|
7393
|
-
letterSpacing: "0.05em",
|
|
7913
|
+
function InstructionKeyRow({ keyLabel, action }) {
|
|
7914
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
7915
|
+
const isIconKey = normalized === "LMB" || normalized === "RMB" || normalized === "BACKSPACE" || keyLabel === "\u232B";
|
|
7916
|
+
const minWidth = isIconKey ? "2.6vh" : "2.4vh";
|
|
7917
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
|
|
7918
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7919
|
+
"div",
|
|
7920
|
+
{
|
|
7921
|
+
style: {
|
|
7922
|
+
minWidth,
|
|
7923
|
+
height: "2.4vh",
|
|
7924
|
+
padding: "0 0.4vh",
|
|
7925
|
+
borderRadius: "0.3vh",
|
|
7926
|
+
border: "0.15vh solid rgba(255,255,255,0.35)",
|
|
7927
|
+
background: "rgba(255,255,255,0.06)",
|
|
7928
|
+
display: "flex",
|
|
7929
|
+
alignItems: "center",
|
|
7930
|
+
justifyContent: "center",
|
|
7931
|
+
opacity: 0.85,
|
|
7932
|
+
filter: "drop-shadow(0 0 0.3vh rgba(0,0,0,0.5))",
|
|
7933
|
+
flexShrink: 0,
|
|
7934
|
+
boxSizing: "border-box"
|
|
7935
|
+
},
|
|
7936
|
+
children: renderKeyContent(keyLabel)
|
|
7937
|
+
}
|
|
7938
|
+
),
|
|
7939
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7940
|
+
core.Text,
|
|
7941
|
+
{
|
|
7942
|
+
style: {
|
|
7943
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
7944
|
+
fontSize: "1.05vh",
|
|
7945
|
+
color: "rgba(255,255,255,0.45)",
|
|
7946
|
+
letterSpacing: "0.06em",
|
|
7394
7947
|
textTransform: "uppercase"
|
|
7395
7948
|
},
|
|
7396
|
-
|
|
7397
|
-
backgroundColor: "rgba(77, 77, 77, 0.4)"
|
|
7398
|
-
}
|
|
7949
|
+
children: action
|
|
7399
7950
|
}
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7951
|
+
)
|
|
7952
|
+
] });
|
|
7953
|
+
}
|
|
7954
|
+
function MouseIcon({ side }) {
|
|
7955
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
7956
|
+
const fillActive = "rgba(255,255,255,0.85)";
|
|
7957
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 22", width: "1.4vh", height: "1.9vh", fill: "none", stroke, strokeWidth: "1.4", strokeLinejoin: "round", children: [
|
|
7958
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "1", width: "14", height: "20", rx: "6" }),
|
|
7959
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "1", x2: "8", y2: "9" }),
|
|
7960
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7961
|
+
"path",
|
|
7962
|
+
{
|
|
7963
|
+
d: side === "left" ? "M 7.4 1.6 L 2 1.6 A 5 5 0 0 0 1 6 L 1 9 L 7.4 9 Z" : "M 8.6 1.6 L 14 1.6 A 5 5 0 0 1 15 6 L 15 9 L 8.6 9 Z",
|
|
7964
|
+
fill: fillActive,
|
|
7965
|
+
stroke: "none"
|
|
7966
|
+
}
|
|
7967
|
+
)
|
|
7968
|
+
] });
|
|
7969
|
+
}
|
|
7970
|
+
function BackspaceIcon() {
|
|
7971
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
7972
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 22 16", width: "1.7vh", height: "1.3vh", fill: "none", stroke, strokeWidth: "1.4", strokeLinejoin: "round", strokeLinecap: "round", children: [
|
|
7973
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 21 2 L 8 2 L 2 8 L 8 14 L 21 14 Z" }),
|
|
7974
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "11", y1: "6", x2: "16", y2: "11" }),
|
|
7975
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "6", x2: "11", y2: "11" })
|
|
7976
|
+
] });
|
|
7977
|
+
}
|
|
7978
|
+
function WorldPositionPicker({ value, onChange, compact, setOnly, gotoOnly }) {
|
|
7979
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7980
|
+
!gotoOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionSetButton2, { value, onChange, compact }),
|
|
7981
|
+
!setOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionGotoButton2, { value, compact })
|
|
7982
|
+
] });
|
|
7983
|
+
}
|
|
7984
|
+
function WorldPositionSetButton2({
|
|
7985
|
+
value,
|
|
7986
|
+
onChange,
|
|
7987
|
+
compact
|
|
7988
|
+
}) {
|
|
7989
|
+
const theme2 = core.useMantineTheme();
|
|
7990
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
7991
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
7992
|
+
const onClick = async () => {
|
|
7993
|
+
const instructions = {
|
|
7994
|
+
title: locale("PickPositionTitle") || "Pick Position",
|
|
7995
|
+
hint: locale("PickPositionHint") || "Walk to where you want this set",
|
|
7996
|
+
keys: [
|
|
7997
|
+
{ key: "E", action: locale("Set") || "Set" },
|
|
7998
|
+
{ key: "\u232B", action: locale("Cancel") || "Cancel" }
|
|
7999
|
+
]
|
|
8000
|
+
};
|
|
8001
|
+
const pendingResult = begin({ id: "capturePosition", ...instructions });
|
|
8002
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "capturePosition", instructions }).catch(() => {
|
|
8003
|
+
useAdminToolStore.getState().cancelActive();
|
|
8004
|
+
});
|
|
8005
|
+
const result = await pendingResult;
|
|
8006
|
+
if (result) onChange(result);
|
|
8007
|
+
};
|
|
8008
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("SetWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8009
|
+
framerMotion.motion.button,
|
|
8010
|
+
{
|
|
8011
|
+
onClick,
|
|
8012
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
8013
|
+
whileTap: { scale: 0.95 },
|
|
8014
|
+
style: {
|
|
8015
|
+
background: core.alpha(color, 0.1),
|
|
8016
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
8017
|
+
borderRadius: theme2.radius.xs,
|
|
8018
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
8019
|
+
cursor: "pointer",
|
|
8020
|
+
display: "flex",
|
|
8021
|
+
alignItems: "center",
|
|
8022
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
8023
|
+
},
|
|
8024
|
+
children: [
|
|
8025
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crosshair, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
8026
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Set") })
|
|
8027
|
+
]
|
|
7426
8028
|
}
|
|
7427
|
-
}
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
8029
|
+
) });
|
|
8030
|
+
}
|
|
8031
|
+
function WorldPositionGotoButton2({
|
|
8032
|
+
value,
|
|
8033
|
+
compact
|
|
8034
|
+
}) {
|
|
8035
|
+
const theme2 = core.useMantineTheme();
|
|
8036
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
8037
|
+
const onClick = () => {
|
|
8038
|
+
fetchNui("ADMIN_TOOL_INVOKE", { id: "gotoCoord", value }).catch(() => {
|
|
8039
|
+
});
|
|
8040
|
+
};
|
|
8041
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("GotoWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8042
|
+
framerMotion.motion.button,
|
|
8043
|
+
{
|
|
8044
|
+
onClick,
|
|
8045
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
8046
|
+
whileTap: { scale: 0.95 },
|
|
8047
|
+
style: {
|
|
8048
|
+
background: core.alpha(color, 0.1),
|
|
8049
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
8050
|
+
borderRadius: theme2.radius.xs,
|
|
8051
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
8052
|
+
cursor: "pointer",
|
|
8053
|
+
display: "flex",
|
|
8054
|
+
alignItems: "center",
|
|
8055
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
8056
|
+
},
|
|
8057
|
+
children: [
|
|
8058
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
8059
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Goto") })
|
|
8060
|
+
]
|
|
7455
8061
|
}
|
|
7456
|
-
}
|
|
8062
|
+
) });
|
|
8063
|
+
}
|
|
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
|
+
});
|
|
7457
8097
|
return {
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
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 });
|
|
7463
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
|
+
] });
|
|
7464
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
|
+
);
|
|
7465
8207
|
}
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
}
|
|
7480
|
-
render() {
|
|
7481
|
-
if (!this.state.error) return this.props.children;
|
|
7482
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7483
|
-
core.Box,
|
|
7484
|
-
{
|
|
7485
|
-
style: {
|
|
7486
|
-
position: "fixed",
|
|
7487
|
-
inset: 0,
|
|
7488
|
-
width: "100vw",
|
|
7489
|
-
height: "100vh",
|
|
7490
|
-
background: "rgba(10, 10, 12, 0.92)",
|
|
7491
|
-
display: "flex",
|
|
7492
|
-
alignItems: "center",
|
|
7493
|
-
justifyContent: "center",
|
|
7494
|
-
padding: "2rem",
|
|
7495
|
-
zIndex: 999999
|
|
7496
|
-
},
|
|
7497
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7498
|
-
core.Box,
|
|
7499
|
-
{
|
|
7500
|
-
maw: 900,
|
|
7501
|
-
w: "100%",
|
|
7502
|
-
p: "lg",
|
|
7503
|
-
style: {
|
|
7504
|
-
background: "rgba(20,20,24,0.75)",
|
|
7505
|
-
border: "1px solid rgba(255,255,255,0.08)",
|
|
7506
|
-
borderRadius: "10px",
|
|
7507
|
-
boxShadow: "0 10px 40px rgba(0,0,0,0.6)"
|
|
7508
|
-
},
|
|
7509
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(core.Stack, { gap: "sm", children: [
|
|
7510
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Title, { order: 2, c: "red.5", children: "Dirk UI Crash" }),
|
|
7511
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { c: "dimmed", size: "sm", children: "The interface encountered a fatal error and stopped rendering." }),
|
|
7512
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Code, { block: true, style: { maxHeight: 150, overflow: "auto" }, children: this.state.error?.message }),
|
|
7513
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", c: "dimmed", children: "Check console for full stack trace" })
|
|
7514
|
-
] })
|
|
7515
|
-
}
|
|
7516
|
-
)
|
|
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
|
|
7517
8221
|
}
|
|
7518
|
-
|
|
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}`);
|
|
7519
8230
|
}
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
function
|
|
7523
|
-
const
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
8231
|
+
return parts.join(" \xB7 ");
|
|
8232
|
+
}
|
|
8233
|
+
function usePickDoor() {
|
|
8234
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
8235
|
+
return async () => {
|
|
8236
|
+
const pending = begin({
|
|
8237
|
+
id: "pickDoor",
|
|
8238
|
+
title: locale("PickDoorTitle"),
|
|
8239
|
+
hint: locale("PickDoorHint"),
|
|
8240
|
+
keys: [
|
|
8241
|
+
{ key: "LMB", action: locale("Toggle") },
|
|
8242
|
+
{ key: "E", action: locale("Confirm") },
|
|
8243
|
+
{ key: "BACKSPACE", action: locale("Cancel") }
|
|
8244
|
+
]
|
|
7534
8245
|
});
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
fetchNui("NUI_READY").catch(() => {
|
|
8246
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "pickDoor" }).catch(() => {
|
|
8247
|
+
useAdminToolStore.getState().cancelActive();
|
|
7538
8248
|
});
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
}
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
8249
|
+
return await pending;
|
|
8250
|
+
};
|
|
8251
|
+
}
|
|
8252
|
+
function DoorPickerButton({
|
|
8253
|
+
onPick,
|
|
8254
|
+
compact,
|
|
8255
|
+
label: label2,
|
|
8256
|
+
tooltip
|
|
8257
|
+
}) {
|
|
8258
|
+
const theme2 = core.useMantineTheme();
|
|
8259
|
+
const color = theme2.colors[theme2.primaryColor][5];
|
|
8260
|
+
const pickDoor = usePickDoor();
|
|
8261
|
+
const onClick = async () => {
|
|
8262
|
+
const picked = await pickDoor();
|
|
8263
|
+
if (picked && picked.doors.length > 0) onPick(picked);
|
|
8264
|
+
};
|
|
8265
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8266
|
+
core.Tooltip,
|
|
8267
|
+
{
|
|
8268
|
+
label: tooltip ?? locale("PickDoorTooltip"),
|
|
8269
|
+
position: "top",
|
|
8270
|
+
withArrow: true,
|
|
8271
|
+
withinPortal: true,
|
|
8272
|
+
zIndex: 2e3,
|
|
8273
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8274
|
+
framerMotion.motion.button,
|
|
8275
|
+
{
|
|
8276
|
+
onClick,
|
|
8277
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
8278
|
+
whileTap: { scale: 0.95 },
|
|
8279
|
+
style: {
|
|
8280
|
+
background: core.alpha(color, 0.1),
|
|
8281
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
8282
|
+
borderRadius: theme2.radius.xs,
|
|
8283
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
8284
|
+
cursor: "pointer",
|
|
8285
|
+
display: "flex",
|
|
8286
|
+
alignItems: "center",
|
|
8287
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
8288
|
+
},
|
|
8289
|
+
children: [
|
|
8290
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DoorOpen, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
8291
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: label2 ?? locale("PickDoor") })
|
|
8292
|
+
]
|
|
8293
|
+
}
|
|
8294
|
+
)
|
|
7564
8295
|
}
|
|
7565
8296
|
);
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
8297
|
+
}
|
|
8298
|
+
var MapImpl = React4.memo(({
|
|
8299
|
+
children,
|
|
8300
|
+
initialZoom = 2,
|
|
8301
|
+
initialCenter = gameToMap(0, 0),
|
|
8302
|
+
mapStyle = "game"
|
|
8303
|
+
}) => {
|
|
8304
|
+
const mapRef = React4.useRef(null);
|
|
8305
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8306
|
+
reactLeaflet.MapContainer,
|
|
8307
|
+
{
|
|
8308
|
+
maxBoundsViscosity: 1,
|
|
8309
|
+
preferCanvas: true,
|
|
8310
|
+
zoom: Math.round(initialZoom),
|
|
8311
|
+
zoomSnap: 1,
|
|
8312
|
+
zoomDelta: 1,
|
|
8313
|
+
zoomControl: false,
|
|
8314
|
+
crs: leaflet.CRS.Simple,
|
|
8315
|
+
style: {
|
|
8316
|
+
height: "100%",
|
|
8317
|
+
width: "100%",
|
|
8318
|
+
overflow: "hidden",
|
|
8319
|
+
outline: "none !important",
|
|
8320
|
+
border: "none !important",
|
|
8321
|
+
boxShadow: "none !important",
|
|
8322
|
+
backgroundColor: "#384950"
|
|
8323
|
+
},
|
|
8324
|
+
center: initialCenter,
|
|
8325
|
+
attributionControl: false,
|
|
8326
|
+
doubleClickZoom: false,
|
|
8327
|
+
inertia: false,
|
|
8328
|
+
zoomAnimation: false,
|
|
8329
|
+
ref: mapRef,
|
|
8330
|
+
maxBounds: [[-250, -250], [250, 250]],
|
|
8331
|
+
children: [
|
|
8332
|
+
/* @__PURE__ */ jsxRuntime.jsx(MapLayer, { mapLayer: mapStyle }),
|
|
8333
|
+
children
|
|
8334
|
+
]
|
|
7584
8335
|
}
|
|
8336
|
+
);
|
|
8337
|
+
});
|
|
8338
|
+
MapImpl.displayName = "DirkMap";
|
|
8339
|
+
var Map2 = MapImpl;
|
|
8340
|
+
var MapLayer = ({ mapLayer }) => {
|
|
8341
|
+
const map = reactLeaflet.useMap();
|
|
8342
|
+
const layerRef = React4.useRef(null);
|
|
8343
|
+
React4.useEffect(() => {
|
|
8344
|
+
if (layerRef.current) {
|
|
8345
|
+
map.removeLayer(layerRef.current);
|
|
8346
|
+
}
|
|
8347
|
+
const layer = leaflet.tileLayer(
|
|
8348
|
+
`https://s.rsg.sc/sc/images/games/GTAV/map/${mapLayer}/{z}/{x}/{y}.jpg`,
|
|
8349
|
+
{
|
|
8350
|
+
maxZoom: 6,
|
|
8351
|
+
minZoom: 4,
|
|
8352
|
+
bounds: leaflet.latLngBounds(leaflet.latLng(0, 128), leaflet.latLng(-192, 0)),
|
|
8353
|
+
tileSize: 256,
|
|
8354
|
+
updateWhenZooming: false,
|
|
8355
|
+
keepBuffer: 2,
|
|
8356
|
+
opacity: 0.75
|
|
8357
|
+
}
|
|
8358
|
+
);
|
|
8359
|
+
layer.addTo(map);
|
|
8360
|
+
layerRef.current = layer;
|
|
7585
8361
|
return () => {
|
|
7586
|
-
|
|
8362
|
+
if (layerRef.current) {
|
|
8363
|
+
map.removeLayer(layerRef.current);
|
|
8364
|
+
}
|
|
7587
8365
|
};
|
|
7588
|
-
}, []);
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
const
|
|
7593
|
-
const
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
8366
|
+
}, [mapLayer, map]);
|
|
8367
|
+
return null;
|
|
8368
|
+
};
|
|
8369
|
+
function ZoomControls() {
|
|
8370
|
+
const theme2 = core.useMantineTheme();
|
|
8371
|
+
const map = reactLeaflet.useMap();
|
|
8372
|
+
const buttons = [
|
|
8373
|
+
{ Icon: lucideReact.Plus, fn: () => map.zoomIn() },
|
|
8374
|
+
{ Icon: lucideReact.Minus, fn: () => map.zoomOut() }
|
|
8375
|
+
];
|
|
8376
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8377
|
+
framerMotion.motion.div,
|
|
8378
|
+
{
|
|
8379
|
+
style: {
|
|
8380
|
+
position: "absolute",
|
|
8381
|
+
right: "2vh",
|
|
8382
|
+
top: "2vh",
|
|
8383
|
+
display: "flex",
|
|
8384
|
+
flexDirection: "column",
|
|
8385
|
+
zIndex: 999999,
|
|
8386
|
+
boxShadow: `0 0 1vh ${core.alpha(theme2.colors.dark[9], 0.85)}`,
|
|
8387
|
+
background: core.alpha(theme2.colors.dark[9], 0.85),
|
|
8388
|
+
borderRadius: theme2.radius.xs
|
|
8389
|
+
},
|
|
8390
|
+
initial: { opacity: 0, y: -20 },
|
|
8391
|
+
animate: { opacity: 1, y: 0 },
|
|
8392
|
+
exit: { opacity: 0, y: -20 },
|
|
8393
|
+
children: buttons.map(({ Icon, fn }, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8394
|
+
framerMotion.motion.div,
|
|
8395
|
+
{
|
|
8396
|
+
whileHover: { scale: 1.1, filter: "brightness(1.5)" },
|
|
8397
|
+
onClick: fn,
|
|
8398
|
+
style: {
|
|
8399
|
+
padding: theme2.spacing.xs,
|
|
8400
|
+
cursor: "pointer",
|
|
8401
|
+
display: "flex"
|
|
8402
|
+
},
|
|
8403
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 34, color: theme2.colors.gray[5] })
|
|
8404
|
+
},
|
|
8405
|
+
i
|
|
8406
|
+
))
|
|
8407
|
+
}
|
|
7600
8408
|
);
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
8409
|
+
}
|
|
8410
|
+
var DEFAULT_SPRITE = 162;
|
|
8411
|
+
var DEFAULT_COLOR = 5;
|
|
8412
|
+
function BlipMarker({
|
|
8413
|
+
position,
|
|
8414
|
+
sprite,
|
|
8415
|
+
color,
|
|
8416
|
+
scale = 1,
|
|
8417
|
+
onClick,
|
|
8418
|
+
selected,
|
|
8419
|
+
disabled,
|
|
8420
|
+
fallbackSprite = DEFAULT_SPRITE,
|
|
8421
|
+
fallbackColor = DEFAULT_COLOR
|
|
8422
|
+
}) {
|
|
8423
|
+
const [hovered, setHovered] = React4.useState(false);
|
|
8424
|
+
const mapCoords = React4.useMemo(() => gameToMap(position.x, position.y), [position.x, position.y]);
|
|
8425
|
+
const effectiveSprite = sprite ?? fallbackSprite;
|
|
8426
|
+
const effectiveColor = color ?? fallbackColor;
|
|
8427
|
+
const url = blipUrlForSprite(effectiveSprite);
|
|
8428
|
+
const colorHex = getBlipColor(effectiveColor)?.hex ?? "#ffffff";
|
|
8429
|
+
const handleClick = (e) => {
|
|
8430
|
+
e.originalEvent?.stopPropagation?.();
|
|
8431
|
+
if (disabled) return;
|
|
8432
|
+
onClick?.();
|
|
8433
|
+
};
|
|
8434
|
+
const baseSize = 1.8 * scale;
|
|
8435
|
+
const size = `${baseSize}vh`;
|
|
8436
|
+
const ringSize = `${baseSize * 1.6}vh`;
|
|
8437
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8438
|
+
reactLeafletComponentMarker.Marker,
|
|
7606
8439
|
{
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
8440
|
+
position: mapCoords,
|
|
8441
|
+
eventHandlers: onClick ? { click: handleClick } : void 0,
|
|
8442
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8443
|
+
framerMotion.motion.div,
|
|
8444
|
+
{
|
|
8445
|
+
onHoverStart: () => setHovered(true),
|
|
8446
|
+
onHoverEnd: () => setHovered(false),
|
|
8447
|
+
style: {
|
|
8448
|
+
position: "relative",
|
|
8449
|
+
display: "flex",
|
|
8450
|
+
alignItems: "center",
|
|
8451
|
+
justifyContent: "center",
|
|
8452
|
+
cursor: disabled ? "not-allowed" : onClick ? "pointer" : "default",
|
|
8453
|
+
opacity: disabled ? 0.35 : 1,
|
|
8454
|
+
width: size,
|
|
8455
|
+
height: size
|
|
8456
|
+
},
|
|
8457
|
+
animate: { scale: hovered && !disabled ? 1.2 : selected ? 1.15 : 1 },
|
|
8458
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
8459
|
+
children: [
|
|
8460
|
+
(selected || hovered) && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8461
|
+
framerMotion.motion.div,
|
|
8462
|
+
{
|
|
8463
|
+
style: {
|
|
8464
|
+
position: "absolute",
|
|
8465
|
+
width: ringSize,
|
|
8466
|
+
height: ringSize,
|
|
8467
|
+
borderRadius: "50%",
|
|
8468
|
+
border: `0.18vh solid ${core.alpha(colorHex, 0.85)}`,
|
|
8469
|
+
boxShadow: `0 0 1vh ${core.alpha(colorHex, 0.55)}`
|
|
8470
|
+
},
|
|
8471
|
+
initial: { opacity: 0, scale: 0.8 },
|
|
8472
|
+
animate: { opacity: 1, scale: 1 }
|
|
8473
|
+
}
|
|
8474
|
+
),
|
|
8475
|
+
url && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8476
|
+
"div",
|
|
8477
|
+
{
|
|
8478
|
+
style: {
|
|
8479
|
+
width: size,
|
|
8480
|
+
height: size,
|
|
8481
|
+
backgroundColor: colorHex,
|
|
8482
|
+
WebkitMaskImage: `url(${url})`,
|
|
8483
|
+
maskImage: `url(${url})`,
|
|
8484
|
+
WebkitMaskRepeat: "no-repeat",
|
|
8485
|
+
maskRepeat: "no-repeat",
|
|
8486
|
+
WebkitMaskPosition: "center",
|
|
8487
|
+
maskPosition: "center",
|
|
8488
|
+
WebkitMaskSize: "contain",
|
|
8489
|
+
maskSize: "contain",
|
|
8490
|
+
filter: [
|
|
8491
|
+
"drop-shadow(0.12vh 0 0 #000)",
|
|
8492
|
+
"drop-shadow(-0.12vh 0 0 #000)",
|
|
8493
|
+
"drop-shadow(0 0.12vh 0 #000)",
|
|
8494
|
+
"drop-shadow(0 -0.12vh 0 #000)",
|
|
8495
|
+
`drop-shadow(0 0 0.4vh ${core.alpha("#000", 0.7)})`
|
|
8496
|
+
].join(" "),
|
|
8497
|
+
pointerEvents: "none",
|
|
8498
|
+
userSelect: "none"
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
)
|
|
8502
|
+
]
|
|
8503
|
+
}
|
|
8504
|
+
)
|
|
7611
8505
|
}
|
|
7612
|
-
)
|
|
7613
|
-
|
|
8506
|
+
);
|
|
8507
|
+
}
|
|
8508
|
+
function useTornEdges() {
|
|
8509
|
+
const game = useSettings((state) => state.game);
|
|
8510
|
+
return game === "rdr3" ? "torn-edge-wrapper" : "";
|
|
8511
|
+
}
|
|
8512
|
+
function TornEdgeSVGFilter() {
|
|
8513
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8514
|
+
"svg",
|
|
8515
|
+
{
|
|
8516
|
+
style: { position: "absolute", width: 0, height: 0, pointerEvents: "none" },
|
|
8517
|
+
"aria-hidden": "true",
|
|
8518
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("filter", { id: "torn-edge-filter", x: "-50%", y: "-50%", width: "200%", height: "200%", children: [
|
|
8519
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8520
|
+
"feTurbulence",
|
|
8521
|
+
{
|
|
8522
|
+
type: "fractalNoise",
|
|
8523
|
+
baseFrequency: "0.018 0.022",
|
|
8524
|
+
numOctaves: "5",
|
|
8525
|
+
seed: "9",
|
|
8526
|
+
result: "noise1"
|
|
8527
|
+
}
|
|
8528
|
+
),
|
|
8529
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8530
|
+
"feTurbulence",
|
|
8531
|
+
{
|
|
8532
|
+
type: "fractalNoise",
|
|
8533
|
+
baseFrequency: "0.08 0.12",
|
|
8534
|
+
numOctaves: "2",
|
|
8535
|
+
seed: "3",
|
|
8536
|
+
result: "noise2"
|
|
8537
|
+
}
|
|
8538
|
+
),
|
|
8539
|
+
/* @__PURE__ */ jsxRuntime.jsx("feBlend", { in: "noise1", in2: "noise2", mode: "multiply", result: "combinedNoise" }),
|
|
8540
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8541
|
+
"feDisplacementMap",
|
|
8542
|
+
{
|
|
8543
|
+
in: "SourceGraphic",
|
|
8544
|
+
in2: "combinedNoise",
|
|
8545
|
+
scale: "52",
|
|
8546
|
+
xChannelSelector: "R",
|
|
8547
|
+
yChannelSelector: "G",
|
|
8548
|
+
result: "displaced"
|
|
8549
|
+
}
|
|
8550
|
+
),
|
|
8551
|
+
/* @__PURE__ */ jsxRuntime.jsx("feGaussianBlur", { stdDeviation: "0.8", in: "displaced", result: "blurred" }),
|
|
8552
|
+
/* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: "blurred", result: "alphaFade", children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "gamma", amplitude: "1", exponent: "1.3", offset: "-0.05" }) }),
|
|
8553
|
+
/* @__PURE__ */ jsxRuntime.jsx("feMorphology", { operator: "erode", radius: "0.4", in: "alphaFade", result: "eroded" }),
|
|
8554
|
+
/* @__PURE__ */ jsxRuntime.jsx("feMerge", { children: /* @__PURE__ */ jsxRuntime.jsx("feMergeNode", { in: "eroded" }) })
|
|
8555
|
+
] }) })
|
|
8556
|
+
}
|
|
8557
|
+
);
|
|
8558
|
+
}
|
|
8559
|
+
var moduleCache = /* @__PURE__ */ new Map();
|
|
8560
|
+
function useValidModels(names) {
|
|
8561
|
+
const cacheKey = React4.useMemo(() => {
|
|
8562
|
+
const unique = Array.from(new Set(names.filter((n) => typeof n === "string" && n.length > 0)));
|
|
8563
|
+
unique.sort();
|
|
8564
|
+
return unique.join("|");
|
|
8565
|
+
}, [names]);
|
|
8566
|
+
const [version, setVersion] = React4.useState(0);
|
|
8567
|
+
const inflight = React4.useRef(/* @__PURE__ */ new Set());
|
|
8568
|
+
React4.useEffect(() => {
|
|
8569
|
+
if (!cacheKey) return;
|
|
8570
|
+
const all = cacheKey.split("|").filter(Boolean);
|
|
8571
|
+
const missing = all.filter((n) => !moduleCache.has(n) && !inflight.current.has(n));
|
|
8572
|
+
if (missing.length === 0) return;
|
|
8573
|
+
missing.forEach((n) => inflight.current.add(n));
|
|
8574
|
+
let cancelled = false;
|
|
8575
|
+
fetchNui(
|
|
8576
|
+
"ADMIN_TOOL_QUERY",
|
|
8577
|
+
{ id: "validateModels", value: missing },
|
|
8578
|
+
// Fallback when running outside FiveM (browser dev) — assume valid so the
|
|
8579
|
+
// dev shell doesn't grey out every row.
|
|
8580
|
+
Object.fromEntries(missing.map((n) => [n, true]))
|
|
8581
|
+
).then((result) => {
|
|
8582
|
+
if (cancelled) return;
|
|
8583
|
+
const map = result && typeof result === "object" ? result : {};
|
|
8584
|
+
missing.forEach((n) => {
|
|
8585
|
+
moduleCache.set(n, !!map[n]);
|
|
8586
|
+
inflight.current.delete(n);
|
|
8587
|
+
});
|
|
8588
|
+
setVersion((v) => v + 1);
|
|
8589
|
+
}).catch(() => {
|
|
8590
|
+
if (cancelled) return;
|
|
8591
|
+
missing.forEach((n) => {
|
|
8592
|
+
inflight.current.delete(n);
|
|
8593
|
+
});
|
|
8594
|
+
});
|
|
8595
|
+
return () => {
|
|
8596
|
+
cancelled = true;
|
|
8597
|
+
};
|
|
8598
|
+
}, [cacheKey]);
|
|
8599
|
+
return React4.useMemo(() => {
|
|
8600
|
+
const out = /* @__PURE__ */ new Set();
|
|
8601
|
+
if (!cacheKey) return out;
|
|
8602
|
+
for (const n of cacheKey.split("|")) {
|
|
8603
|
+
if (n && moduleCache.get(n) === true) out.add(n);
|
|
8604
|
+
}
|
|
8605
|
+
return out;
|
|
8606
|
+
}, [cacheKey, version]);
|
|
7614
8607
|
}
|
|
7615
8608
|
var Vector2Schema = zod.z.object({
|
|
7616
8609
|
x: zod.z.number(),
|
|
@@ -7635,6 +8628,7 @@ exports.AsyncSaveButton = AsyncSaveButton;
|
|
|
7635
8628
|
exports.BlipColorSelect = BlipColorSelect;
|
|
7636
8629
|
exports.BlipDisplaySelect = BlipDisplaySelect;
|
|
7637
8630
|
exports.BlipIconSelect = BlipIconSelect;
|
|
8631
|
+
exports.BlipMarker = BlipMarker;
|
|
7638
8632
|
exports.BorderedIcon = BorderedIcon;
|
|
7639
8633
|
exports.ConfigPanel = ConfigPanel;
|
|
7640
8634
|
exports.ConfirmModal = ConfirmModal;
|
|
@@ -7643,6 +8637,7 @@ exports.ControlSelect = ControlSelect;
|
|
|
7643
8637
|
exports.Counter = Counter;
|
|
7644
8638
|
exports.DirkProvider = DirkProvider;
|
|
7645
8639
|
exports.DiscordRoleSelect = DiscordRoleSelect;
|
|
8640
|
+
exports.DoorPickerButton = DoorPickerButton;
|
|
7646
8641
|
exports.FiveMKeyBindInput = FiveMKeyBindInput;
|
|
7647
8642
|
exports.FloatingParticles = FloatingParticles;
|
|
7648
8643
|
exports.FormProvider = FormProvider;
|
|
@@ -7655,8 +8650,11 @@ exports.INPUT_MAPPER_KEYS_BY_PRIMARY = INPUT_MAPPER_KEYS_BY_PRIMARY;
|
|
|
7655
8650
|
exports.INPUT_MAPPER_PRIMARY_OPTIONS = INPUT_MAPPER_PRIMARY_OPTIONS;
|
|
7656
8651
|
exports.InfoBox = InfoBox;
|
|
7657
8652
|
exports.InputContainer = InputContainer;
|
|
8653
|
+
exports.InstructionPanel = InstructionPanel;
|
|
7658
8654
|
exports.LevelBanner = LevelBanner;
|
|
7659
8655
|
exports.LevelPanel = LevelPanel;
|
|
8656
|
+
exports.Map = Map2;
|
|
8657
|
+
exports.MapLayer = MapLayer;
|
|
7660
8658
|
exports.MissingItemsBanner = MissingItemsBanner;
|
|
7661
8659
|
exports.Modal = Modal;
|
|
7662
8660
|
exports.ModalContext = ModalContext;
|
|
@@ -7668,6 +8666,7 @@ exports.MotionText = MotionText;
|
|
|
7668
8666
|
exports.NavBar = NavBar;
|
|
7669
8667
|
exports.NavigationContext = NavigationContext;
|
|
7670
8668
|
exports.NavigationProvider = NavigationProvider;
|
|
8669
|
+
exports.PlayerSelect = PlayerSelect;
|
|
7671
8670
|
exports.PositionPicker = PositionPicker;
|
|
7672
8671
|
exports.PromptModal = PromptModal;
|
|
7673
8672
|
exports.ScenarioSelect = ScenarioSelect;
|
|
@@ -7685,17 +8684,26 @@ exports.Vector4DeleteButton = Vector4DeleteButton;
|
|
|
7685
8684
|
exports.Vector4Display = Vector4Display;
|
|
7686
8685
|
exports.Vector4Schema = Vector4Schema;
|
|
7687
8686
|
exports.WorldPositionGotoButton = WorldPositionGotoButton;
|
|
8687
|
+
exports.WorldPositionPicker = WorldPositionPicker;
|
|
7688
8688
|
exports.WorldPositionSetButton = WorldPositionSetButton;
|
|
8689
|
+
exports.ZoomControls = ZoomControls;
|
|
8690
|
+
exports.blipUrl = blipUrl;
|
|
8691
|
+
exports.blipUrlForSprite = blipUrlForSprite;
|
|
8692
|
+
exports.clearAdminState = clearAdminState;
|
|
7689
8693
|
exports.colorWithAlpha = colorWithAlpha;
|
|
7690
8694
|
exports.copyToClipboard = copyToClipboard;
|
|
7691
8695
|
exports.createFormStore = createFormStore;
|
|
7692
8696
|
exports.createScriptConfig = createScriptConfig;
|
|
7693
8697
|
exports.createSkill = createSkill;
|
|
8698
|
+
exports.dirkQueryClient = dirkQueryClient;
|
|
8699
|
+
exports.ensureFrameworkGroups = ensureFrameworkGroups;
|
|
7694
8700
|
exports.extractDefaults = extractDefaults;
|
|
7695
8701
|
exports.fetchLuaTable = fetchLuaTable;
|
|
7696
8702
|
exports.fetchNui = fetchNui;
|
|
7697
8703
|
exports.formatGtaControl = formatGtaControl;
|
|
7698
8704
|
exports.gameToMap = gameToMap;
|
|
8705
|
+
exports.getBlipColor = getBlipColor;
|
|
8706
|
+
exports.getBlipEntry = getBlipEntry;
|
|
7699
8707
|
exports.getGtaControl = getGtaControl;
|
|
7700
8708
|
exports.getImageShape = getImageShape;
|
|
7701
8709
|
exports.getItemImageUrl = getItemImageUrl;
|
|
@@ -7719,6 +8727,8 @@ exports.selectAllGroups = selectAllGroups;
|
|
|
7719
8727
|
exports.splitFAString = splitFAString;
|
|
7720
8728
|
exports.updatePresignedURL = updatePresignedURL;
|
|
7721
8729
|
exports.uploadImage = uploadImage;
|
|
8730
|
+
exports.useAdminState = useAdminState;
|
|
8731
|
+
exports.useAdminToolStore = useAdminToolStore;
|
|
7722
8732
|
exports.useAudio = useAudio;
|
|
7723
8733
|
exports.useAutoFetcher = useAutoFetcher;
|
|
7724
8734
|
exports.useForm = useForm;
|
|
@@ -7736,8 +8746,11 @@ exports.useModalActions = useModalActions;
|
|
|
7736
8746
|
exports.useNavigation = useNavigation;
|
|
7737
8747
|
exports.useNavigationStore = useNavigationStore;
|
|
7738
8748
|
exports.useNuiEvent = useNuiEvent;
|
|
8749
|
+
exports.usePickDoor = usePickDoor;
|
|
8750
|
+
exports.usePlayers = usePlayers;
|
|
7739
8751
|
exports.useProfanityStore = useProfanityStore;
|
|
7740
8752
|
exports.useSettings = useSettings;
|
|
7741
8753
|
exports.useTornEdges = useTornEdges;
|
|
8754
|
+
exports.useValidModels = useValidModels;
|
|
7742
8755
|
//# sourceMappingURL=index.cjs.map
|
|
7743
8756
|
//# sourceMappingURL=index.cjs.map
|