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/components/index.js
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { Flex, Text, Image, TextInput, Select, Box, useMantineTheme, Tooltip, alpha, Progress, RingProgress, Portal, Button, NumberInput, MultiSelect, Loader, Switch, ActionIcon, Stack, ColorInput, Popover, Group, JsonInput } from '@mantine/core';
|
|
2
|
-
import {
|
|
3
|
-
import { createContext,
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { createContext, memo, useRef, useEffect, useContext, useState, useCallback, useMemo } from 'react';
|
|
4
4
|
import { create, useStore, createStore } from 'zustand';
|
|
5
5
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
6
6
|
import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
|
|
7
|
-
import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, Palette, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, Search, Filter, User } from 'lucide-react';
|
|
7
|
+
import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, Palette, DoorOpen, Plus, Minus, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, Search, Filter, User } from 'lucide-react';
|
|
8
8
|
import clickSoundUrl from '../click_sound-PNCRRTM4.mp3';
|
|
9
9
|
import hoverSoundUrl from '../hover_sound-NBUA222C.mp3';
|
|
10
10
|
import { notifications } from '@mantine/notifications';
|
|
11
|
-
import { QueryClient,
|
|
11
|
+
import { QueryClient, useQuery, keepPreviousData, useInfiniteQuery } from '@tanstack/react-query';
|
|
12
|
+
import '@mantine/core/styles.css';
|
|
13
|
+
import '@mantine/notifications/styles.css';
|
|
14
|
+
import './styles/fonts.css';
|
|
15
|
+
import './styles/notify.css';
|
|
16
|
+
import './styles/scrollBar.css';
|
|
17
|
+
import './styles/tornEdge.css';
|
|
18
|
+
import { library } from '@fortawesome/fontawesome-svg-core';
|
|
19
|
+
import { fab } from '@fortawesome/free-brands-svg-icons';
|
|
20
|
+
import { far } from '@fortawesome/free-regular-svg-icons';
|
|
21
|
+
import { fas } from '@fortawesome/free-solid-svg-icons';
|
|
12
22
|
import { generateColors } from '@mantine/colors-generator';
|
|
23
|
+
import { createPortal } from 'react-dom';
|
|
24
|
+
import { CRS, tileLayer, latLngBounds, latLng } from 'leaflet';
|
|
25
|
+
import 'leaflet/dist/leaflet.css';
|
|
26
|
+
import { MapContainer, useMap } from 'react-leaflet';
|
|
27
|
+
import { Marker } from '@adamscybot/react-leaflet-component-marker';
|
|
13
28
|
|
|
14
29
|
// src/components/BlipSelect.tsx
|
|
15
30
|
var BLIP_ENTRIES = [
|
|
@@ -953,6 +968,18 @@ var BLIP_COLOR_DATA = BLIP_COLORS.map(([id, label]) => ({
|
|
|
953
968
|
}));
|
|
954
969
|
var blipEntryMap = new Map(BLIP_ENTRIES.map(([id, name, ext]) => [String(id), { id, name, ext }]));
|
|
955
970
|
var blipColorMap = new Map(BLIP_COLORS.map(([id, label, hex]) => [String(id), { id, label, hex }]));
|
|
971
|
+
function getBlipEntry(spriteId) {
|
|
972
|
+
if (spriteId == null) return void 0;
|
|
973
|
+
return blipEntryMap.get(String(spriteId));
|
|
974
|
+
}
|
|
975
|
+
function getBlipColor(colorId) {
|
|
976
|
+
if (colorId == null) return void 0;
|
|
977
|
+
return blipColorMap.get(String(colorId));
|
|
978
|
+
}
|
|
979
|
+
function blipUrlForSprite(spriteId) {
|
|
980
|
+
const entry = getBlipEntry(spriteId);
|
|
981
|
+
return entry ? blipUrl(entry.name, entry.ext) : null;
|
|
982
|
+
}
|
|
956
983
|
var renderBlipOption = ({ option }) => {
|
|
957
984
|
const entry = blipEntryMap.get(option.value);
|
|
958
985
|
if (!entry) return option.label;
|
|
@@ -1230,11 +1257,11 @@ var colorNames = {
|
|
|
1230
1257
|
Yellow: { r: 255, g: 255, b: 0 },
|
|
1231
1258
|
YellowGreen: { r: 154, g: 205, b: 50 }
|
|
1232
1259
|
};
|
|
1233
|
-
function colorWithAlpha(color,
|
|
1260
|
+
function colorWithAlpha(color, alpha17) {
|
|
1234
1261
|
const lowerCasedColor = color.toLowerCase();
|
|
1235
1262
|
if (colorNames[lowerCasedColor]) {
|
|
1236
1263
|
const rgb = colorNames[lowerCasedColor];
|
|
1237
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${
|
|
1264
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha17})`;
|
|
1238
1265
|
}
|
|
1239
1266
|
if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
|
|
1240
1267
|
const hex = color.slice(1);
|
|
@@ -1242,12 +1269,12 @@ function colorWithAlpha(color, alpha12) {
|
|
|
1242
1269
|
const r = bigint >> 16 & 255;
|
|
1243
1270
|
const g = bigint >> 8 & 255;
|
|
1244
1271
|
const b = bigint & 255;
|
|
1245
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
1272
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha17})`;
|
|
1246
1273
|
}
|
|
1247
1274
|
if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
|
|
1248
1275
|
const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
|
|
1249
1276
|
if (result) {
|
|
1250
|
-
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${
|
|
1277
|
+
return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha17})`;
|
|
1251
1278
|
}
|
|
1252
1279
|
}
|
|
1253
1280
|
return color;
|
|
@@ -1316,11 +1343,35 @@ function reportMissingLocale(key) {
|
|
|
1316
1343
|
fetchNui("REPORT_MISSING_LOCALE", { key }).catch(() => {
|
|
1317
1344
|
});
|
|
1318
1345
|
}
|
|
1346
|
+
var PACKAGE_DEFAULTS = {
|
|
1347
|
+
"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.",
|
|
1348
|
+
"cfgpanel_discard": "Discard",
|
|
1349
|
+
"cfgpanel_manual_edit": "Manual Edit",
|
|
1350
|
+
"cfgpanel_reset_defaults": "Reset Defaults",
|
|
1351
|
+
"cfgpanel_version": "Version",
|
|
1352
|
+
"cfgpanel_back_title": "Back to script list",
|
|
1353
|
+
"cfgpanel_undo": "Undo",
|
|
1354
|
+
"cfgpanel_redo": "Redo",
|
|
1355
|
+
"cfgpanel_save": "Save",
|
|
1356
|
+
"cfgpanel_saving": "Saving...",
|
|
1357
|
+
"cfgpanel_history": "History",
|
|
1358
|
+
"cfgpanel_reset_title": "Reset to Defaults",
|
|
1359
|
+
"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.",
|
|
1360
|
+
"cfgpanel_reset_confirm": "Reset Config",
|
|
1361
|
+
"cfgpanel_discard_title": "Discard Unsaved Changes?",
|
|
1362
|
+
"cfgpanel_discard_desc_back": "You have unsaved changes. Going back now will discard them.",
|
|
1363
|
+
"cfgpanel_discard_desc_close": "You have unsaved changes. Closing now will discard them.",
|
|
1364
|
+
"cfgpanel_discard_confirm_back": "Go Back Without Saving",
|
|
1365
|
+
"cfgpanel_discard_confirm_close": "Close Without Saving",
|
|
1366
|
+
"cfgpanel_json_title": "Config JSON",
|
|
1367
|
+
"cfgpanel_cancel": "Cancel",
|
|
1368
|
+
"cfgpanel_apply": "Apply",
|
|
1369
|
+
"cfgpanel_history_title": "Config History",
|
|
1370
|
+
"cfgpanel_close": "Close"
|
|
1371
|
+
};
|
|
1319
1372
|
var localeStore = create((set, get) => {
|
|
1320
1373
|
return {
|
|
1321
|
-
locales: {
|
|
1322
|
-
"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."
|
|
1323
|
-
},
|
|
1374
|
+
locales: { ...PACKAGE_DEFAULTS },
|
|
1324
1375
|
locale: (key, ...args) => {
|
|
1325
1376
|
const exists = get().locales[key];
|
|
1326
1377
|
if (!exists) reportMissingLocale(key);
|
|
@@ -1334,7 +1385,7 @@ var localeStore = create((set, get) => {
|
|
|
1334
1385
|
});
|
|
1335
1386
|
var locale = localeStore.getState().locale;
|
|
1336
1387
|
registerInitialFetch("GET_LOCALES", void 0).then((data) => {
|
|
1337
|
-
localeStore.setState({ locales: data });
|
|
1388
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...data } });
|
|
1338
1389
|
}).catch(() => {
|
|
1339
1390
|
});
|
|
1340
1391
|
if (typeof window !== "undefined") {
|
|
@@ -1342,9 +1393,22 @@ if (typeof window !== "undefined") {
|
|
|
1342
1393
|
const msg = event.data;
|
|
1343
1394
|
if (!msg || msg.action !== "UPDATE_DIRK_LIB_LOCALES") return;
|
|
1344
1395
|
if (!msg.data || typeof msg.data !== "object") return;
|
|
1345
|
-
|
|
1396
|
+
if (Object.keys(msg.data).length === 0) return;
|
|
1397
|
+
localeStore.setState({ locales: { ...PACKAGE_DEFAULTS, ...msg.data } });
|
|
1346
1398
|
});
|
|
1347
1399
|
}
|
|
1400
|
+
|
|
1401
|
+
// src/utils/map.ts
|
|
1402
|
+
var mapCenter = [-119.43, 58.84];
|
|
1403
|
+
var latPr100 = 1.421;
|
|
1404
|
+
function gameToMap(x, y) {
|
|
1405
|
+
return [
|
|
1406
|
+
mapCenter[0] + latPr100 / 100 * y,
|
|
1407
|
+
// lng
|
|
1408
|
+
mapCenter[1] + latPr100 / 100 * x
|
|
1409
|
+
// lat
|
|
1410
|
+
];
|
|
1411
|
+
}
|
|
1348
1412
|
var useItems = create(() => ({}));
|
|
1349
1413
|
var useItemsList = (excludeItemNames = []) => {
|
|
1350
1414
|
const excludeSet = new Set(excludeItemNames);
|
|
@@ -1364,15 +1428,21 @@ var useFrameworkGroups = create(() => ({
|
|
|
1364
1428
|
gangs: [],
|
|
1365
1429
|
loaded: false
|
|
1366
1430
|
}));
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1431
|
+
var frameworkGroupsRequested = false;
|
|
1432
|
+
function ensureFrameworkGroups() {
|
|
1433
|
+
if (frameworkGroupsRequested) return;
|
|
1434
|
+
frameworkGroupsRequested = true;
|
|
1435
|
+
fetchNui("GET_FRAMEWORK_GROUPS", void 0).then((data) => {
|
|
1436
|
+
useFrameworkGroups.setState({
|
|
1437
|
+
jobs: Array.isArray(data?.jobs) ? data.jobs : [],
|
|
1438
|
+
gangs: Array.isArray(data?.gangs) ? data.gangs : [],
|
|
1439
|
+
loaded: true
|
|
1440
|
+
});
|
|
1441
|
+
}).catch(() => {
|
|
1442
|
+
frameworkGroupsRequested = false;
|
|
1443
|
+
useFrameworkGroups.setState({ loaded: true });
|
|
1372
1444
|
});
|
|
1373
|
-
}
|
|
1374
|
-
useFrameworkGroups.setState({ loaded: true });
|
|
1375
|
-
});
|
|
1445
|
+
}
|
|
1376
1446
|
|
|
1377
1447
|
// src/utils/inputMapper.ts
|
|
1378
1448
|
var INPUT_MAPPER_PRIMARY_OPTIONS = [
|
|
@@ -2381,7 +2451,7 @@ function NavigationProvider({ children, defaultPage }) {
|
|
|
2381
2451
|
}
|
|
2382
2452
|
function NavBar(props) {
|
|
2383
2453
|
const pageId = useNavigation((state) => state.pageId);
|
|
2384
|
-
const
|
|
2454
|
+
const store2 = useNavigationStore();
|
|
2385
2455
|
return /* @__PURE__ */ jsx(
|
|
2386
2456
|
SegmentedControl,
|
|
2387
2457
|
{
|
|
@@ -2390,7 +2460,7 @@ function NavBar(props) {
|
|
|
2390
2460
|
value: pageId,
|
|
2391
2461
|
items: props.items,
|
|
2392
2462
|
onChange: (value) => {
|
|
2393
|
-
|
|
2463
|
+
store2.setState({ pageId: value });
|
|
2394
2464
|
}
|
|
2395
2465
|
}
|
|
2396
2466
|
);
|
|
@@ -3697,34 +3767,82 @@ function FormProvider({
|
|
|
3697
3767
|
return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children });
|
|
3698
3768
|
}
|
|
3699
3769
|
function useForm() {
|
|
3700
|
-
const
|
|
3701
|
-
if (!
|
|
3770
|
+
const store2 = useContext(FormContext);
|
|
3771
|
+
if (!store2) {
|
|
3702
3772
|
throw new Error("useForm must be used inside <FormProvider>");
|
|
3703
3773
|
}
|
|
3704
|
-
const state = useStore(
|
|
3774
|
+
const state = useStore(store2);
|
|
3705
3775
|
const changedFields = useMemo(() => {
|
|
3706
3776
|
return collectChangedPaths(state.values, state.initialValues);
|
|
3707
3777
|
}, [state.values, state.initialValues]);
|
|
3708
3778
|
return { ...state, changedFields, changedCount: changedFields.length };
|
|
3709
3779
|
}
|
|
3710
3780
|
function useFormField(path) {
|
|
3711
|
-
const
|
|
3712
|
-
if (!
|
|
3781
|
+
const store2 = useContext(FormContext);
|
|
3782
|
+
if (!store2) {
|
|
3713
3783
|
throw new Error("useFormField must be used inside <FormProvider>");
|
|
3714
3784
|
}
|
|
3715
|
-
return useStore(
|
|
3785
|
+
return useStore(store2, (s) => getNested(s.values, path));
|
|
3716
3786
|
}
|
|
3717
3787
|
function useFormActions() {
|
|
3718
|
-
const
|
|
3719
|
-
if (!
|
|
3788
|
+
const store2 = useContext(FormContext);
|
|
3789
|
+
if (!store2) {
|
|
3720
3790
|
throw new Error("useFormActions must be used inside <FormProvider>");
|
|
3721
3791
|
}
|
|
3722
|
-
return
|
|
3792
|
+
return store2.getState();
|
|
3793
|
+
}
|
|
3794
|
+
var store = /* @__PURE__ */ new Map();
|
|
3795
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
3796
|
+
function notify(key) {
|
|
3797
|
+
const ls = listeners.get(key);
|
|
3798
|
+
if (!ls) return;
|
|
3799
|
+
ls.forEach((fn) => fn());
|
|
3800
|
+
}
|
|
3801
|
+
function useAdminState(key, initial) {
|
|
3802
|
+
const [, setTick] = useState(0);
|
|
3803
|
+
useEffect(() => {
|
|
3804
|
+
const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
3805
|
+
listeners.set(key, set);
|
|
3806
|
+
const handler = () => setTick((t3) => t3 + 1);
|
|
3807
|
+
set.add(handler);
|
|
3808
|
+
return () => {
|
|
3809
|
+
set.delete(handler);
|
|
3810
|
+
if (set.size === 0) listeners.delete(key);
|
|
3811
|
+
};
|
|
3812
|
+
}, [key]);
|
|
3813
|
+
const value = store.has(key) ? store.get(key) : initial;
|
|
3814
|
+
const setValue = (v) => {
|
|
3815
|
+
const next = typeof v === "function" ? v(value) : v;
|
|
3816
|
+
store.set(key, next);
|
|
3817
|
+
notify(key);
|
|
3818
|
+
};
|
|
3819
|
+
return [value, setValue];
|
|
3723
3820
|
}
|
|
3724
3821
|
function getScriptConfigInstance() {
|
|
3725
3822
|
throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
|
|
3726
3823
|
}
|
|
3727
|
-
var
|
|
3824
|
+
var useAdminToolStore = create((set, get) => ({
|
|
3825
|
+
active: null,
|
|
3826
|
+
begin: (spec) => new Promise((resolve) => {
|
|
3827
|
+
const prev = get().active;
|
|
3828
|
+
if (prev) prev.resolve(null);
|
|
3829
|
+
set({ active: { ...spec, resolve } });
|
|
3830
|
+
}),
|
|
3831
|
+
resolveActive: (value) => {
|
|
3832
|
+
const cur = get().active;
|
|
3833
|
+
if (!cur) return;
|
|
3834
|
+
cur.resolve(value);
|
|
3835
|
+
set({ active: null });
|
|
3836
|
+
},
|
|
3837
|
+
cancelActive: () => {
|
|
3838
|
+
const cur = get().active;
|
|
3839
|
+
if (!cur) return;
|
|
3840
|
+
cur.resolve(null);
|
|
3841
|
+
set({ active: null });
|
|
3842
|
+
}
|
|
3843
|
+
}));
|
|
3844
|
+
library.add(fas, far, fab);
|
|
3845
|
+
var dirkQueryClient = new QueryClient({
|
|
3728
3846
|
defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
|
|
3729
3847
|
});
|
|
3730
3848
|
function NavItemButton({
|
|
@@ -3805,7 +3923,7 @@ function ConfigJsonModal({
|
|
|
3805
3923
|
setError(e.message);
|
|
3806
3924
|
}
|
|
3807
3925
|
};
|
|
3808
|
-
return /* @__PURE__ */ jsxs(Modal, { title: "
|
|
3926
|
+
return /* @__PURE__ */ jsxs(Modal, { title: locale("cfgpanel_json_title"), icon: Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
|
|
3809
3927
|
/* @__PURE__ */ jsxs(Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
|
|
3810
3928
|
/* @__PURE__ */ jsx(
|
|
3811
3929
|
JsonInput,
|
|
@@ -3833,7 +3951,7 @@ function ConfigJsonModal({
|
|
|
3833
3951
|
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 },
|
|
3834
3952
|
children: [
|
|
3835
3953
|
/* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)" }),
|
|
3836
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
3954
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: locale("cfgpanel_cancel") })
|
|
3837
3955
|
]
|
|
3838
3956
|
}
|
|
3839
3957
|
),
|
|
@@ -3846,7 +3964,7 @@ function ConfigJsonModal({
|
|
|
3846
3964
|
style: { background: alpha(color, 0.14), border: `0.1vh solid ${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 },
|
|
3847
3965
|
children: [
|
|
3848
3966
|
/* @__PURE__ */ jsx(Check, { color }),
|
|
3849
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: "
|
|
3967
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: locale("cfgpanel_apply") })
|
|
3850
3968
|
]
|
|
3851
3969
|
}
|
|
3852
3970
|
)
|
|
@@ -3987,7 +4105,7 @@ function ConfigHistoryModal({
|
|
|
3987
4105
|
historyQuery.fetchNextPage();
|
|
3988
4106
|
}
|
|
3989
4107
|
};
|
|
3990
|
-
return /* @__PURE__ */ jsxs(Modal, { title: "
|
|
4108
|
+
return /* @__PURE__ */ jsxs(Modal, { title: locale("cfgpanel_history_title"), icon: History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
|
|
3991
4109
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
|
|
3992
4110
|
/* @__PURE__ */ jsxs(Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[7], 0.8)}` }, children: [
|
|
3993
4111
|
/* @__PURE__ */ jsx(TextInput, { leftSection: /* @__PURE__ */ jsx(Search, { size: "1.4vh" }), placeholder: "Search path/admin/value", value: queryInput, onChange: (e) => setQueryInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
|
|
@@ -4030,7 +4148,7 @@ function ConfigHistoryModal({
|
|
|
4030
4148
|
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 },
|
|
4031
4149
|
children: [
|
|
4032
4150
|
/* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)", size: "1.5vh" }),
|
|
4033
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "
|
|
4151
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: locale("cfgpanel_close") })
|
|
4034
4152
|
]
|
|
4035
4153
|
}
|
|
4036
4154
|
) })
|
|
@@ -4055,7 +4173,7 @@ function ConfigPanelInner({
|
|
|
4055
4173
|
const theme = useMantineTheme();
|
|
4056
4174
|
const color = theme.colors[theme.primaryColor][5];
|
|
4057
4175
|
const version = useSettings((s) => s.resourceVersion);
|
|
4058
|
-
const [activeTab, setActiveTab] =
|
|
4176
|
+
const [activeTab, setActiveTab] = useAdminState("__dirkConfigPanel:activeTab", navItems[0]?.id ?? "");
|
|
4059
4177
|
const firstMountRef = useRef(true);
|
|
4060
4178
|
const [jsonOpen, setJsonOpen] = useState(false);
|
|
4061
4179
|
const [historyOpen, setHistoryOpen] = useState(false);
|
|
@@ -4090,16 +4208,16 @@ function ConfigPanelInner({
|
|
|
4090
4208
|
/* @__PURE__ */ jsx(AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsx(
|
|
4091
4209
|
ConfirmModal,
|
|
4092
4210
|
{
|
|
4093
|
-
title: "
|
|
4094
|
-
description: "
|
|
4095
|
-
confirmLabel: "
|
|
4211
|
+
title: locale("cfgpanel_reset_title"),
|
|
4212
|
+
description: locale("cfgpanel_reset_desc"),
|
|
4213
|
+
confirmLabel: locale("cfgpanel_reset_confirm"),
|
|
4096
4214
|
confirmText: resetConfirmText,
|
|
4097
4215
|
onConfirm: async () => {
|
|
4098
4216
|
setResetOpen(false);
|
|
4099
4217
|
const result = await resetConfig();
|
|
4100
4218
|
if (result?.success) {
|
|
4101
|
-
const { store } = getScriptConfigInstance();
|
|
4102
|
-
form.reinitialize(cloneConfig(
|
|
4219
|
+
const { store: store2 } = getScriptConfigInstance();
|
|
4220
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
4103
4221
|
notifications.show({
|
|
4104
4222
|
color: "green",
|
|
4105
4223
|
title: locale("ConfigResetSuccessTitle"),
|
|
@@ -4124,9 +4242,9 @@ function ConfigPanelInner({
|
|
|
4124
4242
|
/* @__PURE__ */ jsx(AnimatePresence, { children: pendingAction !== null && /* @__PURE__ */ jsx(
|
|
4125
4243
|
ConfirmModal,
|
|
4126
4244
|
{
|
|
4127
|
-
title: "
|
|
4128
|
-
description: pendingAction === "back" ? "
|
|
4129
|
-
confirmLabel: pendingAction === "back" ? "
|
|
4245
|
+
title: locale("cfgpanel_discard_title"),
|
|
4246
|
+
description: pendingAction === "back" ? locale("cfgpanel_discard_desc_back") : locale("cfgpanel_discard_desc_close"),
|
|
4247
|
+
confirmLabel: pendingAction === "back" ? locale("cfgpanel_discard_confirm_back") : locale("cfgpanel_discard_confirm_close"),
|
|
4130
4248
|
onConfirm: () => {
|
|
4131
4249
|
const action = pendingAction;
|
|
4132
4250
|
setPendingAction(null);
|
|
@@ -4164,7 +4282,7 @@ function ConfigPanelInner({
|
|
|
4164
4282
|
/* @__PURE__ */ jsx(
|
|
4165
4283
|
motion.button,
|
|
4166
4284
|
{
|
|
4167
|
-
title: "
|
|
4285
|
+
title: locale("cfgpanel_back_title"),
|
|
4168
4286
|
onClick: handleBack,
|
|
4169
4287
|
whileHover: { background: alpha(color, 0.16), borderColor: alpha(color, 0.45) },
|
|
4170
4288
|
whileTap: { scale: 0.95 },
|
|
@@ -4192,7 +4310,7 @@ function ConfigPanelInner({
|
|
|
4192
4310
|
/* @__PURE__ */ jsx(
|
|
4193
4311
|
motion.button,
|
|
4194
4312
|
{
|
|
4195
|
-
title: "
|
|
4313
|
+
title: locale("cfgpanel_undo"),
|
|
4196
4314
|
onClick: () => form.canBack && form.back(),
|
|
4197
4315
|
disabled: !form.canBack,
|
|
4198
4316
|
whileHover: form.canBack ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4204,7 +4322,7 @@ function ConfigPanelInner({
|
|
|
4204
4322
|
/* @__PURE__ */ jsx(
|
|
4205
4323
|
motion.button,
|
|
4206
4324
|
{
|
|
4207
|
-
title: "
|
|
4325
|
+
title: locale("cfgpanel_redo"),
|
|
4208
4326
|
onClick: () => form.canForward && form.forward(),
|
|
4209
4327
|
disabled: !form.canForward,
|
|
4210
4328
|
whileHover: form.canForward ? { background: "rgba(255,255,255,0.07)" } : void 0,
|
|
@@ -4216,7 +4334,7 @@ function ConfigPanelInner({
|
|
|
4216
4334
|
/* @__PURE__ */ jsx(
|
|
4217
4335
|
motion.button,
|
|
4218
4336
|
{
|
|
4219
|
-
title: isSaving ? "
|
|
4337
|
+
title: isSaving ? locale("cfgpanel_saving") : isDirty ? `${locale("cfgpanel_save")} (${changedCount})` : locale("cfgpanel_save"),
|
|
4220
4338
|
onClick: () => isDirty && !isSaving && form.submit(),
|
|
4221
4339
|
disabled: !isDirty || isSaving,
|
|
4222
4340
|
whileHover: isDirty && !isSaving ? { background: alpha(color, 0.25), borderColor: alpha(color, 0.5) } : void 0,
|
|
@@ -4228,7 +4346,7 @@ function ConfigPanelInner({
|
|
|
4228
4346
|
/* @__PURE__ */ jsx(
|
|
4229
4347
|
motion.button,
|
|
4230
4348
|
{
|
|
4231
|
-
title: "
|
|
4349
|
+
title: locale("cfgpanel_history"),
|
|
4232
4350
|
onClick: () => setHistoryOpen(true),
|
|
4233
4351
|
whileHover: { background: alpha("#22d3ee", 0.16), borderColor: alpha("#22d3ee", 0.5) },
|
|
4234
4352
|
whileTap: { scale: 0.97 },
|
|
@@ -4249,7 +4367,7 @@ function ConfigPanelInner({
|
|
|
4249
4367
|
style: { width: "100%", background: "transparent", border: `0.1vh solid ${isDirty ? alpha("#f97316", 0.35) : 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" },
|
|
4250
4368
|
children: [
|
|
4251
4369
|
/* @__PURE__ */ jsx(XCircle, { color: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", size: "1.6vh" }),
|
|
4252
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", children: "
|
|
4370
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", children: locale("cfgpanel_discard") })
|
|
4253
4371
|
]
|
|
4254
4372
|
}
|
|
4255
4373
|
),
|
|
@@ -4263,7 +4381,7 @@ function ConfigPanelInner({
|
|
|
4263
4381
|
style: { width: "100%", background: alpha(color, 0.07), border: `0.1vh solid ${alpha(color, 0.28)}`, borderRadius: theme.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
4264
4382
|
children: [
|
|
4265
4383
|
/* @__PURE__ */ jsx(Code2, { color, size: "1.6vh" }),
|
|
4266
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: "
|
|
4384
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("cfgpanel_manual_edit") })
|
|
4267
4385
|
]
|
|
4268
4386
|
}
|
|
4269
4387
|
),
|
|
@@ -4276,12 +4394,13 @@ function ConfigPanelInner({
|
|
|
4276
4394
|
style: { width: "100%", background: alpha("#ef4444", 0.07), border: `0.1vh solid ${alpha("#ef4444", 0.25)}`, borderRadius: theme.radius.xs, padding: "0.65vh 0.8vh", cursor: "pointer", display: "flex", alignItems: "center", gap: "0.55vh" },
|
|
4277
4395
|
children: [
|
|
4278
4396
|
/* @__PURE__ */ jsx(RotateCcw, { color: "#ef4444", size: "1.6vh" }),
|
|
4279
|
-
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: "
|
|
4397
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: locale("cfgpanel_reset_defaults") })
|
|
4280
4398
|
]
|
|
4281
4399
|
}
|
|
4282
4400
|
),
|
|
4283
4401
|
version && /* @__PURE__ */ jsxs(Text, { size: "0.95vh", c: "dimmed", ta: "center", style: { letterSpacing: "0.04em", opacity: 0.8 }, children: [
|
|
4284
|
-
"
|
|
4402
|
+
locale("cfgpanel_version"),
|
|
4403
|
+
" ",
|
|
4285
4404
|
version
|
|
4286
4405
|
] })
|
|
4287
4406
|
] })
|
|
@@ -4327,13 +4446,13 @@ function ServerOnlyFetcher() {
|
|
|
4327
4446
|
var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
|
|
4328
4447
|
function ConfigPanel(props) {
|
|
4329
4448
|
const { open, onClose = defaultOnClose } = props;
|
|
4330
|
-
const { store, updateConfig } = getScriptConfigInstance();
|
|
4449
|
+
const { store: store2, updateConfig } = getScriptConfigInstance();
|
|
4331
4450
|
const [isSaving, setIsSaving] = useState(false);
|
|
4332
4451
|
if (!open) return null;
|
|
4333
|
-
return /* @__PURE__ */ jsx(
|
|
4452
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
|
|
4334
4453
|
FormProvider,
|
|
4335
4454
|
{
|
|
4336
|
-
initialValues: cloneConfig(
|
|
4455
|
+
initialValues: cloneConfig(store2.getState()),
|
|
4337
4456
|
onSubmit: async (form) => {
|
|
4338
4457
|
if (isSaving) return;
|
|
4339
4458
|
setIsSaving(true);
|
|
@@ -4341,7 +4460,7 @@ function ConfigPanel(props) {
|
|
|
4341
4460
|
const result = await updateConfig(form.values);
|
|
4342
4461
|
if (result?.success) {
|
|
4343
4462
|
form.reinitialize(cloneConfig(form.values));
|
|
4344
|
-
|
|
4463
|
+
dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
|
|
4345
4464
|
useMissingItemsAudit.getState().refresh();
|
|
4346
4465
|
notifications.show({
|
|
4347
4466
|
color: "green",
|
|
@@ -4351,7 +4470,7 @@ function ConfigPanel(props) {
|
|
|
4351
4470
|
});
|
|
4352
4471
|
return;
|
|
4353
4472
|
}
|
|
4354
|
-
form.reinitialize(cloneConfig(
|
|
4473
|
+
form.reinitialize(cloneConfig(store2.getState()));
|
|
4355
4474
|
const err = result?._error || "Unknown";
|
|
4356
4475
|
console.warn(`[ConfigPanel] config save failed: ${err}`);
|
|
4357
4476
|
const titleKey = err === "NoPermission" ? "ConfigSaveNoPermissionTitle" : err === "VersionConflict" ? "ConfigSaveVersionConflictTitle" : err === "NotReady" ? "ConfigSaveNotReadyTitle" : "ConfigSaveFailedTitle";
|
|
@@ -4848,6 +4967,9 @@ function GroupName(props) {
|
|
|
4848
4967
|
const ctx = useContext(GroupSelectContext);
|
|
4849
4968
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
4850
4969
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
4970
|
+
useEffect(() => {
|
|
4971
|
+
ensureFrameworkGroups();
|
|
4972
|
+
}, []);
|
|
4851
4973
|
const inCompound = ctx !== null;
|
|
4852
4974
|
const currentValue = inCompound ? ctx.value.name : props.value;
|
|
4853
4975
|
const filterType = inCompound ? ctx.type : props.type;
|
|
@@ -4887,6 +5009,9 @@ function GroupRank(props) {
|
|
|
4887
5009
|
}
|
|
4888
5010
|
const jobs = useFrameworkGroups((s) => s.jobs);
|
|
4889
5011
|
const gangs = useFrameworkGroups((s) => s.gangs);
|
|
5012
|
+
useEffect(() => {
|
|
5013
|
+
ensureFrameworkGroups();
|
|
5014
|
+
}, []);
|
|
4890
5015
|
const all = [...jobs, ...gangs];
|
|
4891
5016
|
const selectedGroup = all.find((g) => g.name === ctx.value.name) ?? null;
|
|
4892
5017
|
const grades = selectedGroup?.grades ?? [];
|
|
@@ -6532,7 +6657,733 @@ function AccountSelect(props) {
|
|
|
6532
6657
|
!hideFrameworkHint && /* @__PURE__ */ jsx(FrameworkHint, { framework })
|
|
6533
6658
|
] });
|
|
6534
6659
|
}
|
|
6660
|
+
var BODY_HIDE_STYLE_ID = "dirk-instruction-panel-style";
|
|
6661
|
+
var BODY_HIDE_ATTR = "data-dirk-instruction-active";
|
|
6662
|
+
var OVERLAY_ATTR = "data-dirk-instruction-overlay";
|
|
6663
|
+
function ensureBodyHideStyle() {
|
|
6664
|
+
if (document.getElementById(BODY_HIDE_STYLE_ID)) return;
|
|
6665
|
+
const el = document.createElement("style");
|
|
6666
|
+
el.id = BODY_HIDE_STYLE_ID;
|
|
6667
|
+
el.textContent = `
|
|
6668
|
+
body[${BODY_HIDE_ATTR}] > *:not([${OVERLAY_ATTR}]) {
|
|
6669
|
+
visibility: hidden !important;
|
|
6670
|
+
opacity: 0 !important;
|
|
6671
|
+
pointer-events: none !important;
|
|
6672
|
+
}
|
|
6673
|
+
`;
|
|
6674
|
+
document.head.appendChild(el);
|
|
6675
|
+
}
|
|
6676
|
+
function InstructionPanel({
|
|
6677
|
+
visible,
|
|
6678
|
+
title,
|
|
6679
|
+
hint,
|
|
6680
|
+
keys,
|
|
6681
|
+
icon: Icon = MapPin,
|
|
6682
|
+
hideRestOfAdmin = true
|
|
6683
|
+
}) {
|
|
6684
|
+
const theme = useMantineTheme();
|
|
6685
|
+
const pc = theme.colors[theme.primaryColor];
|
|
6686
|
+
useEffect(() => {
|
|
6687
|
+
if (!visible || !hideRestOfAdmin) return;
|
|
6688
|
+
ensureBodyHideStyle();
|
|
6689
|
+
document.body.setAttribute(BODY_HIDE_ATTR, "");
|
|
6690
|
+
return () => {
|
|
6691
|
+
document.body.removeAttribute(BODY_HIDE_ATTR);
|
|
6692
|
+
};
|
|
6693
|
+
}, [visible, hideRestOfAdmin]);
|
|
6694
|
+
if (!visible) return null;
|
|
6695
|
+
return createPortal(
|
|
6696
|
+
/* @__PURE__ */ jsx(
|
|
6697
|
+
"div",
|
|
6698
|
+
{
|
|
6699
|
+
...{ [OVERLAY_ATTR]: "" },
|
|
6700
|
+
style: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: 1e4 },
|
|
6701
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(
|
|
6702
|
+
motion.div,
|
|
6703
|
+
{
|
|
6704
|
+
initial: { opacity: 0, y: 12, scale: 0.92 },
|
|
6705
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
6706
|
+
exit: { opacity: 0, y: 12, scale: 0.92 },
|
|
6707
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
6708
|
+
style: { position: "absolute", bottom: "3vh", right: "3vh", userSelect: "none" },
|
|
6709
|
+
children: /* @__PURE__ */ jsxs(
|
|
6710
|
+
Flex,
|
|
6711
|
+
{
|
|
6712
|
+
direction: "column",
|
|
6713
|
+
gap: "0.8vh",
|
|
6714
|
+
style: {
|
|
6715
|
+
background: alpha(theme.colors.dark[9], 0.55),
|
|
6716
|
+
border: "0.1vh solid rgba(255,255,255,0.07)",
|
|
6717
|
+
borderRadius: theme.radius.sm,
|
|
6718
|
+
boxShadow: "0 0.74vh 2.96vh rgba(0,0,0,0.5)",
|
|
6719
|
+
padding: "1.4vh 1.6vh",
|
|
6720
|
+
minWidth: "22vh",
|
|
6721
|
+
maxWidth: "28vh"
|
|
6722
|
+
},
|
|
6723
|
+
children: [
|
|
6724
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: "0.6vh", children: [
|
|
6725
|
+
/* @__PURE__ */ jsx(Icon, { size: "1.6vh", color: pc[6], strokeWidth: 2.5 }),
|
|
6726
|
+
/* @__PURE__ */ jsx(
|
|
6727
|
+
Text,
|
|
6728
|
+
{
|
|
6729
|
+
style: {
|
|
6730
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6731
|
+
fontSize: "1.7vh",
|
|
6732
|
+
fontWeight: 700,
|
|
6733
|
+
letterSpacing: "0.14em",
|
|
6734
|
+
textTransform: "uppercase",
|
|
6735
|
+
color: pc[6],
|
|
6736
|
+
textShadow: `0 0 0.8vh ${alpha(pc[7], 0.5)}, 0 0 1.6vh ${alpha(pc[9], 0.3)}`
|
|
6737
|
+
},
|
|
6738
|
+
children: title
|
|
6739
|
+
}
|
|
6740
|
+
)
|
|
6741
|
+
] }),
|
|
6742
|
+
(hint || keys && keys.length > 0) && /* @__PURE__ */ jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
6743
|
+
hint && /* @__PURE__ */ jsx(
|
|
6744
|
+
Text,
|
|
6745
|
+
{
|
|
6746
|
+
style: {
|
|
6747
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6748
|
+
fontSize: "1.05vh",
|
|
6749
|
+
color: "rgba(255,255,255,0.45)",
|
|
6750
|
+
letterSpacing: "0.06em",
|
|
6751
|
+
textTransform: "uppercase",
|
|
6752
|
+
lineHeight: 1.4
|
|
6753
|
+
},
|
|
6754
|
+
children: hint
|
|
6755
|
+
}
|
|
6756
|
+
),
|
|
6757
|
+
keys && keys.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6758
|
+
hint && /* @__PURE__ */ jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
|
|
6759
|
+
/* @__PURE__ */ jsx(Flex, { direction: "column", gap: "0.5vh", children: keys.map((k, i) => /* @__PURE__ */ jsx(InstructionKeyRow, { keyLabel: k.key, action: k.action }, i)) })
|
|
6760
|
+
] })
|
|
6761
|
+
]
|
|
6762
|
+
}
|
|
6763
|
+
)
|
|
6764
|
+
},
|
|
6765
|
+
"instruction-card"
|
|
6766
|
+
) })
|
|
6767
|
+
}
|
|
6768
|
+
),
|
|
6769
|
+
document.body
|
|
6770
|
+
);
|
|
6771
|
+
}
|
|
6772
|
+
function renderKeyContent(keyLabel) {
|
|
6773
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
6774
|
+
if (normalized === "LMB") return /* @__PURE__ */ jsx(MouseIcon, { side: "left" });
|
|
6775
|
+
if (normalized === "RMB") return /* @__PURE__ */ jsx(MouseIcon, { side: "right" });
|
|
6776
|
+
if (normalized === "BACKSPACE" || keyLabel === "\u232B") return /* @__PURE__ */ jsx(BackspaceIcon, {});
|
|
6777
|
+
return /* @__PURE__ */ jsx(
|
|
6778
|
+
Text,
|
|
6779
|
+
{
|
|
6780
|
+
style: {
|
|
6781
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6782
|
+
fontSize: "1.2vh",
|
|
6783
|
+
color: "rgba(255,255,255,0.85)",
|
|
6784
|
+
lineHeight: 1,
|
|
6785
|
+
padding: "0 0.3vh"
|
|
6786
|
+
},
|
|
6787
|
+
children: keyLabel
|
|
6788
|
+
}
|
|
6789
|
+
);
|
|
6790
|
+
}
|
|
6791
|
+
function InstructionKeyRow({ keyLabel, action }) {
|
|
6792
|
+
const normalized = keyLabel.trim().toUpperCase();
|
|
6793
|
+
const isIconKey = normalized === "LMB" || normalized === "RMB" || normalized === "BACKSPACE" || keyLabel === "\u232B";
|
|
6794
|
+
const minWidth = isIconKey ? "2.6vh" : "2.4vh";
|
|
6795
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "0.6vh", children: [
|
|
6796
|
+
/* @__PURE__ */ jsx(
|
|
6797
|
+
"div",
|
|
6798
|
+
{
|
|
6799
|
+
style: {
|
|
6800
|
+
minWidth,
|
|
6801
|
+
height: "2.4vh",
|
|
6802
|
+
padding: "0 0.4vh",
|
|
6803
|
+
borderRadius: "0.3vh",
|
|
6804
|
+
border: "0.15vh solid rgba(255,255,255,0.35)",
|
|
6805
|
+
background: "rgba(255,255,255,0.06)",
|
|
6806
|
+
display: "flex",
|
|
6807
|
+
alignItems: "center",
|
|
6808
|
+
justifyContent: "center",
|
|
6809
|
+
opacity: 0.85,
|
|
6810
|
+
filter: "drop-shadow(0 0 0.3vh rgba(0,0,0,0.5))",
|
|
6811
|
+
flexShrink: 0,
|
|
6812
|
+
boxSizing: "border-box"
|
|
6813
|
+
},
|
|
6814
|
+
children: renderKeyContent(keyLabel)
|
|
6815
|
+
}
|
|
6816
|
+
),
|
|
6817
|
+
/* @__PURE__ */ jsx(
|
|
6818
|
+
Text,
|
|
6819
|
+
{
|
|
6820
|
+
style: {
|
|
6821
|
+
fontFamily: "Akrobat Bold, sans-serif",
|
|
6822
|
+
fontSize: "1.05vh",
|
|
6823
|
+
color: "rgba(255,255,255,0.45)",
|
|
6824
|
+
letterSpacing: "0.06em",
|
|
6825
|
+
textTransform: "uppercase"
|
|
6826
|
+
},
|
|
6827
|
+
children: action
|
|
6828
|
+
}
|
|
6829
|
+
)
|
|
6830
|
+
] });
|
|
6831
|
+
}
|
|
6832
|
+
function MouseIcon({ side }) {
|
|
6833
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
6834
|
+
const fillActive = "rgba(255,255,255,0.85)";
|
|
6835
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 22", width: "1.4vh", height: "1.9vh", fill: "none", stroke, strokeWidth: "1.4", strokeLinejoin: "round", children: [
|
|
6836
|
+
/* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "14", height: "20", rx: "6" }),
|
|
6837
|
+
/* @__PURE__ */ jsx("line", { x1: "8", y1: "1", x2: "8", y2: "9" }),
|
|
6838
|
+
/* @__PURE__ */ jsx(
|
|
6839
|
+
"path",
|
|
6840
|
+
{
|
|
6841
|
+
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",
|
|
6842
|
+
fill: fillActive,
|
|
6843
|
+
stroke: "none"
|
|
6844
|
+
}
|
|
6845
|
+
)
|
|
6846
|
+
] });
|
|
6847
|
+
}
|
|
6848
|
+
function BackspaceIcon() {
|
|
6849
|
+
const stroke = "rgba(255,255,255,0.85)";
|
|
6850
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 22 16", width: "1.7vh", height: "1.3vh", fill: "none", stroke, strokeWidth: "1.4", strokeLinejoin: "round", strokeLinecap: "round", children: [
|
|
6851
|
+
/* @__PURE__ */ jsx("path", { d: "M 21 2 L 8 2 L 2 8 L 8 14 L 21 14 Z" }),
|
|
6852
|
+
/* @__PURE__ */ jsx("line", { x1: "11", y1: "6", x2: "16", y2: "11" }),
|
|
6853
|
+
/* @__PURE__ */ jsx("line", { x1: "16", y1: "6", x2: "11", y2: "11" })
|
|
6854
|
+
] });
|
|
6855
|
+
}
|
|
6856
|
+
function WorldPositionPicker({ value, onChange, compact, setOnly, gotoOnly }) {
|
|
6857
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6858
|
+
!gotoOnly && /* @__PURE__ */ jsx(WorldPositionSetButton2, { value, onChange, compact }),
|
|
6859
|
+
!setOnly && /* @__PURE__ */ jsx(WorldPositionGotoButton2, { value, compact })
|
|
6860
|
+
] });
|
|
6861
|
+
}
|
|
6862
|
+
function WorldPositionSetButton2({
|
|
6863
|
+
value,
|
|
6864
|
+
onChange,
|
|
6865
|
+
compact
|
|
6866
|
+
}) {
|
|
6867
|
+
const theme = useMantineTheme();
|
|
6868
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
6869
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
6870
|
+
const onClick = async () => {
|
|
6871
|
+
const instructions = {
|
|
6872
|
+
title: locale("PickPositionTitle") || "Pick Position",
|
|
6873
|
+
hint: locale("PickPositionHint") || "Walk to where you want this set",
|
|
6874
|
+
keys: [
|
|
6875
|
+
{ key: "E", action: locale("Set") || "Set" },
|
|
6876
|
+
{ key: "\u232B", action: locale("Cancel") || "Cancel" }
|
|
6877
|
+
]
|
|
6878
|
+
};
|
|
6879
|
+
const pendingResult = begin({ id: "capturePosition", ...instructions });
|
|
6880
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "capturePosition", instructions }).catch(() => {
|
|
6881
|
+
useAdminToolStore.getState().cancelActive();
|
|
6882
|
+
});
|
|
6883
|
+
const result = await pendingResult;
|
|
6884
|
+
if (result) onChange(result);
|
|
6885
|
+
};
|
|
6886
|
+
return /* @__PURE__ */ jsx(Tooltip, { label: locale("SetWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxs(
|
|
6887
|
+
motion.button,
|
|
6888
|
+
{
|
|
6889
|
+
onClick,
|
|
6890
|
+
whileHover: { background: alpha(color, 0.18) },
|
|
6891
|
+
whileTap: { scale: 0.95 },
|
|
6892
|
+
style: {
|
|
6893
|
+
background: alpha(color, 0.1),
|
|
6894
|
+
border: `0.1vh solid ${alpha(color, 0.35)}`,
|
|
6895
|
+
borderRadius: theme.radius.xs,
|
|
6896
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
6897
|
+
cursor: "pointer",
|
|
6898
|
+
display: "flex",
|
|
6899
|
+
alignItems: "center",
|
|
6900
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
6901
|
+
},
|
|
6902
|
+
children: [
|
|
6903
|
+
/* @__PURE__ */ jsx(Crosshair, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
6904
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Set") })
|
|
6905
|
+
]
|
|
6906
|
+
}
|
|
6907
|
+
) });
|
|
6908
|
+
}
|
|
6909
|
+
function WorldPositionGotoButton2({
|
|
6910
|
+
value,
|
|
6911
|
+
compact
|
|
6912
|
+
}) {
|
|
6913
|
+
const theme = useMantineTheme();
|
|
6914
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
6915
|
+
const onClick = () => {
|
|
6916
|
+
fetchNui("ADMIN_TOOL_INVOKE", { id: "gotoCoord", value }).catch(() => {
|
|
6917
|
+
});
|
|
6918
|
+
};
|
|
6919
|
+
return /* @__PURE__ */ jsx(Tooltip, { label: locale("GotoWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxs(
|
|
6920
|
+
motion.button,
|
|
6921
|
+
{
|
|
6922
|
+
onClick,
|
|
6923
|
+
whileHover: { background: alpha(color, 0.18) },
|
|
6924
|
+
whileTap: { scale: 0.95 },
|
|
6925
|
+
style: {
|
|
6926
|
+
background: alpha(color, 0.1),
|
|
6927
|
+
border: `0.1vh solid ${alpha(color, 0.35)}`,
|
|
6928
|
+
borderRadius: theme.radius.xs,
|
|
6929
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
6930
|
+
cursor: "pointer",
|
|
6931
|
+
display: "flex",
|
|
6932
|
+
alignItems: "center",
|
|
6933
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
6934
|
+
},
|
|
6935
|
+
children: [
|
|
6936
|
+
/* @__PURE__ */ jsx(MapPin, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
6937
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Goto") })
|
|
6938
|
+
]
|
|
6939
|
+
}
|
|
6940
|
+
) });
|
|
6941
|
+
}
|
|
6942
|
+
function usePlayers(opts = {}) {
|
|
6943
|
+
const {
|
|
6944
|
+
includeOffline = false,
|
|
6945
|
+
search = "",
|
|
6946
|
+
limit = 50,
|
|
6947
|
+
staleTimeMs,
|
|
6948
|
+
refetchIntervalMs
|
|
6949
|
+
} = opts;
|
|
6950
|
+
const query = useQuery({
|
|
6951
|
+
queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
|
|
6952
|
+
queryFn: async () => {
|
|
6953
|
+
const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
|
|
6954
|
+
const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
|
|
6955
|
+
const result = await fetchNui(
|
|
6956
|
+
"ADMIN_TOOL_QUERY",
|
|
6957
|
+
payload,
|
|
6958
|
+
// Browser-dev fallback. Returns a couple of mock players so the
|
|
6959
|
+
// dev shell isn't blank.
|
|
6960
|
+
includeOffline ? [
|
|
6961
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
|
|
6962
|
+
{ id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
|
|
6963
|
+
] : [
|
|
6964
|
+
{ id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
|
|
6965
|
+
]
|
|
6966
|
+
);
|
|
6967
|
+
return Array.isArray(result) ? result : [];
|
|
6968
|
+
},
|
|
6969
|
+
staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
|
|
6970
|
+
gcTime: 5 * 6e4,
|
|
6971
|
+
refetchInterval: refetchIntervalMs ?? false,
|
|
6972
|
+
refetchOnWindowFocus: false,
|
|
6973
|
+
placeholderData: includeOffline ? keepPreviousData : void 0
|
|
6974
|
+
});
|
|
6975
|
+
return {
|
|
6976
|
+
players: query.data ?? [],
|
|
6977
|
+
isLoading: query.isLoading,
|
|
6978
|
+
isFetching: query.isFetching,
|
|
6979
|
+
error: query.error ?? null,
|
|
6980
|
+
refresh: () => query.refetch()
|
|
6981
|
+
};
|
|
6982
|
+
}
|
|
6983
|
+
var DEBOUNCE_MS = 300;
|
|
6984
|
+
var ONLINE_COLOR = "#3FA83F";
|
|
6985
|
+
var OFFLINE_COLOR = "#E54141";
|
|
6986
|
+
function PlayerSelect({
|
|
6987
|
+
value,
|
|
6988
|
+
onChange,
|
|
6989
|
+
includeOffline = false,
|
|
6990
|
+
limit = 50,
|
|
6991
|
+
searchable: searchableProp,
|
|
6992
|
+
placeholder,
|
|
6993
|
+
nothingFoundMessage: nothingFoundMessageProp,
|
|
6994
|
+
loadingLabel = "Loading\u2026",
|
|
6995
|
+
onlineLabel = "Online",
|
|
6996
|
+
offlineLabel = "Offline",
|
|
6997
|
+
refreshLabel = "Refresh player list",
|
|
6998
|
+
...rest
|
|
6999
|
+
}) {
|
|
7000
|
+
const theme = useMantineTheme();
|
|
7001
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
7002
|
+
const [searchInput, setSearchInput] = useState("");
|
|
7003
|
+
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
7004
|
+
const { players, isFetching, refresh } = usePlayers({
|
|
7005
|
+
includeOffline,
|
|
7006
|
+
search: includeOffline ? debouncedSearch : void 0,
|
|
7007
|
+
limit
|
|
7008
|
+
});
|
|
7009
|
+
const sortedPlayers = useMemo(
|
|
7010
|
+
() => [...players].sort((a, b) => {
|
|
7011
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
7012
|
+
return a.charName.localeCompare(b.charName);
|
|
7013
|
+
}),
|
|
7014
|
+
[players]
|
|
7015
|
+
);
|
|
7016
|
+
const playerByCitizen = useMemo(() => {
|
|
7017
|
+
const m = /* @__PURE__ */ new Map();
|
|
7018
|
+
for (const p of sortedPlayers) m.set(p.citizenId, p);
|
|
7019
|
+
return m;
|
|
7020
|
+
}, [sortedPlayers]);
|
|
7021
|
+
const data = useMemo(() => {
|
|
7022
|
+
const items = sortedPlayers.map((p) => ({
|
|
7023
|
+
value: p.citizenId,
|
|
7024
|
+
label: formatLabel(p)
|
|
7025
|
+
}));
|
|
7026
|
+
if (value && !items.some((i) => i.value === value)) {
|
|
7027
|
+
items.unshift({ value, label: value });
|
|
7028
|
+
}
|
|
7029
|
+
return items;
|
|
7030
|
+
}, [sortedPlayers, value]);
|
|
7031
|
+
const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
|
|
7032
|
+
const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
|
|
7033
|
+
useEffect(() => {
|
|
7034
|
+
if (!includeOffline) return;
|
|
7035
|
+
if (selectedLabel && searchInput === selectedLabel) return;
|
|
7036
|
+
const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
|
|
7037
|
+
return () => clearTimeout(t3);
|
|
7038
|
+
}, [searchInput, includeOffline, selectedLabel]);
|
|
7039
|
+
const renderOption = ({ option }) => {
|
|
7040
|
+
const p = playerByCitizen.get(option.value);
|
|
7041
|
+
if (!p) return option.label;
|
|
7042
|
+
return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
|
|
7043
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
|
|
7044
|
+
/* @__PURE__ */ jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
|
|
7045
|
+
] });
|
|
7046
|
+
};
|
|
7047
|
+
return /* @__PURE__ */ jsx(
|
|
7048
|
+
Select,
|
|
7049
|
+
{
|
|
7050
|
+
...rest,
|
|
7051
|
+
data,
|
|
7052
|
+
value: value ?? null,
|
|
7053
|
+
onChange: (v) => {
|
|
7054
|
+
if (!v) return onChange(null);
|
|
7055
|
+
const player = playerByCitizen.get(v) ?? null;
|
|
7056
|
+
onChange(player);
|
|
7057
|
+
},
|
|
7058
|
+
searchable: searchableProp ?? true,
|
|
7059
|
+
searchValue: includeOffline ? searchInput : void 0,
|
|
7060
|
+
onSearchChange: includeOffline ? setSearchInput : void 0,
|
|
7061
|
+
placeholder,
|
|
7062
|
+
nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
|
|
7063
|
+
maxDropdownHeight: 300,
|
|
7064
|
+
renderOption,
|
|
7065
|
+
leftSection: selectedPlayer ? /* @__PURE__ */ jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
|
|
7066
|
+
rightSectionWidth: "3.5vh",
|
|
7067
|
+
rightSectionPointerEvents: "all",
|
|
7068
|
+
rightSection: /* @__PURE__ */ jsx(
|
|
7069
|
+
ActionIcon,
|
|
7070
|
+
{
|
|
7071
|
+
variant: "subtle",
|
|
7072
|
+
size: "sm",
|
|
7073
|
+
onClick: (e) => {
|
|
7074
|
+
e.stopPropagation();
|
|
7075
|
+
refresh();
|
|
7076
|
+
},
|
|
7077
|
+
"aria-label": refreshLabel,
|
|
7078
|
+
title: refreshLabel,
|
|
7079
|
+
style: { marginRight: "0.6vh" },
|
|
7080
|
+
children: isFetching ? /* @__PURE__ */ jsx(Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsx(RefreshCw, { size: "1.4vh", color })
|
|
7081
|
+
}
|
|
7082
|
+
)
|
|
7083
|
+
}
|
|
7084
|
+
);
|
|
7085
|
+
}
|
|
7086
|
+
function StatusDot({ online, onlineLabel, offlineLabel }) {
|
|
7087
|
+
return /* @__PURE__ */ jsx(
|
|
7088
|
+
"span",
|
|
7089
|
+
{
|
|
7090
|
+
title: online ? onlineLabel : offlineLabel,
|
|
7091
|
+
style: {
|
|
7092
|
+
display: "inline-block",
|
|
7093
|
+
width: "0.9vh",
|
|
7094
|
+
height: "0.9vh",
|
|
7095
|
+
borderRadius: "50%",
|
|
7096
|
+
backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
|
|
7097
|
+
boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
|
|
7098
|
+
flexShrink: 0
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
);
|
|
7102
|
+
}
|
|
7103
|
+
function formatLabel(p) {
|
|
7104
|
+
const parts = [p.charName || p.citizenId];
|
|
7105
|
+
if (p.online) {
|
|
7106
|
+
if (p.name) parts.push(p.name);
|
|
7107
|
+
if (p.id != null) parts.push(`#${p.id}`);
|
|
7108
|
+
}
|
|
7109
|
+
return parts.join(" \xB7 ");
|
|
7110
|
+
}
|
|
7111
|
+
function usePickDoor() {
|
|
7112
|
+
const begin = useAdminToolStore((s) => s.begin);
|
|
7113
|
+
return async () => {
|
|
7114
|
+
const pending = begin({
|
|
7115
|
+
id: "pickDoor",
|
|
7116
|
+
title: locale("PickDoorTitle"),
|
|
7117
|
+
hint: locale("PickDoorHint"),
|
|
7118
|
+
keys: [
|
|
7119
|
+
{ key: "LMB", action: locale("Toggle") },
|
|
7120
|
+
{ key: "E", action: locale("Confirm") },
|
|
7121
|
+
{ key: "BACKSPACE", action: locale("Cancel") }
|
|
7122
|
+
]
|
|
7123
|
+
});
|
|
7124
|
+
fetchNui("ADMIN_TOOL_BEGIN", { id: "pickDoor" }).catch(() => {
|
|
7125
|
+
useAdminToolStore.getState().cancelActive();
|
|
7126
|
+
});
|
|
7127
|
+
return await pending;
|
|
7128
|
+
};
|
|
7129
|
+
}
|
|
7130
|
+
function DoorPickerButton({
|
|
7131
|
+
onPick,
|
|
7132
|
+
compact,
|
|
7133
|
+
label,
|
|
7134
|
+
tooltip
|
|
7135
|
+
}) {
|
|
7136
|
+
const theme = useMantineTheme();
|
|
7137
|
+
const color = theme.colors[theme.primaryColor][5];
|
|
7138
|
+
const pickDoor = usePickDoor();
|
|
7139
|
+
const onClick = async () => {
|
|
7140
|
+
const picked = await pickDoor();
|
|
7141
|
+
if (picked && picked.doors.length > 0) onPick(picked);
|
|
7142
|
+
};
|
|
7143
|
+
return /* @__PURE__ */ jsx(
|
|
7144
|
+
Tooltip,
|
|
7145
|
+
{
|
|
7146
|
+
label: tooltip ?? locale("PickDoorTooltip"),
|
|
7147
|
+
position: "top",
|
|
7148
|
+
withArrow: true,
|
|
7149
|
+
withinPortal: true,
|
|
7150
|
+
zIndex: 2e3,
|
|
7151
|
+
children: /* @__PURE__ */ jsxs(
|
|
7152
|
+
motion.button,
|
|
7153
|
+
{
|
|
7154
|
+
onClick,
|
|
7155
|
+
whileHover: { background: alpha(color, 0.18) },
|
|
7156
|
+
whileTap: { scale: 0.95 },
|
|
7157
|
+
style: {
|
|
7158
|
+
background: alpha(color, 0.1),
|
|
7159
|
+
border: `0.1vh solid ${alpha(color, 0.35)}`,
|
|
7160
|
+
borderRadius: theme.radius.xs,
|
|
7161
|
+
padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
|
|
7162
|
+
cursor: "pointer",
|
|
7163
|
+
display: "flex",
|
|
7164
|
+
alignItems: "center",
|
|
7165
|
+
gap: compact ? "0.3vh" : "0.4vh"
|
|
7166
|
+
},
|
|
7167
|
+
children: [
|
|
7168
|
+
/* @__PURE__ */ jsx(DoorOpen, { size: compact ? "1.1vh" : "1.3vh", color }),
|
|
7169
|
+
/* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: label ?? locale("PickDoor") })
|
|
7170
|
+
]
|
|
7171
|
+
}
|
|
7172
|
+
)
|
|
7173
|
+
}
|
|
7174
|
+
);
|
|
7175
|
+
}
|
|
7176
|
+
var MapImpl = memo(({
|
|
7177
|
+
children,
|
|
7178
|
+
initialZoom = 2,
|
|
7179
|
+
initialCenter = gameToMap(0, 0),
|
|
7180
|
+
mapStyle = "game"
|
|
7181
|
+
}) => {
|
|
7182
|
+
const mapRef = useRef(null);
|
|
7183
|
+
return /* @__PURE__ */ jsxs(
|
|
7184
|
+
MapContainer,
|
|
7185
|
+
{
|
|
7186
|
+
maxBoundsViscosity: 1,
|
|
7187
|
+
preferCanvas: true,
|
|
7188
|
+
zoom: Math.round(initialZoom),
|
|
7189
|
+
zoomSnap: 1,
|
|
7190
|
+
zoomDelta: 1,
|
|
7191
|
+
zoomControl: false,
|
|
7192
|
+
crs: CRS.Simple,
|
|
7193
|
+
style: {
|
|
7194
|
+
height: "100%",
|
|
7195
|
+
width: "100%",
|
|
7196
|
+
overflow: "hidden",
|
|
7197
|
+
outline: "none !important",
|
|
7198
|
+
border: "none !important",
|
|
7199
|
+
boxShadow: "none !important",
|
|
7200
|
+
backgroundColor: "#384950"
|
|
7201
|
+
},
|
|
7202
|
+
center: initialCenter,
|
|
7203
|
+
attributionControl: false,
|
|
7204
|
+
doubleClickZoom: false,
|
|
7205
|
+
inertia: false,
|
|
7206
|
+
zoomAnimation: false,
|
|
7207
|
+
ref: mapRef,
|
|
7208
|
+
maxBounds: [[-250, -250], [250, 250]],
|
|
7209
|
+
children: [
|
|
7210
|
+
/* @__PURE__ */ jsx(MapLayer, { mapLayer: mapStyle }),
|
|
7211
|
+
children
|
|
7212
|
+
]
|
|
7213
|
+
}
|
|
7214
|
+
);
|
|
7215
|
+
});
|
|
7216
|
+
MapImpl.displayName = "DirkMap";
|
|
7217
|
+
var Map2 = MapImpl;
|
|
7218
|
+
var MapLayer = ({ mapLayer }) => {
|
|
7219
|
+
const map = useMap();
|
|
7220
|
+
const layerRef = useRef(null);
|
|
7221
|
+
useEffect(() => {
|
|
7222
|
+
if (layerRef.current) {
|
|
7223
|
+
map.removeLayer(layerRef.current);
|
|
7224
|
+
}
|
|
7225
|
+
const layer = tileLayer(
|
|
7226
|
+
`https://s.rsg.sc/sc/images/games/GTAV/map/${mapLayer}/{z}/{x}/{y}.jpg`,
|
|
7227
|
+
{
|
|
7228
|
+
maxZoom: 6,
|
|
7229
|
+
minZoom: 4,
|
|
7230
|
+
bounds: latLngBounds(latLng(0, 128), latLng(-192, 0)),
|
|
7231
|
+
tileSize: 256,
|
|
7232
|
+
updateWhenZooming: false,
|
|
7233
|
+
keepBuffer: 2,
|
|
7234
|
+
opacity: 0.75
|
|
7235
|
+
}
|
|
7236
|
+
);
|
|
7237
|
+
layer.addTo(map);
|
|
7238
|
+
layerRef.current = layer;
|
|
7239
|
+
return () => {
|
|
7240
|
+
if (layerRef.current) {
|
|
7241
|
+
map.removeLayer(layerRef.current);
|
|
7242
|
+
}
|
|
7243
|
+
};
|
|
7244
|
+
}, [mapLayer, map]);
|
|
7245
|
+
return null;
|
|
7246
|
+
};
|
|
7247
|
+
function ZoomControls() {
|
|
7248
|
+
const theme = useMantineTheme();
|
|
7249
|
+
const map = useMap();
|
|
7250
|
+
const buttons = [
|
|
7251
|
+
{ Icon: Plus, fn: () => map.zoomIn() },
|
|
7252
|
+
{ Icon: Minus, fn: () => map.zoomOut() }
|
|
7253
|
+
];
|
|
7254
|
+
return /* @__PURE__ */ jsx(
|
|
7255
|
+
motion.div,
|
|
7256
|
+
{
|
|
7257
|
+
style: {
|
|
7258
|
+
position: "absolute",
|
|
7259
|
+
right: "2vh",
|
|
7260
|
+
top: "2vh",
|
|
7261
|
+
display: "flex",
|
|
7262
|
+
flexDirection: "column",
|
|
7263
|
+
zIndex: 999999,
|
|
7264
|
+
boxShadow: `0 0 1vh ${alpha(theme.colors.dark[9], 0.85)}`,
|
|
7265
|
+
background: alpha(theme.colors.dark[9], 0.85),
|
|
7266
|
+
borderRadius: theme.radius.xs
|
|
7267
|
+
},
|
|
7268
|
+
initial: { opacity: 0, y: -20 },
|
|
7269
|
+
animate: { opacity: 1, y: 0 },
|
|
7270
|
+
exit: { opacity: 0, y: -20 },
|
|
7271
|
+
children: buttons.map(({ Icon, fn }, i) => /* @__PURE__ */ jsx(
|
|
7272
|
+
motion.div,
|
|
7273
|
+
{
|
|
7274
|
+
whileHover: { scale: 1.1, filter: "brightness(1.5)" },
|
|
7275
|
+
onClick: fn,
|
|
7276
|
+
style: {
|
|
7277
|
+
padding: theme.spacing.xs,
|
|
7278
|
+
cursor: "pointer",
|
|
7279
|
+
display: "flex"
|
|
7280
|
+
},
|
|
7281
|
+
children: /* @__PURE__ */ jsx(Icon, { size: 34, color: theme.colors.gray[5] })
|
|
7282
|
+
},
|
|
7283
|
+
i
|
|
7284
|
+
))
|
|
7285
|
+
}
|
|
7286
|
+
);
|
|
7287
|
+
}
|
|
7288
|
+
var DEFAULT_SPRITE = 162;
|
|
7289
|
+
var DEFAULT_COLOR = 5;
|
|
7290
|
+
function BlipMarker({
|
|
7291
|
+
position,
|
|
7292
|
+
sprite,
|
|
7293
|
+
color,
|
|
7294
|
+
scale = 1,
|
|
7295
|
+
onClick,
|
|
7296
|
+
selected,
|
|
7297
|
+
disabled,
|
|
7298
|
+
fallbackSprite = DEFAULT_SPRITE,
|
|
7299
|
+
fallbackColor = DEFAULT_COLOR
|
|
7300
|
+
}) {
|
|
7301
|
+
const [hovered, setHovered] = useState(false);
|
|
7302
|
+
const mapCoords = useMemo(() => gameToMap(position.x, position.y), [position.x, position.y]);
|
|
7303
|
+
const effectiveSprite = sprite ?? fallbackSprite;
|
|
7304
|
+
const effectiveColor = color ?? fallbackColor;
|
|
7305
|
+
const url = blipUrlForSprite(effectiveSprite);
|
|
7306
|
+
const colorHex = getBlipColor(effectiveColor)?.hex ?? "#ffffff";
|
|
7307
|
+
const handleClick = (e) => {
|
|
7308
|
+
e.originalEvent?.stopPropagation?.();
|
|
7309
|
+
if (disabled) return;
|
|
7310
|
+
onClick?.();
|
|
7311
|
+
};
|
|
7312
|
+
const baseSize = 1.8 * scale;
|
|
7313
|
+
const size = `${baseSize}vh`;
|
|
7314
|
+
const ringSize = `${baseSize * 1.6}vh`;
|
|
7315
|
+
return /* @__PURE__ */ jsx(
|
|
7316
|
+
Marker,
|
|
7317
|
+
{
|
|
7318
|
+
position: mapCoords,
|
|
7319
|
+
eventHandlers: onClick ? { click: handleClick } : void 0,
|
|
7320
|
+
icon: /* @__PURE__ */ jsxs(
|
|
7321
|
+
motion.div,
|
|
7322
|
+
{
|
|
7323
|
+
onHoverStart: () => setHovered(true),
|
|
7324
|
+
onHoverEnd: () => setHovered(false),
|
|
7325
|
+
style: {
|
|
7326
|
+
position: "relative",
|
|
7327
|
+
display: "flex",
|
|
7328
|
+
alignItems: "center",
|
|
7329
|
+
justifyContent: "center",
|
|
7330
|
+
cursor: disabled ? "not-allowed" : onClick ? "pointer" : "default",
|
|
7331
|
+
opacity: disabled ? 0.35 : 1,
|
|
7332
|
+
width: size,
|
|
7333
|
+
height: size
|
|
7334
|
+
},
|
|
7335
|
+
animate: { scale: hovered && !disabled ? 1.2 : selected ? 1.15 : 1 },
|
|
7336
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
7337
|
+
children: [
|
|
7338
|
+
(selected || hovered) && !disabled && /* @__PURE__ */ jsx(
|
|
7339
|
+
motion.div,
|
|
7340
|
+
{
|
|
7341
|
+
style: {
|
|
7342
|
+
position: "absolute",
|
|
7343
|
+
width: ringSize,
|
|
7344
|
+
height: ringSize,
|
|
7345
|
+
borderRadius: "50%",
|
|
7346
|
+
border: `0.18vh solid ${alpha(colorHex, 0.85)}`,
|
|
7347
|
+
boxShadow: `0 0 1vh ${alpha(colorHex, 0.55)}`
|
|
7348
|
+
},
|
|
7349
|
+
initial: { opacity: 0, scale: 0.8 },
|
|
7350
|
+
animate: { opacity: 1, scale: 1 }
|
|
7351
|
+
}
|
|
7352
|
+
),
|
|
7353
|
+
url && /* @__PURE__ */ jsx(
|
|
7354
|
+
"div",
|
|
7355
|
+
{
|
|
7356
|
+
style: {
|
|
7357
|
+
width: size,
|
|
7358
|
+
height: size,
|
|
7359
|
+
backgroundColor: colorHex,
|
|
7360
|
+
WebkitMaskImage: `url(${url})`,
|
|
7361
|
+
maskImage: `url(${url})`,
|
|
7362
|
+
WebkitMaskRepeat: "no-repeat",
|
|
7363
|
+
maskRepeat: "no-repeat",
|
|
7364
|
+
WebkitMaskPosition: "center",
|
|
7365
|
+
maskPosition: "center",
|
|
7366
|
+
WebkitMaskSize: "contain",
|
|
7367
|
+
maskSize: "contain",
|
|
7368
|
+
filter: [
|
|
7369
|
+
"drop-shadow(0.12vh 0 0 #000)",
|
|
7370
|
+
"drop-shadow(-0.12vh 0 0 #000)",
|
|
7371
|
+
"drop-shadow(0 0.12vh 0 #000)",
|
|
7372
|
+
"drop-shadow(0 -0.12vh 0 #000)",
|
|
7373
|
+
`drop-shadow(0 0 0.4vh ${alpha("#000", 0.7)})`
|
|
7374
|
+
].join(" "),
|
|
7375
|
+
pointerEvents: "none",
|
|
7376
|
+
userSelect: "none"
|
|
7377
|
+
}
|
|
7378
|
+
}
|
|
7379
|
+
)
|
|
7380
|
+
]
|
|
7381
|
+
}
|
|
7382
|
+
)
|
|
7383
|
+
}
|
|
7384
|
+
);
|
|
7385
|
+
}
|
|
6535
7386
|
|
|
6536
|
-
export { AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DiscordRoleSelect, FiveMKeyBindInput, FloatingParticles, GroupName, GroupRank, GroupSelect, InfoBox, InputContainer, LevelBanner, LevelPanel, MissingItemsBanner, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PositionPicker, PromptModal, ScenarioSelect, SegmentedControl, SegmentedProgress, SelectItem, SwitchPanel, TestBed, ThemeOverrideSection, Title, Vector4DeleteButton, Vector4Display, WorldPositionGotoButton, WorldPositionSetButton, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore };
|
|
7387
|
+
export { AccountSelect, AdminPageTitle, AnimPostFxSelect, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BlipMarker, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DiscordRoleSelect, DoorPickerButton, FiveMKeyBindInput, FloatingParticles, GroupName, GroupRank, GroupSelect, InfoBox, InputContainer, InstructionPanel, LevelBanner, LevelPanel, Map2 as Map, MapLayer, MissingItemsBanner, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PlayerSelect, PositionPicker, PromptModal, ScenarioSelect, SegmentedControl, SegmentedProgress, SelectItem, SwitchPanel, TestBed, ThemeOverrideSection, Title, Vector4DeleteButton, Vector4Display, WorldPositionGotoButton, WorldPositionPicker, WorldPositionSetButton, ZoomControls, blipUrl, blipUrlForSprite, getBlipColor, getBlipEntry, useAdminToolStore, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, usePickDoor };
|
|
6537
7388
|
//# sourceMappingURL=index.js.map
|
|
6538
7389
|
//# sourceMappingURL=index.js.map
|