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
|
@@ -11,7 +11,22 @@ var clickSoundUrl = require('../click_sound-PNCRRTM4.mp3');
|
|
|
11
11
|
var hoverSoundUrl = require('../hover_sound-NBUA222C.mp3');
|
|
12
12
|
var notifications = require('@mantine/notifications');
|
|
13
13
|
var reactQuery = require('@tanstack/react-query');
|
|
14
|
+
require('@mantine/core/styles.css');
|
|
15
|
+
require('@mantine/notifications/styles.css');
|
|
16
|
+
require('./styles/fonts.css');
|
|
17
|
+
require('./styles/notify.css');
|
|
18
|
+
require('./styles/scrollBar.css');
|
|
19
|
+
require('./styles/tornEdge.css');
|
|
20
|
+
var fontawesomeSvgCore = require('@fortawesome/fontawesome-svg-core');
|
|
21
|
+
var freeBrandsSvgIcons = require('@fortawesome/free-brands-svg-icons');
|
|
22
|
+
var freeRegularSvgIcons = require('@fortawesome/free-regular-svg-icons');
|
|
23
|
+
var freeSolidSvgIcons = require('@fortawesome/free-solid-svg-icons');
|
|
14
24
|
var colorsGenerator = require('@mantine/colors-generator');
|
|
25
|
+
var reactDom = require('react-dom');
|
|
26
|
+
var leaflet = require('leaflet');
|
|
27
|
+
require('leaflet/dist/leaflet.css');
|
|
28
|
+
var reactLeaflet = require('react-leaflet');
|
|
29
|
+
var reactLeafletComponentMarker = require('@adamscybot/react-leaflet-component-marker');
|
|
15
30
|
|
|
16
31
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
32
|
|
|
@@ -960,6 +975,18 @@ var BLIP_COLOR_DATA = BLIP_COLORS.map(([id, label]) => ({
|
|
|
960
975
|
}));
|
|
961
976
|
var blipEntryMap = new Map(BLIP_ENTRIES.map(([id, name, ext]) => [String(id), { id, name, ext }]));
|
|
962
977
|
var blipColorMap = new Map(BLIP_COLORS.map(([id, label, hex]) => [String(id), { id, label, hex }]));
|
|
978
|
+
function getBlipEntry(spriteId) {
|
|
979
|
+
if (spriteId == null) return void 0;
|
|
980
|
+
return blipEntryMap.get(String(spriteId));
|
|
981
|
+
}
|
|
982
|
+
function getBlipColor(colorId) {
|
|
983
|
+
if (colorId == null) return void 0;
|
|
984
|
+
return blipColorMap.get(String(colorId));
|
|
985
|
+
}
|
|
986
|
+
function blipUrlForSprite(spriteId) {
|
|
987
|
+
const entry = getBlipEntry(spriteId);
|
|
988
|
+
return entry ? blipUrl(entry.name, entry.ext) : null;
|
|
989
|
+
}
|
|
963
990
|
var renderBlipOption = ({ option }) => {
|
|
964
991
|
const entry = blipEntryMap.get(option.value);
|
|
965
992
|
if (!entry) return option.label;
|
|
@@ -1237,11 +1264,11 @@ var colorNames = {
|
|
|
1237
1264
|
Yellow: { r: 255, g: 255, b: 0 },
|
|
1238
1265
|
YellowGreen: { r: 154, g: 205, b: 50 }
|
|
1239
1266
|
};
|
|
1240
|
-
function colorWithAlpha(color,
|
|
1267
|
+
function colorWithAlpha(color, alpha17) {
|
|
1241
1268
|
const lowerCasedColor = color.toLowerCase();
|
|
1242
1269
|
if (colorNames[lowerCasedColor]) {
|
|
1243
1270
|
const rgb = colorNames[lowerCasedColor];
|
|
1244
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${
|
|
1271
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha17})`;
|
|
1245
1272
|
}
|
|
1246
1273
|
if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
|
|
1247
1274
|
const hex = color.slice(1);
|
|
@@ -1249,12 +1276,12 @@ function colorWithAlpha(color, alpha12) {
|
|
|
1249
1276
|
const r = bigint >> 16 & 255;
|
|
1250
1277
|
const g = bigint >> 8 & 255;
|
|
1251
1278
|
const b = bigint & 255;
|
|
1252
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
1279
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha17})`;
|
|
1253
1280
|
}
|
|
1254
1281
|
if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
|
|
1255
1282
|
const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
|
|
1256
1283
|
if (result) {
|
|
1257
|
-
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${
|
|
1284
|
+
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha17})`;
|
|
1258
1285
|
}
|
|
1259
1286
|
}
|
|
1260
1287
|
return color;
|
|
@@ -1323,11 +1350,35 @@ function reportMissingLocale(key) {
|
|
|
1323
1350
|
fetchNui("REPORT_MISSING_LOCALE", { key }).catch(() => {
|
|
1324
1351
|
});
|
|
1325
1352
|
}
|
|
1353
|
+
var PACKAGE_DEFAULTS = {
|
|
1354
|
+
"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.",
|
|
1355
|
+
"cfgpanel_discard": "Discard",
|
|
1356
|
+
"cfgpanel_manual_edit": "Manual Edit",
|
|
1357
|
+
"cfgpanel_reset_defaults": "Reset Defaults",
|
|
1358
|
+
"cfgpanel_version": "Version",
|
|
1359
|
+
"cfgpanel_back_title": "Back to script list",
|
|
1360
|
+
"cfgpanel_undo": "Undo",
|
|
1361
|
+
"cfgpanel_redo": "Redo",
|
|
1362
|
+
"cfgpanel_save": "Save",
|
|
1363
|
+
"cfgpanel_saving": "Saving...",
|
|
1364
|
+
"cfgpanel_history": "History",
|
|
1365
|
+
"cfgpanel_reset_title": "Reset to Defaults",
|
|
1366
|
+
"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.",
|
|
1367
|
+
"cfgpanel_reset_confirm": "Reset Config",
|
|
1368
|
+
"cfgpanel_discard_title": "Discard Unsaved Changes?",
|
|
1369
|
+
"cfgpanel_discard_desc_back": "You have unsaved changes. Going back now will discard them.",
|
|
1370
|
+
"cfgpanel_discard_desc_close": "You have unsaved changes. Closing now will discard them.",
|
|
1371
|
+
"cfgpanel_discard_confirm_back": "Go Back Without Saving",
|
|
1372
|
+
"cfgpanel_discard_confirm_close": "Close Without Saving",
|
|
1373
|
+
"cfgpanel_json_title": "Config JSON",
|
|
1374
|
+
"cfgpanel_cancel": "Cancel",
|
|
1375
|
+
"cfgpanel_apply": "Apply",
|
|
1376
|
+
"cfgpanel_history_title": "Config History",
|
|
1377
|
+
"cfgpanel_close": "Close"
|
|
1378
|
+
};
|
|
1326
1379
|
var localeStore = zustand.create((set, get) => {
|
|
1327
1380
|
return {
|
|
1328
|
-
locales: {
|
|
1329
|
-
"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."
|
|
1330
|
-
},
|
|
1381
|
+
locales: { ...PACKAGE_DEFAULTS },
|
|
1331
1382
|
locale: (key, ...args) => {
|
|
1332
1383
|
const exists = get().locales[key];
|
|
1333
1384
|
if (!exists) reportMissingLocale(key);
|
|
@@ -1341,7 +1392,7 @@ var localeStore = zustand.create((set, get) => {
|
|
|
1341
1392
|
});
|
|
1342
1393
|
var locale = localeStore.getState().locale;
|
|
1343
1394
|
registerInitialFetch("GET_LOCALES", void 0).then((data) => {
|
|
1344
|
-
localeStore.setState({ locales: data });
|
|
1395
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...data } });
|
|
1345
1396
|
}).catch(() => {
|
|
1346
1397
|
});
|
|
1347
1398
|
if (typeof window !== "undefined") {
|
|
@@ -1349,9 +1400,22 @@ if (typeof window !== "undefined") {
|
|
|
1349
1400
|
const msg = event.data;
|
|
1350
1401
|
if (!msg || msg.action !== "UPDATE_DIRK_LIB_LOCALES") return;
|
|
1351
1402
|
if (!msg.data || typeof msg.data !== "object") return;
|
|
1352
|
-
|
|
1403
|
+
if (Object.keys(msg.data).length === 0) return;
|
|
1404
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...msg.data } });
|
|
1353
1405
|
});
|
|
1354
1406
|
}
|
|
1407
|
+
|
|
1408
|
+
// src/utils/map.ts
|
|
1409
|
+
var mapCenter = [-119.43, 58.84];
|
|
1410
|
+
var latPr100 = 1.421;
|
|
1411
|
+
function gameToMap(x, y) {
|
|
1412
|
+
return [
|
|
1413
|
+
mapCenter[0] + latPr100 / 100 * y,
|
|
1414
|
+
// lng
|
|
1415
|
+
mapCenter[1] + latPr100 / 100 * x
|
|
1416
|
+
// lat
|
|
1417
|
+
];
|
|
1418
|
+
}
|
|
1355
1419
|
var useItems = zustand.create(() => ({}));
|
|
1356
1420
|
var useItemsList = (excludeItemNames = []) => {
|
|
1357
1421
|
const excludeSet = new Set(excludeItemNames);
|
|
@@ -1371,15 +1435,21 @@ var useFrameworkGroups = zustand.create(() => ({
|
|
|
1371
1435
|
gangs: [],
|
|
1372
1436
|
loaded: false
|
|
1373
1437
|
}));
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1438
|
+
var frameworkGroupsRequested = false;
|
|
1439
|
+
function ensureFrameworkGroups() {
|
|
1440
|
+
if (frameworkGroupsRequested) return;
|
|
1441
|
+
frameworkGroupsRequested = true;
|
|
1442
|
+
fetchNui("GET_FRAMEWORK_GROUPS", void 0).then((data) => {
|
|
1443
|
+
useFrameworkGroups.setState({
|
|
1444
|
+
jobs: Array.isArray(data?.jobs) ? data.jobs : [],
|
|
1445
|
+
gangs: Array.isArray(data?.gangs) ? data.gangs : [],
|
|
1446
|
+
loaded: true
|
|
1447
|
+
});
|
|
1448
|
+
}).catch(() => {
|
|
1449
|
+
frameworkGroupsRequested = false;
|
|
1450
|
+
useFrameworkGroups.setState({ loaded: true });
|
|
1379
1451
|
});
|
|
1380
|
-
}
|
|
1381
|
-
useFrameworkGroups.setState({ loaded: true });
|
|
1382
|
-
});
|
|
1452
|
+
}
|
|
1383
1453
|
|
|
1384
1454
|
// src/utils/inputMapper.ts
|
|
1385
1455
|
var INPUT_MAPPER_PRIMARY_OPTIONS = [
|
|
@@ -2388,7 +2458,7 @@ function NavigationProvider({ children, defaultPage }) {
|
|
|
2388
2458
|
}
|
|
2389
2459
|
function NavBar(props) {
|
|
2390
2460
|
const pageId = useNavigation((state) => state.pageId);
|
|
2391
|
-
const
|
|
2461
|
+
const store2 = useNavigationStore();
|
|
2392
2462
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2393
2463
|
SegmentedControl,
|
|
2394
2464
|
{
|
|
@@ -2397,7 +2467,7 @@ function NavBar(props) {
|
|
|
2397
2467
|
value: pageId,
|
|
2398
2468
|
items: props.items,
|
|
2399
2469
|
onChange: (value) => {
|
|
2400
|
-
|
|
2470
|
+
store2.setState({ pageId: value });
|
|
2401
2471
|
}
|
|
2402
2472
|
}
|
|
2403
2473
|
);
|
|
@@ -3704,34 +3774,82 @@ function FormProvider({
|
|
|
3704
3774
|
return /* @__PURE__ */ jsxRuntime.jsx(FormContext.Provider, { value: storeRef.current, children });
|
|
3705
3775
|
}
|
|
3706
3776
|
function useForm() {
|
|
3707
|
-
const
|
|
3708
|
-
if (!
|
|
3777
|
+
const store2 = react.useContext(FormContext);
|
|
3778
|
+
if (!store2) {
|
|
3709
3779
|
throw new Error("useForm must be used inside <FormProvider>");
|
|
3710
3780
|
}
|
|
3711
|
-
const state = zustand.useStore(
|
|
3781
|
+
const state = zustand.useStore(store2);
|
|
3712
3782
|
const changedFields = react.useMemo(() => {
|
|
3713
3783
|
return collectChangedPaths(state.values, state.initialValues);
|
|
3714
3784
|
}, [state.values, state.initialValues]);
|
|
3715
3785
|
return { ...state, changedFields, changedCount: changedFields.length };
|
|
3716
3786
|
}
|
|
3717
3787
|
function useFormField(path) {
|
|
3718
|
-
const
|
|
3719
|
-
if (!
|
|
3788
|
+
const store2 = react.useContext(FormContext);
|
|
3789
|
+
if (!store2) {
|
|
3720
3790
|
throw new Error("useFormField must be used inside <FormProvider>");
|
|
3721
3791
|
}
|
|
3722
|
-
return zustand.useStore(
|
|
3792
|
+
return zustand.useStore(store2, (s) => getNested(s.values, path));
|
|
3723
3793
|
}
|
|
3724
3794
|
function useFormActions() {
|
|
3725
|
-
const
|
|
3726
|
-
if (!
|
|
3795
|
+
const store2 = react.useContext(FormContext);
|
|
3796
|
+
if (!store2) {
|
|
3727
3797
|
throw new Error("useFormActions must be used inside <FormProvider>");
|
|
3728
3798
|
}
|
|
3729
|
-
return
|
|
3799
|
+
return store2.getState();
|
|
3800
|
+
}
|
|
3801
|
+
var store = /* @__PURE__ */ new Map();
|
|
3802
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
3803
|
+
function notify(key) {
|
|
3804
|
+
const ls = listeners.get(key);
|
|
3805
|
+
if (!ls) return;
|
|
3806
|
+
ls.forEach((fn) => fn());
|
|
3807
|
+
}
|
|
3808
|
+
function useAdminState(key, initial) {
|
|
3809
|
+
const [, setTick] = react.useState(0);
|
|
3810
|
+
react.useEffect(() => {
|
|
3811
|
+
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
3812
|
+
listeners.set(key, set);
|
|
3813
|
+
const handler = () => setTick((t3) => t3 + 1);
|
|
3814
|
+
set.add(handler);
|
|
3815
|
+
return () => {
|
|
3816
|
+
set.delete(handler);
|
|
3817
|
+
if (set.size === 0) listeners.delete(key);
|
|
3818
|
+
};
|
|
3819
|
+
}, [key]);
|
|
3820
|
+
const value = store.has(key) ? store.get(key) : initial;
|
|
3821
|
+
const setValue = (v) => {
|
|
3822
|
+
const next = typeof v === "function" ? v(value) : v;
|
|
3823
|
+
store.set(key, next);
|
|
3824
|
+
notify(key);
|
|
3825
|
+
};
|
|
3826
|
+
return [value, setValue];
|
|
3730
3827
|
}
|
|
3731
3828
|
function getScriptConfigInstance() {
|
|
3732
3829
|
throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
|
|
3733
3830
|
}
|
|
3734
|
-
var
|
|
3831
|
+
var useAdminToolStore = zustand.create((set, get) => ({
|
|
3832
|
+
active: null,
|
|
3833
|
+
begin: (spec) => new Promise((resolve) => {
|
|
3834
|
+
const prev = get().active;
|
|
3835
|
+
if (prev) prev.resolve(null);
|
|
3836
|
+
set({ active: { ...spec, resolve } });
|
|
3837
|
+
}),
|
|
3838
|
+
resolveActive: (value) => {
|
|
3839
|
+
const cur = get().active;
|
|
3840
|
+
if (!cur) return;
|
|
3841
|
+
cur.resolve(value);
|
|
3842
|
+
set({ active: null });
|
|
3843
|
+
},
|
|
3844
|
+
cancelActive: () => {
|
|
3845
|
+
const cur = get().active;
|
|
3846
|
+
if (!cur) return;
|
|
3847
|
+
cur.resolve(null);
|
|
3848
|
+
set({ active: null });
|
|
3849
|
+
}
|
|
3850
|
+
}));
|
|
3851
|
+
fontawesomeSvgCore.library.add(freeSolidSvgIcons.fas, freeRegularSvgIcons.far, freeBrandsSvgIcons.fab);
|
|
3852
|
+
var dirkQueryClient = new reactQuery.QueryClient({
|
|
3735
3853
|
defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
|
|
3736
3854
|
});
|
|
3737
3855
|
function NavItemButton({
|
|
@@ -3812,7 +3930,7 @@ function ConfigJsonModal({
|
|
|
3812
3930
|
setError(e.message);
|
|
3813
3931
|
}
|
|
3814
3932
|
};
|
|
3815
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "
|
|
3933
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: locale("cfgpanel_json_title"), icon: lucideReact.Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
|
|
3816
3934
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
|
|
3817
3935
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3818
3936
|
core.JsonInput,
|
|
@@ -3840,7 +3958,7 @@ function ConfigJsonModal({
|
|
|
3840
3958
|
style: { background: "transparent", border: `0.1vh solid ${theme.colors.dark[6]}`, borderRadius: theme.radius.xs, padding: `${theme.spacing.xxs} ${theme.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme.spacing.xxs },
|
|
3841
3959
|
children: [
|
|
3842
3960
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { color: "rgba(255,255,255,0.4)" }),
|
|
3843
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
3961
|
+
/* @__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") })
|
|
3844
3962
|
]
|
|
3845
3963
|
}
|
|
3846
3964
|
),
|
|
@@ -3853,7 +3971,7 @@ function ConfigJsonModal({
|
|
|
3853
3971
|
style: { background: core.alpha(color, 0.14), border: `0.1vh solid ${core.alpha(color, 0.4)}`, borderRadius: theme.radius.xs, padding: `${theme.spacing.xxs} ${theme.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme.spacing.xxs },
|
|
3854
3972
|
children: [
|
|
3855
3973
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { color }),
|
|
3856
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: "
|
|
3974
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: locale("cfgpanel_apply") })
|
|
3857
3975
|
]
|
|
3858
3976
|
}
|
|
3859
3977
|
)
|
|
@@ -3994,7 +4112,7 @@ function ConfigHistoryModal({
|
|
|
3994
4112
|
historyQuery.fetchNextPage();
|
|
3995
4113
|
}
|
|
3996
4114
|
};
|
|
3997
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: "
|
|
4115
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { title: locale("cfgpanel_history_title"), icon: lucideReact.History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
|
|
3998
4116
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
|
|
3999
4117
|
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${core.alpha(theme.colors.dark[7], 0.8)}` }, children: [
|
|
4000
4118
|
/* @__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 } }),
|
|
@@ -4037,7 +4155,7 @@ function ConfigHistoryModal({
|
|
|
4037
4155
|
style: { background: "transparent", border: `0.1vh solid ${theme.colors.dark[6]}`, borderRadius: theme.radius.xs, padding: `${theme.spacing.xxs} ${theme.spacing.xs}`, cursor: "pointer", display: "flex", alignItems: "center", gap: theme.spacing.xxs },
|
|
4038
4156
|
children: [
|
|
4039
4157
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { color: "rgba(255,255,255,0.4)", size: "1.5vh" }),
|
|
4040
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
4158
|
+
/* @__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") })
|
|
4041
4159
|
]
|
|
4042
4160
|
}
|
|
4043
4161
|
) })
|
|
@@ -4062,7 +4180,7 @@ function ConfigPanelInner({
|
|
|
4062
4180
|
const theme = core.useMantineTheme();
|
|
4063
4181
|
const color = theme.colors[theme.primaryColor][5];
|
|
4064
4182
|
const version = useSettings((s) => s.resourceVersion);
|
|
4065
|
-
const [activeTab, setActiveTab] =
|
|
4183
|
+
const [activeTab, setActiveTab] = useAdminState("__dirkConfigPanel:activeTab", navItems[0]?.id ?? "");
|
|
4066
4184
|
const firstMountRef = react.useRef(true);
|
|
4067
4185
|
const [jsonOpen, setJsonOpen] = react.useState(false);
|
|
4068
4186
|
const [historyOpen, setHistoryOpen] = react.useState(false);
|
|
@@ -4097,16 +4215,16 @@ function ConfigPanelInner({
|
|
|
4097
4215
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4098
4216
|
ConfirmModal,
|
|
4099
4217
|
{
|
|
4100
|
-
title: "
|
|
4101
|
-
description: "
|
|
4102
|
-
confirmLabel: "
|
|
4218
|
+
title: locale("cfgpanel_reset_title"),
|
|
4219
|
+
description: locale("cfgpanel_reset_desc"),
|
|
4220
|
+
confirmLabel: locale("cfgpanel_reset_confirm"),
|
|
4103
4221
|
confirmText: resetConfirmText,
|
|
4104
4222
|
onConfirm: async () => {
|
|
4105
4223
|
setResetOpen(false);
|
|
4106
4224
|
const result = await resetConfig();
|
|
4107
4225
|
if (result?.success) {
|
|
4108
|
-
const { store } = getScriptConfigInstance();
|
|
4109
|
-
form.reinitialize(cloneConfig(
|
|
4226
|
+
const { store: store2 } = getScriptConfigInstance();
|
|
4227
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
4110
4228
|
notifications.notifications.show({
|
|
4111
4229
|
color: "green",
|
|
4112
4230
|
title: locale("ConfigResetSuccessTitle"),
|
|
@@ -4131,9 +4249,9 @@ function ConfigPanelInner({
|
|
|
4131
4249
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: pendingAction !== null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4132
4250
|
ConfirmModal,
|
|
4133
4251
|
{
|
|
4134
|
-
title: "
|
|
4135
|
-
description: pendingAction === "back" ? "
|
|
4136
|
-
confirmLabel: pendingAction === "back" ? "
|
|
4252
|
+
title: locale("cfgpanel_discard_title"),
|
|
4253
|
+
description: pendingAction === "back" ? locale("cfgpanel_discard_desc_back") : locale("cfgpanel_discard_desc_close"),
|
|
4254
|
+
confirmLabel: pendingAction === "back" ? locale("cfgpanel_discard_confirm_back") : locale("cfgpanel_discard_confirm_close"),
|
|
4137
4255
|
onConfirm: () => {
|
|
4138
4256
|
const action = pendingAction;
|
|
4139
4257
|
setPendingAction(null);
|
|
@@ -4171,7 +4289,7 @@ function ConfigPanelInner({
|
|
|
4171
4289
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4172
4290
|
framerMotion.motion.button,
|
|
4173
4291
|
{
|
|
4174
|
-
title: "
|
|
4292
|
+
title: locale("cfgpanel_back_title"),
|
|
4175
4293
|
onClick: handleBack,
|
|
4176
4294
|
whileHover: { background: core.alpha(color, 0.16), borderColor: core.alpha(color, 0.45) },
|
|
4177
4295
|
whileTap: { scale: 0.95 },
|
|
@@ -4199,7 +4317,7 @@ function ConfigPanelInner({
|
|
|
4199
4317
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4200
4318
|
framerMotion.motion.button,
|
|
4201
4319
|
{
|
|
4202
|
-
title: "
|
|
4320
|
+
title: locale("cfgpanel_undo"),
|
|
4203
4321
|
onClick: () => form.canBack && form.back(),
|
|
4204
4322
|
disabled: !form.canBack,
|
|
4205
4323
|
whileHover: form.canBack ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4211,7 +4329,7 @@ function ConfigPanelInner({
|
|
|
4211
4329
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4212
4330
|
framerMotion.motion.button,
|
|
4213
4331
|
{
|
|
4214
|
-
title: "
|
|
4332
|
+
title: locale("cfgpanel_redo"),
|
|
4215
4333
|
onClick: () => form.canForward && form.forward(),
|
|
4216
4334
|
disabled: !form.canForward,
|
|
4217
4335
|
whileHover: form.canForward ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4223,7 +4341,7 @@ function ConfigPanelInner({
|
|
|
4223
4341
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4224
4342
|
framerMotion.motion.button,
|
|
4225
4343
|
{
|
|
4226
|
-
title: isSaving ? "
|
|
4344
|
+
title: isSaving ? locale("cfgpanel_saving") : isDirty ? `${locale("cfgpanel_save")} (${changedCount})` : locale("cfgpanel_save"),
|
|
4227
4345
|
onClick: () => isDirty && !isSaving && form.submit(),
|
|
4228
4346
|
disabled: !isDirty || isSaving,
|
|
4229
4347
|
whileHover: isDirty && !isSaving ? { background: core.alpha(color, 0.25), borderColor: core.alpha(color, 0.5) } : void 0,
|
|
@@ -4235,7 +4353,7 @@ function ConfigPanelInner({
|
|
|
4235
4353
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4236
4354
|
framerMotion.motion.button,
|
|
4237
4355
|
{
|
|
4238
|
-
title: "
|
|
4356
|
+
title: locale("cfgpanel_history"),
|
|
4239
4357
|
onClick: () => setHistoryOpen(true),
|
|
4240
4358
|
whileHover: { background: core.alpha("#22d3ee", 0.16), borderColor: core.alpha("#22d3ee", 0.5) },
|
|
4241
4359
|
whileTap: { scale: 0.97 },
|
|
@@ -4256,7 +4374,7 @@ function ConfigPanelInner({
|
|
|
4256
4374
|
style: { width: "100%", background: "transparent", border: `0.1vh solid ${isDirty ? core.alpha("#f97316", 0.35) : core.alpha(theme.colors.dark[5], 0.3)}`, borderRadius: theme.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" },
|
|
4257
4375
|
children: [
|
|
4258
4376
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { color: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", size: "1.6vh" }),
|
|
4259
|
-
/* @__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: "
|
|
4377
|
+
/* @__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") })
|
|
4260
4378
|
]
|
|
4261
4379
|
}
|
|
4262
4380
|
),
|
|
@@ -4270,7 +4388,7 @@ function ConfigPanelInner({
|
|
|
4270
4388
|
style: { width: "100%", background: core.alpha(color, 0.07), border: `0.1vh solid ${core.alpha(color, 0.28)}`, borderRadius: theme.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
4271
4389
|
children: [
|
|
4272
4390
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { color, size: "1.6vh" }),
|
|
4273
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: "
|
|
4391
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("cfgpanel_manual_edit") })
|
|
4274
4392
|
]
|
|
4275
4393
|
}
|
|
4276
4394
|
),
|
|
@@ -4283,12 +4401,13 @@ function ConfigPanelInner({
|
|
|
4283
4401
|
style: { width: "100%", background: core.alpha("#ef4444", 0.07), border: `0.1vh solid ${core.alpha("#ef4444", 0.25)}`, borderRadius: theme.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
4284
4402
|
children: [
|
|
4285
4403
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { color: "#ef4444", size: "1.6vh" }),
|
|
4286
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: "
|
|
4404
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: locale("cfgpanel_reset_defaults") })
|
|
4287
4405
|
]
|
|
4288
4406
|
}
|
|
4289
4407
|
),
|
|
4290
4408
|
version && /* @__PURE__ */ jsxRuntime.jsxs(core.Text, { size: "0.95vh", c: "dimmed", ta: "center", style: { letterSpacing: "0.04em", opacity: 0.8 }, children: [
|
|
4291
|
-
"
|
|
4409
|
+
locale("cfgpanel_version"),
|
|
4410
|
+
" ",
|
|
4292
4411
|
version
|
|
4293
4412
|
] })
|
|
4294
4413
|
] })
|
|
@@ -4334,13 +4453,13 @@ function ServerOnlyFetcher() {
|
|
|
4334
4453
|
var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
|
|
4335
4454
|
function ConfigPanel(props) {
|
|
4336
4455
|
const { open, onClose = defaultOnClose } = props;
|
|
4337
|
-
const { store, updateConfig } = getScriptConfigInstance();
|
|
4456
|
+
const { store: store2, updateConfig } = getScriptConfigInstance();
|
|
4338
4457
|
const [isSaving, setIsSaving] = react.useState(false);
|
|
4339
4458
|
if (!open) return null;
|
|
4340
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4459
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4341
4460
|
FormProvider,
|
|
4342
4461
|
{
|
|
4343
|
-
initialValues: cloneConfig(
|
|
4462
|
+
initialValues: cloneConfig(store2.getState()),
|
|
4344
4463
|
onSubmit: async (form) => {
|
|
4345
4464
|
if (isSaving) return;
|
|
4346
4465
|
setIsSaving(true);
|
|
@@ -4348,7 +4467,7 @@ function ConfigPanel(props) {
|
|
|
4348
4467
|
const result = await updateConfig(form.values);
|
|
4349
4468
|
if (result?.success) {
|
|
4350
4469
|
form.reinitialize(cloneConfig(form.values));
|
|
4351
|
-
|
|
4470
|
+
dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
|
|
4352
4471
|
useMissingItemsAudit.getState().refresh();
|
|
4353
4472
|
notifications.notifications.show({
|
|
4354
4473
|
color: "green",
|
|
@@ -4358,7 +4477,7 @@ function ConfigPanel(props) {
|
|
|
4358
4477
|
});
|
|
4359
4478
|
return;
|
|
4360
4479
|
}
|
|
4361
|
-
form.reinitialize(cloneConfig(
|
|
4480
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
4362
4481
|
const err = result?._error || "Unknown";
|
|
4363
4482
|
console.warn(`[ConfigPanel] config save failed: ${err}`);
|
|
4364
4483
|
const titleKey = err === "NoPermission" ? "ConfigSaveNoPermissionTitle" : err === "VersionConflict" ? "ConfigSaveVersionConflictTitle" : err === "NotReady" ? "ConfigSaveNotReadyTitle" : "ConfigSaveFailedTitle";
|
|
@@ -4855,6 +4974,9 @@ function GroupName(props) {
|
|
|
4855
4974
|
const ctx = react.useContext(GroupSelectContext);
|
|
4856
4975
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
4857
4976
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
4977
|
+
react.useEffect(() => {
|
|
4978
|
+
ensureFrameworkGroups();
|
|
4979
|
+
}, []);
|
|
4858
4980
|
const inCompound = ctx !== null;
|
|
4859
4981
|
const currentValue = inCompound ? ctx.value.name : props.value;
|
|
4860
4982
|
const filterType = inCompound ? ctx.type : props.type;
|
|
@@ -4894,6 +5016,9 @@ function GroupRank(props) {
|
|
|
4894
5016
|
}
|
|
4895
5017
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
4896
5018
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
5019
|
+
react.useEffect(() => {
|
|
5020
|
+
ensureFrameworkGroups();
|
|
5021
|
+
}, []);
|
|
4897
5022
|
const all = [...jobs, ...gangs];
|
|
4898
5023
|
const selectedGroup = all.find((g) => g.name === ctx.value.name) ?? null;
|
|
4899
5024
|
const grades = selectedGroup?.grades ?? [];
|
|
@@ -6539,6 +6664,732 @@ function AccountSelect(props) {
|
|
|
6539
6664
|
!hideFrameworkHint && /* @__PURE__ */ jsxRuntime.jsx(FrameworkHint, { framework })
|
|
6540
6665
|
] });
|
|
6541
6666
|
}
|
|
6667
|
+
var BODY_HIDE_STYLE_ID = "dirk-instruction-panel-style";
|
|
6668
|
+
var BODY_HIDE_ATTR = "data-dirk-instruction-active";
|
|
6669
|
+
var OVERLAY_ATTR = "data-dirk-instruction-overlay";
|
|
6670
|
+
function ensureBodyHideStyle() {
|
|
6671
|
+
if (document.getElementById(BODY_HIDE_STYLE_ID)) return;
|
|
6672
|
+
const el = document.createElement("style");
|
|
6673
|
+
el.id = BODY_HIDE_STYLE_ID;
|
|
6674
|
+
el.textContent = `
|
|
6675
|
+
body[${BODY_HIDE_ATTR}] > *:not([${OVERLAY_ATTR}]) {
|
|
6676
|
+
visibility: hidden !important;
|
|
6677
|
+
opacity: 0 !important;
|
|
6678
|
+
pointer-events: none !important;
|
|
6679
|
+
}
|
|
6680
|
+
`;
|
|
6681
|
+
document.head.appendChild(el);
|
|
6682
|
+
}
|
|
6683
|
+
function InstructionPanel({
|
|
6684
|
+
visible,
|
|
6685
|
+
title,
|
|
6686
|
+
hint,
|
|
6687
|
+
keys,
|
|
6688
|
+
icon: Icon = lucideReact.MapPin,
|
|
6689
|
+
hideRestOfAdmin = true
|
|
6690
|
+
}) {
|
|
6691
|
+
const theme = core.useMantineTheme();
|
|
6692
|
+
const pc = theme.colors[theme.primaryColor];
|
|
6693
|
+
react.useEffect(() => {
|
|
6694
|
+
if (!visible || !hideRestOfAdmin) return;
|
|
6695
|
+
ensureBodyHideStyle();
|
|
6696
|
+
document.body.setAttribute(BODY_HIDE_ATTR, "");
|
|
6697
|
+
return () => {
|
|
6698
|
+
document.body.removeAttribute(BODY_HIDE_ATTR);
|
|
6699
|
+
};
|
|
6700
|
+
}, [visible, hideRestOfAdmin]);
|
|
6701
|
+
if (!visible) return null;
|
|
6702
|
+
return reactDom.createPortal(
|
|
6703
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6704
|
+
"div",
|
|
6705
|
+
{
|
|
6706
|
+
...{ [OVERLAY_ATTR]: "" },
|
|
6707
|
+
style: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: 1e4 },
|
|
6708
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6709
|
+
framerMotion.motion.div,
|
|
6710
|
+
{
|
|
6711
|
+
initial: { opacity: 0, y: 12, scale: 0.92 },
|
|
6712
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
6713
|
+
exit: { opacity: 0, y: 12, scale: 0.92 },
|
|
6714
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
6715
|
+
style: { position: "absolute", bottom: "3vh", right: "3vh", userSelect: "none" },
|
|
6716
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6717
|
+
core.Flex,
|
|
6718
|
+
{
|
|
6719
|
+
direction: "column",
|
|
6720
|
+
gap: "0.8vh",
|
|
6721
|
+
style: {
|
|
6722
|
+
background: core.alpha(theme.colors.dark[9], 0.55),
|
|
6723
|
+
border: "0.1vh solid rgba(255,255,255,0.07)",
|
|
6724
|
+
borderRadius: theme.radius.sm,
|
|
6725
|
+
boxShadow: "0 0.74vh 2.96vh rgba(0,0,0,0.5)",
|
|
6726
|
+
padding: "1.4vh 1.6vh",
|
|
6727
|
+
minWidth: "22vh",
|
|
6728
|
+
maxWidth: "28vh"
|
|
6729
|
+
},
|
|
6730
|
+
children: [
|
|
6731
|
+
/* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
|
|
6732
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.6vh", color: pc[6], strokeWidth: 2.5 }),
|
|
6733
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6734
|
+
core.Text,
|
|
6735
|
+
{
|
|
6736
|
+
style: {
|
|
6737
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6738
|
+
fontSize: "1.7vh",
|
|
6739
|
+
fontWeight: 700,
|
|
6740
|
+
letterSpacing: "0.14em",
|
|
6741
|
+
textTransform: "uppercase",
|
|
6742
|
+
color: pc[6],
|
|
6743
|
+
textShadow: `0 0 0.8vh ${core.alpha(pc[7], 0.5)}, 0 0 1.6vh ${core.alpha(pc[9], 0.3)}`
|
|
6744
|
+
},
|
|
6745
|
+
children: title
|
|
6746
|
+
}
|
|
6747
|
+
)
|
|
6748
|
+
] }),
|
|
6749
|
+
(hint || keys && keys.length > 0) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
6750
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6751
|
+
core.Text,
|
|
6752
|
+
{
|
|
6753
|
+
style: {
|
|
6754
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6755
|
+
fontSize: "1.05vh",
|
|
6756
|
+
color: "rgba(255,255,255,0.45)",
|
|
6757
|
+
letterSpacing: "0.06em",
|
|
6758
|
+
textTransform: "uppercase",
|
|
6759
|
+
lineHeight: 1.4
|
|
6760
|
+
},
|
|
6761
|
+
children: hint
|
|
6762
|
+
}
|
|
6763
|
+
),
|
|
6764
|
+
keys && keys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6765
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
6766
|
+
/* @__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)) })
|
|
6767
|
+
] })
|
|
6768
|
+
]
|
|
6769
|
+
}
|
|
6770
|
+
)
|
|
6771
|
+
},
|
|
6772
|
+
"instruction-card"
|
|
6773
|
+
) })
|
|
6774
|
+
}
|
|
6775
|
+
),
|
|
6776
|
+
document.body
|
|
6777
|
+
);
|
|
6778
|
+
}
|
|
6779
|
+
function renderKeyContent(keyLabel) {
|
|
6780
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
6781
|
+
if (normalized === "LMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "left" });
|
|
6782
|
+
if (normalized === "RMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "right" });
|
|
6783
|
+
if (normalized === "BACKSPACE" || keyLabel === "\u232B") return /* @__PURE__ */ jsxRuntime.jsx(BackspaceIcon, {});
|
|
6784
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6785
|
+
core.Text,
|
|
6786
|
+
{
|
|
6787
|
+
style: {
|
|
6788
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6789
|
+
fontSize: "1.2vh",
|
|
6790
|
+
color: "rgba(255,255,255,0.85)",
|
|
6791
|
+
lineHeight: 1,
|
|
6792
|
+
padding: "0 0.3vh"
|
|
6793
|
+
},
|
|
6794
|
+
children: keyLabel
|
|
6795
|
+
}
|
|
6796
|
+
);
|
|
6797
|
+
}
|
|
6798
|
+
function InstructionKeyRow({ keyLabel, action }) {
|
|
6799
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
6800
|
+
const isIconKey = normalized === "LMB" || normalized === "RMB" || normalized === "BACKSPACE" || keyLabel === "\u232B";
|
|
6801
|
+
const minWidth = isIconKey ? "2.6vh" : "2.4vh";
|
|
6802
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
|
|
6803
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6804
|
+
"div",
|
|
6805
|
+
{
|
|
6806
|
+
style: {
|
|
6807
|
+
minWidth,
|
|
6808
|
+
height: "2.4vh",
|
|
6809
|
+
padding: "0 0.4vh",
|
|
6810
|
+
borderRadius: "0.3vh",
|
|
6811
|
+
border: "0.15vh solid rgba(255,255,255,0.35)",
|
|
6812
|
+
background: "rgba(255,255,255,0.06)",
|
|
6813
|
+
display: "flex",
|
|
6814
|
+
alignItems: "center",
|
|
6815
|
+
justifyContent: "center",
|
|
6816
|
+
opacity: 0.85,
|
|
6817
|
+
filter: "drop-shadow(0 0 0.3vh rgba(0,0,0,0.5))",
|
|
6818
|
+
flexShrink: 0,
|
|
6819
|
+
boxSizing: "border-box"
|
|
6820
|
+
},
|
|
6821
|
+
children: renderKeyContent(keyLabel)
|
|
6822
|
+
}
|
|
6823
|
+
),
|
|
6824
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6825
|
+
core.Text,
|
|
6826
|
+
{
|
|
6827
|
+
style: {
|
|
6828
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6829
|
+
fontSize: "1.05vh",
|
|
6830
|
+
color: "rgba(255,255,255,0.45)",
|
|
6831
|
+
letterSpacing: "0.06em",
|
|
6832
|
+
textTransform: "uppercase"
|
|
6833
|
+
},
|
|
6834
|
+
children: action
|
|
6835
|
+
}
|
|
6836
|
+
)
|
|
6837
|
+
] });
|
|
6838
|
+
}
|
|
6839
|
+
function MouseIcon({ side }) {
|
|
6840
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
6841
|
+
const fillActive = "rgba(255,255,255,0.85)";
|
|
6842
|
+
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: [
|
|
6843
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "1", width: "14", height: "20", rx: "6" }),
|
|
6844
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "1", x2: "8", y2: "9" }),
|
|
6845
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6846
|
+
"path",
|
|
6847
|
+
{
|
|
6848
|
+
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",
|
|
6849
|
+
fill: fillActive,
|
|
6850
|
+
stroke: "none"
|
|
6851
|
+
}
|
|
6852
|
+
)
|
|
6853
|
+
] });
|
|
6854
|
+
}
|
|
6855
|
+
function BackspaceIcon() {
|
|
6856
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
6857
|
+
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: [
|
|
6858
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 21 2 L 8 2 L 2 8 L 8 14 L 21 14 Z" }),
|
|
6859
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "11", y1: "6", x2: "16", y2: "11" }),
|
|
6860
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "6", x2: "11", y2: "11" })
|
|
6861
|
+
] });
|
|
6862
|
+
}
|
|
6863
|
+
function WorldPositionPicker({ value, onChange, compact, setOnly, gotoOnly }) {
|
|
6864
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6865
|
+
!gotoOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionSetButton2, { value, onChange, compact }),
|
|
6866
|
+
!setOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionGotoButton2, { value, compact })
|
|
6867
|
+
] });
|
|
6868
|
+
}
|
|
6869
|
+
function WorldPositionSetButton2({
|
|
6870
|
+
value,
|
|
6871
|
+
onChange,
|
|
6872
|
+
compact
|
|
6873
|
+
}) {
|
|
6874
|
+
const theme = core.useMantineTheme();
|
|
6875
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
6876
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
6877
|
+
const onClick = async () => {
|
|
6878
|
+
const instructions = {
|
|
6879
|
+
title: locale("PickPositionTitle") || "Pick Position",
|
|
6880
|
+
hint: locale("PickPositionHint") || "Walk to where you want this set",
|
|
6881
|
+
keys: [
|
|
6882
|
+
{ key: "E", action: locale("Set") || "Set" },
|
|
6883
|
+
{ key: "\u232B", action: locale("Cancel") || "Cancel" }
|
|
6884
|
+
]
|
|
6885
|
+
};
|
|
6886
|
+
const pendingResult = begin({ id: "capturePosition", ...instructions });
|
|
6887
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "capturePosition", instructions }).catch(() => {
|
|
6888
|
+
useAdminToolStore.getState().cancelActive();
|
|
6889
|
+
});
|
|
6890
|
+
const result = await pendingResult;
|
|
6891
|
+
if (result) onChange(result);
|
|
6892
|
+
};
|
|
6893
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("SetWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6894
|
+
framerMotion.motion.button,
|
|
6895
|
+
{
|
|
6896
|
+
onClick,
|
|
6897
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
6898
|
+
whileTap: { scale: 0.95 },
|
|
6899
|
+
style: {
|
|
6900
|
+
background: core.alpha(color, 0.1),
|
|
6901
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
6902
|
+
borderRadius: theme.radius.xs,
|
|
6903
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
6904
|
+
cursor: "pointer",
|
|
6905
|
+
display: "flex",
|
|
6906
|
+
alignItems: "center",
|
|
6907
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
6908
|
+
},
|
|
6909
|
+
children: [
|
|
6910
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crosshair, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
6911
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Set") })
|
|
6912
|
+
]
|
|
6913
|
+
}
|
|
6914
|
+
) });
|
|
6915
|
+
}
|
|
6916
|
+
function WorldPositionGotoButton2({
|
|
6917
|
+
value,
|
|
6918
|
+
compact
|
|
6919
|
+
}) {
|
|
6920
|
+
const theme = core.useMantineTheme();
|
|
6921
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
6922
|
+
const onClick = () => {
|
|
6923
|
+
fetchNui("ADMIN_TOOL_INVOKE", { id: "gotoCoord", value }).catch(() => {
|
|
6924
|
+
});
|
|
6925
|
+
};
|
|
6926
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("GotoWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6927
|
+
framerMotion.motion.button,
|
|
6928
|
+
{
|
|
6929
|
+
onClick,
|
|
6930
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
6931
|
+
whileTap: { scale: 0.95 },
|
|
6932
|
+
style: {
|
|
6933
|
+
background: core.alpha(color, 0.1),
|
|
6934
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
6935
|
+
borderRadius: theme.radius.xs,
|
|
6936
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
6937
|
+
cursor: "pointer",
|
|
6938
|
+
display: "flex",
|
|
6939
|
+
alignItems: "center",
|
|
6940
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
6941
|
+
},
|
|
6942
|
+
children: [
|
|
6943
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
6944
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Goto") })
|
|
6945
|
+
]
|
|
6946
|
+
}
|
|
6947
|
+
) });
|
|
6948
|
+
}
|
|
6949
|
+
function usePlayers(opts = {}) {
|
|
6950
|
+
const {
|
|
6951
|
+
includeOffline = false,
|
|
6952
|
+
search = "",
|
|
6953
|
+
limit = 50,
|
|
6954
|
+
staleTimeMs,
|
|
6955
|
+
refetchIntervalMs
|
|
6956
|
+
} = opts;
|
|
6957
|
+
const query = reactQuery.useQuery({
|
|
6958
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6959
|
+
queryFn: async () => {
|
|
6960
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6961
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6962
|
+
const result = await fetchNui(
|
|
6963
|
+
"ADMIN_TOOL_QUERY",
|
|
6964
|
+
payload,
|
|
6965
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6966
|
+
// dev shell isn't blank.
|
|
6967
|
+
includeOffline ? [
|
|
6968
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6969
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6970
|
+
] : [
|
|
6971
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6972
|
+
]
|
|
6973
|
+
);
|
|
6974
|
+
return Array.isArray(result) ? result : [];
|
|
6975
|
+
},
|
|
6976
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6977
|
+
gcTime: 5 * 6e4,
|
|
6978
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6979
|
+
refetchOnWindowFocus: false,
|
|
6980
|
+
placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
|
|
6981
|
+
});
|
|
6982
|
+
return {
|
|
6983
|
+
players: query.data ?? [],
|
|
6984
|
+
isLoading: query.isLoading,
|
|
6985
|
+
isFetching: query.isFetching,
|
|
6986
|
+
error: query.error ?? null,
|
|
6987
|
+
refresh: () => query.refetch()
|
|
6988
|
+
};
|
|
6989
|
+
}
|
|
6990
|
+
var DEBOUNCE_MS = 300;
|
|
6991
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6992
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6993
|
+
function PlayerSelect({
|
|
6994
|
+
value,
|
|
6995
|
+
onChange,
|
|
6996
|
+
includeOffline = false,
|
|
6997
|
+
limit = 50,
|
|
6998
|
+
searchable: searchableProp,
|
|
6999
|
+
placeholder,
|
|
7000
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
7001
|
+
loadingLabel = "Loading\u2026",
|
|
7002
|
+
onlineLabel = "Online",
|
|
7003
|
+
offlineLabel = "Offline",
|
|
7004
|
+
refreshLabel = "Refresh player list",
|
|
7005
|
+
...rest
|
|
7006
|
+
}) {
|
|
7007
|
+
const theme = core.useMantineTheme();
|
|
7008
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
7009
|
+
const [searchInput, setSearchInput] = react.useState("");
|
|
7010
|
+
const [debouncedSearch, setDebouncedSearch] = react.useState("");
|
|
7011
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
7012
|
+
includeOffline,
|
|
7013
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
7014
|
+
limit
|
|
7015
|
+
});
|
|
7016
|
+
const sortedPlayers = react.useMemo(
|
|
7017
|
+
() => [...players].sort((a, b) => {
|
|
7018
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
7019
|
+
return a.charName.localeCompare(b.charName);
|
|
7020
|
+
}),
|
|
7021
|
+
[players]
|
|
7022
|
+
);
|
|
7023
|
+
const playerByCitizen = react.useMemo(() => {
|
|
7024
|
+
const m = /* @__PURE__ */ new Map();
|
|
7025
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
7026
|
+
return m;
|
|
7027
|
+
}, [sortedPlayers]);
|
|
7028
|
+
const data = react.useMemo(() => {
|
|
7029
|
+
const items = sortedPlayers.map((p) => ({
|
|
7030
|
+
value: p.citizenId,
|
|
7031
|
+
label: formatLabel(p)
|
|
7032
|
+
}));
|
|
7033
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
7034
|
+
items.unshift({ value, label: value });
|
|
7035
|
+
}
|
|
7036
|
+
return items;
|
|
7037
|
+
}, [sortedPlayers, value]);
|
|
7038
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
7039
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
7040
|
+
react.useEffect(() => {
|
|
7041
|
+
if (!includeOffline) return;
|
|
7042
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
7043
|
+
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
7044
|
+
return () => clearTimeout(t3);
|
|
7045
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
7046
|
+
const renderOption = ({ option }) => {
|
|
7047
|
+
const p = playerByCitizen.get(option.value);
|
|
7048
|
+
if (!p) return option.label;
|
|
7049
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
7050
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
7051
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
7052
|
+
] });
|
|
7053
|
+
};
|
|
7054
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7055
|
+
core.Select,
|
|
7056
|
+
{
|
|
7057
|
+
...rest,
|
|
7058
|
+
data,
|
|
7059
|
+
value: value ?? null,
|
|
7060
|
+
onChange: (v) => {
|
|
7061
|
+
if (!v) return onChange(null);
|
|
7062
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
7063
|
+
onChange(player);
|
|
7064
|
+
},
|
|
7065
|
+
searchable: searchableProp ?? true,
|
|
7066
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
7067
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
7068
|
+
placeholder,
|
|
7069
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
7070
|
+
maxDropdownHeight: 300,
|
|
7071
|
+
renderOption,
|
|
7072
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
7073
|
+
rightSectionWidth: "3.5vh",
|
|
7074
|
+
rightSectionPointerEvents: "all",
|
|
7075
|
+
rightSection: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7076
|
+
core.ActionIcon,
|
|
7077
|
+
{
|
|
7078
|
+
variant: "subtle",
|
|
7079
|
+
size: "sm",
|
|
7080
|
+
onClick: (e) => {
|
|
7081
|
+
e.stopPropagation();
|
|
7082
|
+
refresh();
|
|
7083
|
+
},
|
|
7084
|
+
"aria-label": refreshLabel,
|
|
7085
|
+
title: refreshLabel,
|
|
7086
|
+
style: { marginRight: "0.6vh" },
|
|
7087
|
+
children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
|
|
7088
|
+
}
|
|
7089
|
+
)
|
|
7090
|
+
}
|
|
7091
|
+
);
|
|
7092
|
+
}
|
|
7093
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7094
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7095
|
+
"span",
|
|
7096
|
+
{
|
|
7097
|
+
title: online ? onlineLabel : offlineLabel,
|
|
7098
|
+
style: {
|
|
7099
|
+
display: "inline-block",
|
|
7100
|
+
width: "0.9vh",
|
|
7101
|
+
height: "0.9vh",
|
|
7102
|
+
borderRadius: "50%",
|
|
7103
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7104
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7105
|
+
flexShrink: 0
|
|
7106
|
+
}
|
|
7107
|
+
}
|
|
7108
|
+
);
|
|
7109
|
+
}
|
|
7110
|
+
function formatLabel(p) {
|
|
7111
|
+
const parts = [p.charName || p.citizenId];
|
|
7112
|
+
if (p.online) {
|
|
7113
|
+
if (p.name) parts.push(p.name);
|
|
7114
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7115
|
+
}
|
|
7116
|
+
return parts.join(" \xB7 ");
|
|
7117
|
+
}
|
|
7118
|
+
function usePickDoor() {
|
|
7119
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
7120
|
+
return async () => {
|
|
7121
|
+
const pending = begin({
|
|
7122
|
+
id: "pickDoor",
|
|
7123
|
+
title: locale("PickDoorTitle"),
|
|
7124
|
+
hint: locale("PickDoorHint"),
|
|
7125
|
+
keys: [
|
|
7126
|
+
{ key: "LMB", action: locale("Toggle") },
|
|
7127
|
+
{ key: "E", action: locale("Confirm") },
|
|
7128
|
+
{ key: "BACKSPACE", action: locale("Cancel") }
|
|
7129
|
+
]
|
|
7130
|
+
});
|
|
7131
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "pickDoor" }).catch(() => {
|
|
7132
|
+
useAdminToolStore.getState().cancelActive();
|
|
7133
|
+
});
|
|
7134
|
+
return await pending;
|
|
7135
|
+
};
|
|
7136
|
+
}
|
|
7137
|
+
function DoorPickerButton({
|
|
7138
|
+
onPick,
|
|
7139
|
+
compact,
|
|
7140
|
+
label,
|
|
7141
|
+
tooltip
|
|
7142
|
+
}) {
|
|
7143
|
+
const theme = core.useMantineTheme();
|
|
7144
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
7145
|
+
const pickDoor = usePickDoor();
|
|
7146
|
+
const onClick = async () => {
|
|
7147
|
+
const picked = await pickDoor();
|
|
7148
|
+
if (picked && picked.doors.length > 0) onPick(picked);
|
|
7149
|
+
};
|
|
7150
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7151
|
+
core.Tooltip,
|
|
7152
|
+
{
|
|
7153
|
+
label: tooltip ?? locale("PickDoorTooltip"),
|
|
7154
|
+
position: "top",
|
|
7155
|
+
withArrow: true,
|
|
7156
|
+
withinPortal: true,
|
|
7157
|
+
zIndex: 2e3,
|
|
7158
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7159
|
+
framerMotion.motion.button,
|
|
7160
|
+
{
|
|
7161
|
+
onClick,
|
|
7162
|
+
whileHover: { background: core.alpha(color, 0.18) },
|
|
7163
|
+
whileTap: { scale: 0.95 },
|
|
7164
|
+
style: {
|
|
7165
|
+
background: core.alpha(color, 0.1),
|
|
7166
|
+
border: `0.1vh solid ${core.alpha(color, 0.35)}`,
|
|
7167
|
+
borderRadius: theme.radius.xs,
|
|
7168
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
7169
|
+
cursor: "pointer",
|
|
7170
|
+
display: "flex",
|
|
7171
|
+
alignItems: "center",
|
|
7172
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
7173
|
+
},
|
|
7174
|
+
children: [
|
|
7175
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DoorOpen, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
7176
|
+
/* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: label ?? locale("PickDoor") })
|
|
7177
|
+
]
|
|
7178
|
+
}
|
|
7179
|
+
)
|
|
7180
|
+
}
|
|
7181
|
+
);
|
|
7182
|
+
}
|
|
7183
|
+
var MapImpl = react.memo(({
|
|
7184
|
+
children,
|
|
7185
|
+
initialZoom = 2,
|
|
7186
|
+
initialCenter = gameToMap(0, 0),
|
|
7187
|
+
mapStyle = "game"
|
|
7188
|
+
}) => {
|
|
7189
|
+
const mapRef = react.useRef(null);
|
|
7190
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7191
|
+
reactLeaflet.MapContainer,
|
|
7192
|
+
{
|
|
7193
|
+
maxBoundsViscosity: 1,
|
|
7194
|
+
preferCanvas: true,
|
|
7195
|
+
zoom: Math.round(initialZoom),
|
|
7196
|
+
zoomSnap: 1,
|
|
7197
|
+
zoomDelta: 1,
|
|
7198
|
+
zoomControl: false,
|
|
7199
|
+
crs: leaflet.CRS.Simple,
|
|
7200
|
+
style: {
|
|
7201
|
+
height: "100%",
|
|
7202
|
+
width: "100%",
|
|
7203
|
+
overflow: "hidden",
|
|
7204
|
+
outline: "none !important",
|
|
7205
|
+
border: "none !important",
|
|
7206
|
+
boxShadow: "none !important",
|
|
7207
|
+
backgroundColor: "#384950"
|
|
7208
|
+
},
|
|
7209
|
+
center: initialCenter,
|
|
7210
|
+
attributionControl: false,
|
|
7211
|
+
doubleClickZoom: false,
|
|
7212
|
+
inertia: false,
|
|
7213
|
+
zoomAnimation: false,
|
|
7214
|
+
ref: mapRef,
|
|
7215
|
+
maxBounds: [[-250, -250], [250, 250]],
|
|
7216
|
+
children: [
|
|
7217
|
+
/* @__PURE__ */ jsxRuntime.jsx(MapLayer, { mapLayer: mapStyle }),
|
|
7218
|
+
children
|
|
7219
|
+
]
|
|
7220
|
+
}
|
|
7221
|
+
);
|
|
7222
|
+
});
|
|
7223
|
+
MapImpl.displayName = "DirkMap";
|
|
7224
|
+
var Map2 = MapImpl;
|
|
7225
|
+
var MapLayer = ({ mapLayer }) => {
|
|
7226
|
+
const map = reactLeaflet.useMap();
|
|
7227
|
+
const layerRef = react.useRef(null);
|
|
7228
|
+
react.useEffect(() => {
|
|
7229
|
+
if (layerRef.current) {
|
|
7230
|
+
map.removeLayer(layerRef.current);
|
|
7231
|
+
}
|
|
7232
|
+
const layer = leaflet.tileLayer(
|
|
7233
|
+
`https://s.rsg.sc/sc/images/games/GTAV/map/${mapLayer}/{z}/{x}/{y}.jpg`,
|
|
7234
|
+
{
|
|
7235
|
+
maxZoom: 6,
|
|
7236
|
+
minZoom: 4,
|
|
7237
|
+
bounds: leaflet.latLngBounds(leaflet.latLng(0, 128), leaflet.latLng(-192, 0)),
|
|
7238
|
+
tileSize: 256,
|
|
7239
|
+
updateWhenZooming: false,
|
|
7240
|
+
keepBuffer: 2,
|
|
7241
|
+
opacity: 0.75
|
|
7242
|
+
}
|
|
7243
|
+
);
|
|
7244
|
+
layer.addTo(map);
|
|
7245
|
+
layerRef.current = layer;
|
|
7246
|
+
return () => {
|
|
7247
|
+
if (layerRef.current) {
|
|
7248
|
+
map.removeLayer(layerRef.current);
|
|
7249
|
+
}
|
|
7250
|
+
};
|
|
7251
|
+
}, [mapLayer, map]);
|
|
7252
|
+
return null;
|
|
7253
|
+
};
|
|
7254
|
+
function ZoomControls() {
|
|
7255
|
+
const theme = core.useMantineTheme();
|
|
7256
|
+
const map = reactLeaflet.useMap();
|
|
7257
|
+
const buttons = [
|
|
7258
|
+
{ Icon: lucideReact.Plus, fn: () => map.zoomIn() },
|
|
7259
|
+
{ Icon: lucideReact.Minus, fn: () => map.zoomOut() }
|
|
7260
|
+
];
|
|
7261
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7262
|
+
framerMotion.motion.div,
|
|
7263
|
+
{
|
|
7264
|
+
style: {
|
|
7265
|
+
position: "absolute",
|
|
7266
|
+
right: "2vh",
|
|
7267
|
+
top: "2vh",
|
|
7268
|
+
display: "flex",
|
|
7269
|
+
flexDirection: "column",
|
|
7270
|
+
zIndex: 999999,
|
|
7271
|
+
boxShadow: `0 0 1vh ${core.alpha(theme.colors.dark[9], 0.85)}`,
|
|
7272
|
+
background: core.alpha(theme.colors.dark[9], 0.85),
|
|
7273
|
+
borderRadius: theme.radius.xs
|
|
7274
|
+
},
|
|
7275
|
+
initial: { opacity: 0, y: -20 },
|
|
7276
|
+
animate: { opacity: 1, y: 0 },
|
|
7277
|
+
exit: { opacity: 0, y: -20 },
|
|
7278
|
+
children: buttons.map(({ Icon, fn }, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7279
|
+
framerMotion.motion.div,
|
|
7280
|
+
{
|
|
7281
|
+
whileHover: { scale: 1.1, filter: "brightness(1.5)" },
|
|
7282
|
+
onClick: fn,
|
|
7283
|
+
style: {
|
|
7284
|
+
padding: theme.spacing.xs,
|
|
7285
|
+
cursor: "pointer",
|
|
7286
|
+
display: "flex"
|
|
7287
|
+
},
|
|
7288
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 34, color: theme.colors.gray[5] })
|
|
7289
|
+
},
|
|
7290
|
+
i
|
|
7291
|
+
))
|
|
7292
|
+
}
|
|
7293
|
+
);
|
|
7294
|
+
}
|
|
7295
|
+
var DEFAULT_SPRITE = 162;
|
|
7296
|
+
var DEFAULT_COLOR = 5;
|
|
7297
|
+
function BlipMarker({
|
|
7298
|
+
position,
|
|
7299
|
+
sprite,
|
|
7300
|
+
color,
|
|
7301
|
+
scale = 1,
|
|
7302
|
+
onClick,
|
|
7303
|
+
selected,
|
|
7304
|
+
disabled,
|
|
7305
|
+
fallbackSprite = DEFAULT_SPRITE,
|
|
7306
|
+
fallbackColor = DEFAULT_COLOR
|
|
7307
|
+
}) {
|
|
7308
|
+
const [hovered, setHovered] = react.useState(false);
|
|
7309
|
+
const mapCoords = react.useMemo(() => gameToMap(position.x, position.y), [position.x, position.y]);
|
|
7310
|
+
const effectiveSprite = sprite ?? fallbackSprite;
|
|
7311
|
+
const effectiveColor = color ?? fallbackColor;
|
|
7312
|
+
const url = blipUrlForSprite(effectiveSprite);
|
|
7313
|
+
const colorHex = getBlipColor(effectiveColor)?.hex ?? "#ffffff";
|
|
7314
|
+
const handleClick = (e) => {
|
|
7315
|
+
e.originalEvent?.stopPropagation?.();
|
|
7316
|
+
if (disabled) return;
|
|
7317
|
+
onClick?.();
|
|
7318
|
+
};
|
|
7319
|
+
const baseSize = 1.8 * scale;
|
|
7320
|
+
const size = `${baseSize}vh`;
|
|
7321
|
+
const ringSize = `${baseSize * 1.6}vh`;
|
|
7322
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7323
|
+
reactLeafletComponentMarker.Marker,
|
|
7324
|
+
{
|
|
7325
|
+
position: mapCoords,
|
|
7326
|
+
eventHandlers: onClick ? { click: handleClick } : void 0,
|
|
7327
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7328
|
+
framerMotion.motion.div,
|
|
7329
|
+
{
|
|
7330
|
+
onHoverStart: () => setHovered(true),
|
|
7331
|
+
onHoverEnd: () => setHovered(false),
|
|
7332
|
+
style: {
|
|
7333
|
+
position: "relative",
|
|
7334
|
+
display: "flex",
|
|
7335
|
+
alignItems: "center",
|
|
7336
|
+
justifyContent: "center",
|
|
7337
|
+
cursor: disabled ? "not-allowed" : onClick ? "pointer" : "default",
|
|
7338
|
+
opacity: disabled ? 0.35 : 1,
|
|
7339
|
+
width: size,
|
|
7340
|
+
height: size
|
|
7341
|
+
},
|
|
7342
|
+
animate: { scale: hovered && !disabled ? 1.2 : selected ? 1.15 : 1 },
|
|
7343
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
7344
|
+
children: [
|
|
7345
|
+
(selected || hovered) && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7346
|
+
framerMotion.motion.div,
|
|
7347
|
+
{
|
|
7348
|
+
style: {
|
|
7349
|
+
position: "absolute",
|
|
7350
|
+
width: ringSize,
|
|
7351
|
+
height: ringSize,
|
|
7352
|
+
borderRadius: "50%",
|
|
7353
|
+
border: `0.18vh solid ${core.alpha(colorHex, 0.85)}`,
|
|
7354
|
+
boxShadow: `0 0 1vh ${core.alpha(colorHex, 0.55)}`
|
|
7355
|
+
},
|
|
7356
|
+
initial: { opacity: 0, scale: 0.8 },
|
|
7357
|
+
animate: { opacity: 1, scale: 1 }
|
|
7358
|
+
}
|
|
7359
|
+
),
|
|
7360
|
+
url && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7361
|
+
"div",
|
|
7362
|
+
{
|
|
7363
|
+
style: {
|
|
7364
|
+
width: size,
|
|
7365
|
+
height: size,
|
|
7366
|
+
backgroundColor: colorHex,
|
|
7367
|
+
WebkitMaskImage: `url(${url})`,
|
|
7368
|
+
maskImage: `url(${url})`,
|
|
7369
|
+
WebkitMaskRepeat: "no-repeat",
|
|
7370
|
+
maskRepeat: "no-repeat",
|
|
7371
|
+
WebkitMaskPosition: "center",
|
|
7372
|
+
maskPosition: "center",
|
|
7373
|
+
WebkitMaskSize: "contain",
|
|
7374
|
+
maskSize: "contain",
|
|
7375
|
+
filter: [
|
|
7376
|
+
"drop-shadow(0.12vh 0 0 #000)",
|
|
7377
|
+
"drop-shadow(-0.12vh 0 0 #000)",
|
|
7378
|
+
"drop-shadow(0 0.12vh 0 #000)",
|
|
7379
|
+
"drop-shadow(0 -0.12vh 0 #000)",
|
|
7380
|
+
`drop-shadow(0 0 0.4vh ${core.alpha("#000", 0.7)})`
|
|
7381
|
+
].join(" "),
|
|
7382
|
+
pointerEvents: "none",
|
|
7383
|
+
userSelect: "none"
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
)
|
|
7387
|
+
]
|
|
7388
|
+
}
|
|
7389
|
+
)
|
|
7390
|
+
}
|
|
7391
|
+
);
|
|
7392
|
+
}
|
|
6542
7393
|
|
|
6543
7394
|
exports.AccountSelect = AccountSelect;
|
|
6544
7395
|
exports.AdminPageTitle = AdminPageTitle;
|
|
@@ -6547,6 +7398,7 @@ exports.AsyncSaveButton = AsyncSaveButton;
|
|
|
6547
7398
|
exports.BlipColorSelect = BlipColorSelect;
|
|
6548
7399
|
exports.BlipDisplaySelect = BlipDisplaySelect;
|
|
6549
7400
|
exports.BlipIconSelect = BlipIconSelect;
|
|
7401
|
+
exports.BlipMarker = BlipMarker;
|
|
6550
7402
|
exports.BorderedIcon = BorderedIcon;
|
|
6551
7403
|
exports.ConfigPanel = ConfigPanel;
|
|
6552
7404
|
exports.ConfirmModal = ConfirmModal;
|
|
@@ -6554,6 +7406,7 @@ exports.ControlMultiSelect = ControlMultiSelect;
|
|
|
6554
7406
|
exports.ControlSelect = ControlSelect;
|
|
6555
7407
|
exports.Counter = Counter;
|
|
6556
7408
|
exports.DiscordRoleSelect = DiscordRoleSelect;
|
|
7409
|
+
exports.DoorPickerButton = DoorPickerButton;
|
|
6557
7410
|
exports.FiveMKeyBindInput = FiveMKeyBindInput;
|
|
6558
7411
|
exports.FloatingParticles = FloatingParticles;
|
|
6559
7412
|
exports.GroupName = GroupName;
|
|
@@ -6561,8 +7414,11 @@ exports.GroupRank = GroupRank;
|
|
|
6561
7414
|
exports.GroupSelect = GroupSelect;
|
|
6562
7415
|
exports.InfoBox = InfoBox;
|
|
6563
7416
|
exports.InputContainer = InputContainer;
|
|
7417
|
+
exports.InstructionPanel = InstructionPanel;
|
|
6564
7418
|
exports.LevelBanner = LevelBanner;
|
|
6565
7419
|
exports.LevelPanel = LevelPanel;
|
|
7420
|
+
exports.Map = Map2;
|
|
7421
|
+
exports.MapLayer = MapLayer;
|
|
6566
7422
|
exports.MissingItemsBanner = MissingItemsBanner;
|
|
6567
7423
|
exports.Modal = Modal;
|
|
6568
7424
|
exports.ModalContext = ModalContext;
|
|
@@ -6574,6 +7430,7 @@ exports.MotionText = MotionText;
|
|
|
6574
7430
|
exports.NavBar = NavBar;
|
|
6575
7431
|
exports.NavigationContext = NavigationContext;
|
|
6576
7432
|
exports.NavigationProvider = NavigationProvider;
|
|
7433
|
+
exports.PlayerSelect = PlayerSelect;
|
|
6577
7434
|
exports.PositionPicker = PositionPicker;
|
|
6578
7435
|
exports.PromptModal = PromptModal;
|
|
6579
7436
|
exports.ScenarioSelect = ScenarioSelect;
|
|
@@ -6587,11 +7444,19 @@ exports.Title = Title;
|
|
|
6587
7444
|
exports.Vector4DeleteButton = Vector4DeleteButton;
|
|
6588
7445
|
exports.Vector4Display = Vector4Display;
|
|
6589
7446
|
exports.WorldPositionGotoButton = WorldPositionGotoButton;
|
|
7447
|
+
exports.WorldPositionPicker = WorldPositionPicker;
|
|
6590
7448
|
exports.WorldPositionSetButton = WorldPositionSetButton;
|
|
7449
|
+
exports.ZoomControls = ZoomControls;
|
|
7450
|
+
exports.blipUrl = blipUrl;
|
|
7451
|
+
exports.blipUrlForSprite = blipUrlForSprite;
|
|
7452
|
+
exports.getBlipColor = getBlipColor;
|
|
7453
|
+
exports.getBlipEntry = getBlipEntry;
|
|
7454
|
+
exports.useAdminToolStore = useAdminToolStore;
|
|
6591
7455
|
exports.useMissingItemsAudit = useMissingItemsAudit;
|
|
6592
7456
|
exports.useModal = useModal;
|
|
6593
7457
|
exports.useModalActions = useModalActions;
|
|
6594
7458
|
exports.useNavigation = useNavigation;
|
|
6595
7459
|
exports.useNavigationStore = useNavigationStore;
|
|
7460
|
+
exports.usePickDoor = usePickDoor;
|
|
6596
7461
|
//# sourceMappingURL=index.cjs.map
|
|
6597
7462
|
//# sourceMappingURL=index.cjs.map
|