dirk-cfx-react 1.1.87 → 1.1.89

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.
@@ -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, alpha12) {
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}, ${alpha12})`;
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}, ${alpha12})`;
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]}, ${alpha12})`;
1284
+ return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha17})`;
1258
1285
  }
1259
1286
  }
1260
1287
  return color;
@@ -1349,9 +1376,22 @@ if (typeof window !== "undefined") {
1349
1376
  const msg = event.data;
1350
1377
  if (!msg || msg.action !== "UPDATE_DIRK_LIB_LOCALES") return;
1351
1378
  if (!msg.data || typeof msg.data !== "object") return;
1379
+ if (Object.keys(msg.data).length === 0) return;
1352
1380
  localeStore.setState({ locales: msg.data });
1353
1381
  });
1354
1382
  }
1383
+
1384
+ // src/utils/map.ts
1385
+ var mapCenter = [-119.43, 58.84];
1386
+ var latPr100 = 1.421;
1387
+ function gameToMap(x, y) {
1388
+ return [
1389
+ mapCenter[0] + latPr100 / 100 * y,
1390
+ // lng
1391
+ mapCenter[1] + latPr100 / 100 * x
1392
+ // lat
1393
+ ];
1394
+ }
1355
1395
  var useItems = zustand.create(() => ({}));
1356
1396
  var useItemsList = (excludeItemNames = []) => {
1357
1397
  const excludeSet = new Set(excludeItemNames);
@@ -1371,15 +1411,21 @@ var useFrameworkGroups = zustand.create(() => ({
1371
1411
  gangs: [],
1372
1412
  loaded: false
1373
1413
  }));
1374
- registerInitialFetch("GET_FRAMEWORK_GROUPS", void 0).then((data) => {
1375
- useFrameworkGroups.setState({
1376
- jobs: Array.isArray(data?.jobs) ? data.jobs : [],
1377
- gangs: Array.isArray(data?.gangs) ? data.gangs : [],
1378
- loaded: true
1414
+ var frameworkGroupsRequested = false;
1415
+ function ensureFrameworkGroups() {
1416
+ if (frameworkGroupsRequested) return;
1417
+ frameworkGroupsRequested = true;
1418
+ fetchNui("GET_FRAMEWORK_GROUPS", void 0).then((data) => {
1419
+ useFrameworkGroups.setState({
1420
+ jobs: Array.isArray(data?.jobs) ? data.jobs : [],
1421
+ gangs: Array.isArray(data?.gangs) ? data.gangs : [],
1422
+ loaded: true
1423
+ });
1424
+ }).catch(() => {
1425
+ frameworkGroupsRequested = false;
1426
+ useFrameworkGroups.setState({ loaded: true });
1379
1427
  });
1380
- }).catch(() => {
1381
- useFrameworkGroups.setState({ loaded: true });
1382
- });
1428
+ }
1383
1429
 
1384
1430
  // src/utils/inputMapper.ts
1385
1431
  var INPUT_MAPPER_PRIMARY_OPTIONS = [
@@ -2388,7 +2434,7 @@ function NavigationProvider({ children, defaultPage }) {
2388
2434
  }
2389
2435
  function NavBar(props) {
2390
2436
  const pageId = useNavigation((state) => state.pageId);
2391
- const store = useNavigationStore();
2437
+ const store2 = useNavigationStore();
2392
2438
  return /* @__PURE__ */ jsxRuntime.jsx(
2393
2439
  SegmentedControl,
2394
2440
  {
@@ -2397,7 +2443,7 @@ function NavBar(props) {
2397
2443
  value: pageId,
2398
2444
  items: props.items,
2399
2445
  onChange: (value) => {
2400
- store.setState({ pageId: value });
2446
+ store2.setState({ pageId: value });
2401
2447
  }
2402
2448
  }
2403
2449
  );
@@ -3704,34 +3750,82 @@ function FormProvider({
3704
3750
  return /* @__PURE__ */ jsxRuntime.jsx(FormContext.Provider, { value: storeRef.current, children });
3705
3751
  }
3706
3752
  function useForm() {
3707
- const store = react.useContext(FormContext);
3708
- if (!store) {
3753
+ const store2 = react.useContext(FormContext);
3754
+ if (!store2) {
3709
3755
  throw new Error("useForm must be used inside <FormProvider>");
3710
3756
  }
3711
- const state = zustand.useStore(store);
3757
+ const state = zustand.useStore(store2);
3712
3758
  const changedFields = react.useMemo(() => {
3713
3759
  return collectChangedPaths(state.values, state.initialValues);
3714
3760
  }, [state.values, state.initialValues]);
3715
3761
  return { ...state, changedFields, changedCount: changedFields.length };
3716
3762
  }
3717
3763
  function useFormField(path) {
3718
- const store = react.useContext(FormContext);
3719
- if (!store) {
3764
+ const store2 = react.useContext(FormContext);
3765
+ if (!store2) {
3720
3766
  throw new Error("useFormField must be used inside <FormProvider>");
3721
3767
  }
3722
- return zustand.useStore(store, (s) => getNested(s.values, path));
3768
+ return zustand.useStore(store2, (s) => getNested(s.values, path));
3723
3769
  }
3724
3770
  function useFormActions() {
3725
- const store = react.useContext(FormContext);
3726
- if (!store) {
3771
+ const store2 = react.useContext(FormContext);
3772
+ if (!store2) {
3727
3773
  throw new Error("useFormActions must be used inside <FormProvider>");
3728
3774
  }
3729
- return store.getState();
3775
+ return store2.getState();
3776
+ }
3777
+ var store = /* @__PURE__ */ new Map();
3778
+ var listeners = /* @__PURE__ */ new Map();
3779
+ function notify(key) {
3780
+ const ls = listeners.get(key);
3781
+ if (!ls) return;
3782
+ ls.forEach((fn) => fn());
3783
+ }
3784
+ function useAdminState(key, initial) {
3785
+ const [, setTick] = react.useState(0);
3786
+ react.useEffect(() => {
3787
+ const set = listeners.get(key) ?? /* @__PURE__ */ new Set();
3788
+ listeners.set(key, set);
3789
+ const handler = () => setTick((t3) => t3 + 1);
3790
+ set.add(handler);
3791
+ return () => {
3792
+ set.delete(handler);
3793
+ if (set.size === 0) listeners.delete(key);
3794
+ };
3795
+ }, [key]);
3796
+ const value = store.has(key) ? store.get(key) : initial;
3797
+ const setValue = (v) => {
3798
+ const next = typeof v === "function" ? v(value) : v;
3799
+ store.set(key, next);
3800
+ notify(key);
3801
+ };
3802
+ return [value, setValue];
3730
3803
  }
3731
3804
  function getScriptConfigInstance() {
3732
3805
  throw new Error("[dirk-cfx-react] createScriptConfig must be called before using ConfigPanel");
3733
3806
  }
3734
- var configPanelQueryClient = new reactQuery.QueryClient({
3807
+ var useAdminToolStore = zustand.create((set, get) => ({
3808
+ active: null,
3809
+ begin: (spec) => new Promise((resolve) => {
3810
+ const prev = get().active;
3811
+ if (prev) prev.resolve(null);
3812
+ set({ active: { ...spec, resolve } });
3813
+ }),
3814
+ resolveActive: (value) => {
3815
+ const cur = get().active;
3816
+ if (!cur) return;
3817
+ cur.resolve(value);
3818
+ set({ active: null });
3819
+ },
3820
+ cancelActive: () => {
3821
+ const cur = get().active;
3822
+ if (!cur) return;
3823
+ cur.resolve(null);
3824
+ set({ active: null });
3825
+ }
3826
+ }));
3827
+ fontawesomeSvgCore.library.add(freeSolidSvgIcons.fas, freeRegularSvgIcons.far, freeBrandsSvgIcons.fab);
3828
+ var dirkQueryClient = new reactQuery.QueryClient({
3735
3829
  defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
3736
3830
  });
3737
3831
  function NavItemButton({
@@ -4062,7 +4156,7 @@ function ConfigPanelInner({
4062
4156
  const theme = core.useMantineTheme();
4063
4157
  const color = theme.colors[theme.primaryColor][5];
4064
4158
  const version = useSettings((s) => s.resourceVersion);
4065
- const [activeTab, setActiveTab] = react.useState(navItems[0]?.id ?? "");
4159
+ const [activeTab, setActiveTab] = useAdminState("__dirkConfigPanel:activeTab", navItems[0]?.id ?? "");
4066
4160
  const firstMountRef = react.useRef(true);
4067
4161
  const [jsonOpen, setJsonOpen] = react.useState(false);
4068
4162
  const [historyOpen, setHistoryOpen] = react.useState(false);
@@ -4105,8 +4199,8 @@ function ConfigPanelInner({
4105
4199
  setResetOpen(false);
4106
4200
  const result = await resetConfig();
4107
4201
  if (result?.success) {
4108
- const { store } = getScriptConfigInstance();
4109
- form.reinitialize(cloneConfig(store.getState()));
4202
+ const { store: store2 } = getScriptConfigInstance();
4203
+ form.reinitialize(cloneConfig(store2.getState()));
4110
4204
  notifications.notifications.show({
4111
4205
  color: "green",
4112
4206
  title: locale("ConfigResetSuccessTitle"),
@@ -4334,13 +4428,13 @@ function ServerOnlyFetcher() {
4334
4428
  var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
4335
4429
  function ConfigPanel(props) {
4336
4430
  const { open, onClose = defaultOnClose } = props;
4337
- const { store, updateConfig } = getScriptConfigInstance();
4431
+ const { store: store2, updateConfig } = getScriptConfigInstance();
4338
4432
  const [isSaving, setIsSaving] = react.useState(false);
4339
4433
  if (!open) return null;
4340
- return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: configPanelQueryClient, children: /* @__PURE__ */ jsxRuntime.jsxs(
4434
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
4341
4435
  FormProvider,
4342
4436
  {
4343
- initialValues: cloneConfig(store.getState()),
4437
+ initialValues: cloneConfig(store2.getState()),
4344
4438
  onSubmit: async (form) => {
4345
4439
  if (isSaving) return;
4346
4440
  setIsSaving(true);
@@ -4348,7 +4442,7 @@ function ConfigPanel(props) {
4348
4442
  const result = await updateConfig(form.values);
4349
4443
  if (result?.success) {
4350
4444
  form.reinitialize(cloneConfig(form.values));
4351
- configPanelQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
4445
+ dirkQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
4352
4446
  useMissingItemsAudit.getState().refresh();
4353
4447
  notifications.notifications.show({
4354
4448
  color: "green",
@@ -4358,7 +4452,7 @@ function ConfigPanel(props) {
4358
4452
  });
4359
4453
  return;
4360
4454
  }
4361
- form.reinitialize(cloneConfig(store.getState()));
4455
+ form.reinitialize(cloneConfig(store2.getState()));
4362
4456
  const err = result?._error || "Unknown";
4363
4457
  console.warn(`[ConfigPanel] config save failed: ${err}`);
4364
4458
  const titleKey = err === "NoPermission" ? "ConfigSaveNoPermissionTitle" : err === "VersionConflict" ? "ConfigSaveVersionConflictTitle" : err === "NotReady" ? "ConfigSaveNotReadyTitle" : "ConfigSaveFailedTitle";
@@ -4855,6 +4949,9 @@ function GroupName(props) {
4855
4949
  const ctx = react.useContext(GroupSelectContext);
4856
4950
  const jobs = useFrameworkGroups((s) => s.jobs);
4857
4951
  const gangs = useFrameworkGroups((s) => s.gangs);
4952
+ react.useEffect(() => {
4953
+ ensureFrameworkGroups();
4954
+ }, []);
4858
4955
  const inCompound = ctx !== null;
4859
4956
  const currentValue = inCompound ? ctx.value.name : props.value;
4860
4957
  const filterType = inCompound ? ctx.type : props.type;
@@ -4894,6 +4991,9 @@ function GroupRank(props) {
4894
4991
  }
4895
4992
  const jobs = useFrameworkGroups((s) => s.jobs);
4896
4993
  const gangs = useFrameworkGroups((s) => s.gangs);
4994
+ react.useEffect(() => {
4995
+ ensureFrameworkGroups();
4996
+ }, []);
4897
4997
  const all = [...jobs, ...gangs];
4898
4998
  const selectedGroup = all.find((g) => g.name === ctx.value.name) ?? null;
4899
4999
  const grades = selectedGroup?.grades ?? [];
@@ -6539,6 +6639,732 @@ function AccountSelect(props) {
6539
6639
  !hideFrameworkHint && /* @__PURE__ */ jsxRuntime.jsx(FrameworkHint, { framework })
6540
6640
  ] });
6541
6641
  }
6642
+ var BODY_HIDE_STYLE_ID = "dirk-instruction-panel-style";
6643
+ var BODY_HIDE_ATTR = "data-dirk-instruction-active";
6644
+ var OVERLAY_ATTR = "data-dirk-instruction-overlay";
6645
+ function ensureBodyHideStyle() {
6646
+ if (document.getElementById(BODY_HIDE_STYLE_ID)) return;
6647
+ const el = document.createElement("style");
6648
+ el.id = BODY_HIDE_STYLE_ID;
6649
+ el.textContent = `
6650
+ body[${BODY_HIDE_ATTR}] > *:not([${OVERLAY_ATTR}]) {
6651
+ visibility: hidden !important;
6652
+ opacity: 0 !important;
6653
+ pointer-events: none !important;
6654
+ }
6655
+ `;
6656
+ document.head.appendChild(el);
6657
+ }
6658
+ function InstructionPanel({
6659
+ visible,
6660
+ title,
6661
+ hint,
6662
+ keys,
6663
+ icon: Icon = lucideReact.MapPin,
6664
+ hideRestOfAdmin = true
6665
+ }) {
6666
+ const theme = core.useMantineTheme();
6667
+ const pc = theme.colors[theme.primaryColor];
6668
+ react.useEffect(() => {
6669
+ if (!visible || !hideRestOfAdmin) return;
6670
+ ensureBodyHideStyle();
6671
+ document.body.setAttribute(BODY_HIDE_ATTR, "");
6672
+ return () => {
6673
+ document.body.removeAttribute(BODY_HIDE_ATTR);
6674
+ };
6675
+ }, [visible, hideRestOfAdmin]);
6676
+ if (!visible) return null;
6677
+ return reactDom.createPortal(
6678
+ /* @__PURE__ */ jsxRuntime.jsx(
6679
+ "div",
6680
+ {
6681
+ ...{ [OVERLAY_ATTR]: "" },
6682
+ style: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: 1e4 },
6683
+ children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
6684
+ framerMotion.motion.div,
6685
+ {
6686
+ initial: { opacity: 0, y: 12, scale: 0.92 },
6687
+ animate: { opacity: 1, y: 0, scale: 1 },
6688
+ exit: { opacity: 0, y: 12, scale: 0.92 },
6689
+ transition: { duration: 0.25, ease: "easeInOut" },
6690
+ style: { position: "absolute", bottom: "3vh", right: "3vh", userSelect: "none" },
6691
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
6692
+ core.Flex,
6693
+ {
6694
+ direction: "column",
6695
+ gap: "0.8vh",
6696
+ style: {
6697
+ background: core.alpha(theme.colors.dark[9], 0.55),
6698
+ border: "0.1vh solid rgba(255,255,255,0.07)",
6699
+ borderRadius: theme.radius.sm,
6700
+ boxShadow: "0 0.74vh 2.96vh rgba(0,0,0,0.5)",
6701
+ padding: "1.4vh 1.6vh",
6702
+ minWidth: "22vh",
6703
+ maxWidth: "28vh"
6704
+ },
6705
+ children: [
6706
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
6707
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "1.6vh", color: pc[6], strokeWidth: 2.5 }),
6708
+ /* @__PURE__ */ jsxRuntime.jsx(
6709
+ core.Text,
6710
+ {
6711
+ style: {
6712
+ fontFamily: "Akrobat Bold, sans-serif",
6713
+ fontSize: "1.7vh",
6714
+ fontWeight: 700,
6715
+ letterSpacing: "0.14em",
6716
+ textTransform: "uppercase",
6717
+ color: pc[6],
6718
+ textShadow: `0 0 0.8vh ${core.alpha(pc[7], 0.5)}, 0 0 1.6vh ${core.alpha(pc[9], 0.3)}`
6719
+ },
6720
+ children: title
6721
+ }
6722
+ )
6723
+ ] }),
6724
+ (hint || keys && keys.length > 0) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
6725
+ hint && /* @__PURE__ */ jsxRuntime.jsx(
6726
+ core.Text,
6727
+ {
6728
+ style: {
6729
+ fontFamily: "Akrobat Bold, sans-serif",
6730
+ fontSize: "1.05vh",
6731
+ color: "rgba(255,255,255,0.45)",
6732
+ letterSpacing: "0.06em",
6733
+ textTransform: "uppercase",
6734
+ lineHeight: 1.4
6735
+ },
6736
+ children: hint
6737
+ }
6738
+ ),
6739
+ keys && keys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6740
+ hint && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.1vh", background: "rgba(255,255,255,0.06)", margin: "0.1vh 0" } }),
6741
+ /* @__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)) })
6742
+ ] })
6743
+ ]
6744
+ }
6745
+ )
6746
+ },
6747
+ "instruction-card"
6748
+ ) })
6749
+ }
6750
+ ),
6751
+ document.body
6752
+ );
6753
+ }
6754
+ function renderKeyContent(keyLabel) {
6755
+ const normalized = keyLabel.trim().toUpperCase();
6756
+ if (normalized === "LMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "left" });
6757
+ if (normalized === "RMB") return /* @__PURE__ */ jsxRuntime.jsx(MouseIcon, { side: "right" });
6758
+ if (normalized === "BACKSPACE" || keyLabel === "\u232B") return /* @__PURE__ */ jsxRuntime.jsx(BackspaceIcon, {});
6759
+ return /* @__PURE__ */ jsxRuntime.jsx(
6760
+ core.Text,
6761
+ {
6762
+ style: {
6763
+ fontFamily: "Akrobat Bold, sans-serif",
6764
+ fontSize: "1.2vh",
6765
+ color: "rgba(255,255,255,0.85)",
6766
+ lineHeight: 1,
6767
+ padding: "0 0.3vh"
6768
+ },
6769
+ children: keyLabel
6770
+ }
6771
+ );
6772
+ }
6773
+ function InstructionKeyRow({ keyLabel, action }) {
6774
+ const normalized = keyLabel.trim().toUpperCase();
6775
+ const isIconKey = normalized === "LMB" || normalized === "RMB" || normalized === "BACKSPACE" || keyLabel === "\u232B";
6776
+ const minWidth = isIconKey ? "2.6vh" : "2.4vh";
6777
+ return /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "0.6vh", children: [
6778
+ /* @__PURE__ */ jsxRuntime.jsx(
6779
+ "div",
6780
+ {
6781
+ style: {
6782
+ minWidth,
6783
+ height: "2.4vh",
6784
+ padding: "0 0.4vh",
6785
+ borderRadius: "0.3vh",
6786
+ border: "0.15vh solid rgba(255,255,255,0.35)",
6787
+ background: "rgba(255,255,255,0.06)",
6788
+ display: "flex",
6789
+ alignItems: "center",
6790
+ justifyContent: "center",
6791
+ opacity: 0.85,
6792
+ filter: "drop-shadow(0 0 0.3vh rgba(0,0,0,0.5))",
6793
+ flexShrink: 0,
6794
+ boxSizing: "border-box"
6795
+ },
6796
+ children: renderKeyContent(keyLabel)
6797
+ }
6798
+ ),
6799
+ /* @__PURE__ */ jsxRuntime.jsx(
6800
+ core.Text,
6801
+ {
6802
+ style: {
6803
+ fontFamily: "Akrobat Bold, sans-serif",
6804
+ fontSize: "1.05vh",
6805
+ color: "rgba(255,255,255,0.45)",
6806
+ letterSpacing: "0.06em",
6807
+ textTransform: "uppercase"
6808
+ },
6809
+ children: action
6810
+ }
6811
+ )
6812
+ ] });
6813
+ }
6814
+ function MouseIcon({ side }) {
6815
+ const stroke = "rgba(255,255,255,0.85)";
6816
+ const fillActive = "rgba(255,255,255,0.85)";
6817
+ 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: [
6818
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "1", width: "14", height: "20", rx: "6" }),
6819
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "1", x2: "8", y2: "9" }),
6820
+ /* @__PURE__ */ jsxRuntime.jsx(
6821
+ "path",
6822
+ {
6823
+ 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",
6824
+ fill: fillActive,
6825
+ stroke: "none"
6826
+ }
6827
+ )
6828
+ ] });
6829
+ }
6830
+ function BackspaceIcon() {
6831
+ const stroke = "rgba(255,255,255,0.85)";
6832
+ 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: [
6833
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 21 2 L 8 2 L 2 8 L 8 14 L 21 14 Z" }),
6834
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "11", y1: "6", x2: "16", y2: "11" }),
6835
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "6", x2: "11", y2: "11" })
6836
+ ] });
6837
+ }
6838
+ function WorldPositionPicker({ value, onChange, compact, setOnly, gotoOnly }) {
6839
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6840
+ !gotoOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionSetButton2, { value, onChange, compact }),
6841
+ !setOnly && /* @__PURE__ */ jsxRuntime.jsx(WorldPositionGotoButton2, { value, compact })
6842
+ ] });
6843
+ }
6844
+ function WorldPositionSetButton2({
6845
+ value,
6846
+ onChange,
6847
+ compact
6848
+ }) {
6849
+ const theme = core.useMantineTheme();
6850
+ const color = theme.colors[theme.primaryColor][5];
6851
+ const begin = useAdminToolStore((s) => s.begin);
6852
+ const onClick = async () => {
6853
+ const instructions = {
6854
+ title: locale("PickPositionTitle") || "Pick Position",
6855
+ hint: locale("PickPositionHint") || "Walk to where you want this set",
6856
+ keys: [
6857
+ { key: "E", action: locale("Set") || "Set" },
6858
+ { key: "\u232B", action: locale("Cancel") || "Cancel" }
6859
+ ]
6860
+ };
6861
+ const pendingResult = begin({ id: "capturePosition", ...instructions });
6862
+ fetchNui("ADMIN_TOOL_BEGIN", { id: "capturePosition", instructions }).catch(() => {
6863
+ useAdminToolStore.getState().cancelActive();
6864
+ });
6865
+ const result = await pendingResult;
6866
+ if (result) onChange(result);
6867
+ };
6868
+ return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("SetWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
6869
+ framerMotion.motion.button,
6870
+ {
6871
+ onClick,
6872
+ whileHover: { background: core.alpha(color, 0.18) },
6873
+ whileTap: { scale: 0.95 },
6874
+ style: {
6875
+ background: core.alpha(color, 0.1),
6876
+ border: `0.1vh solid ${core.alpha(color, 0.35)}`,
6877
+ borderRadius: theme.radius.xs,
6878
+ padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
6879
+ cursor: "pointer",
6880
+ display: "flex",
6881
+ alignItems: "center",
6882
+ gap: compact ? "0.3vh" : "0.4vh"
6883
+ },
6884
+ children: [
6885
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crosshair, { size: compact ? "1.1vh" : "1.3vh", color }),
6886
+ /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Set") })
6887
+ ]
6888
+ }
6889
+ ) });
6890
+ }
6891
+ function WorldPositionGotoButton2({
6892
+ value,
6893
+ compact
6894
+ }) {
6895
+ const theme = core.useMantineTheme();
6896
+ const color = theme.colors[theme.primaryColor][5];
6897
+ const onClick = () => {
6898
+ fetchNui("ADMIN_TOOL_INVOKE", { id: "gotoCoord", value }).catch(() => {
6899
+ });
6900
+ };
6901
+ return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: locale("GotoWorldTooltip"), position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxRuntime.jsxs(
6902
+ framerMotion.motion.button,
6903
+ {
6904
+ onClick,
6905
+ whileHover: { background: core.alpha(color, 0.18) },
6906
+ whileTap: { scale: 0.95 },
6907
+ style: {
6908
+ background: core.alpha(color, 0.1),
6909
+ border: `0.1vh solid ${core.alpha(color, 0.35)}`,
6910
+ borderRadius: theme.radius.xs,
6911
+ padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
6912
+ cursor: "pointer",
6913
+ display: "flex",
6914
+ alignItems: "center",
6915
+ gap: compact ? "0.3vh" : "0.4vh"
6916
+ },
6917
+ children: [
6918
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { size: compact ? "1.1vh" : "1.3vh", color }),
6919
+ /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: locale("Goto") })
6920
+ ]
6921
+ }
6922
+ ) });
6923
+ }
6924
+ function usePlayers(opts = {}) {
6925
+ const {
6926
+ includeOffline = false,
6927
+ search = "",
6928
+ limit = 50,
6929
+ staleTimeMs,
6930
+ refetchIntervalMs
6931
+ } = opts;
6932
+ const query = reactQuery.useQuery({
6933
+ queryKey: includeOffline ? ["dirk:players", "search", search.trim().toLowerCase(), limit] : ["dirk:players", "online"],
6934
+ queryFn: async () => {
6935
+ const toolId = includeOffline ? "searchPlayers" : "getOnlinePlayers";
6936
+ const payload = includeOffline ? { id: toolId, value: { search: search.trim(), limit } } : { id: toolId };
6937
+ const result = await fetchNui(
6938
+ "ADMIN_TOOL_QUERY",
6939
+ payload,
6940
+ // Browser-dev fallback. Returns a couple of mock players so the
6941
+ // dev shell isn't blank.
6942
+ includeOffline ? [
6943
+ { id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true },
6944
+ { id: null, citizenId: "DEF67890", name: "", charName: "Jane Offline", online: false }
6945
+ ] : [
6946
+ { id: 1, citizenId: "ABC12345", name: "Dev User", charName: "John Doe", online: true }
6947
+ ]
6948
+ );
6949
+ return Array.isArray(result) ? result : [];
6950
+ },
6951
+ staleTime: staleTimeMs ?? (includeOffline ? 3e4 : 5e3),
6952
+ gcTime: 5 * 6e4,
6953
+ refetchInterval: refetchIntervalMs ?? false,
6954
+ refetchOnWindowFocus: false,
6955
+ placeholderData: includeOffline ? reactQuery.keepPreviousData : void 0
6956
+ });
6957
+ return {
6958
+ players: query.data ?? [],
6959
+ isLoading: query.isLoading,
6960
+ isFetching: query.isFetching,
6961
+ error: query.error ?? null,
6962
+ refresh: () => query.refetch()
6963
+ };
6964
+ }
6965
+ var DEBOUNCE_MS = 300;
6966
+ var ONLINE_COLOR = "#3FA83F";
6967
+ var OFFLINE_COLOR = "#E54141";
6968
+ function PlayerSelect({
6969
+ value,
6970
+ onChange,
6971
+ includeOffline = false,
6972
+ limit = 50,
6973
+ searchable: searchableProp,
6974
+ placeholder,
6975
+ nothingFoundMessage: nothingFoundMessageProp,
6976
+ loadingLabel = "Loading\u2026",
6977
+ onlineLabel = "Online",
6978
+ offlineLabel = "Offline",
6979
+ refreshLabel = "Refresh player list",
6980
+ ...rest
6981
+ }) {
6982
+ const theme = core.useMantineTheme();
6983
+ const color = theme.colors[theme.primaryColor][5];
6984
+ const [searchInput, setSearchInput] = react.useState("");
6985
+ const [debouncedSearch, setDebouncedSearch] = react.useState("");
6986
+ const { players, isFetching, refresh } = usePlayers({
6987
+ includeOffline,
6988
+ search: includeOffline ? debouncedSearch : void 0,
6989
+ limit
6990
+ });
6991
+ const sortedPlayers = react.useMemo(
6992
+ () => [...players].sort((a, b) => {
6993
+ if (a.online !== b.online) return a.online ? -1 : 1;
6994
+ return a.charName.localeCompare(b.charName);
6995
+ }),
6996
+ [players]
6997
+ );
6998
+ const playerByCitizen = react.useMemo(() => {
6999
+ const m = /* @__PURE__ */ new Map();
7000
+ for (const p of sortedPlayers) m.set(p.citizenId, p);
7001
+ return m;
7002
+ }, [sortedPlayers]);
7003
+ const data = react.useMemo(() => {
7004
+ const items = sortedPlayers.map((p) => ({
7005
+ value: p.citizenId,
7006
+ label: formatLabel(p)
7007
+ }));
7008
+ if (value && !items.some((i) => i.value === value)) {
7009
+ items.unshift({ value, label: value });
7010
+ }
7011
+ return items;
7012
+ }, [sortedPlayers, value]);
7013
+ const selectedPlayer = value ? playerByCitizen.get(value) ?? null : null;
7014
+ const selectedLabel = selectedPlayer ? formatLabel(selectedPlayer) : null;
7015
+ react.useEffect(() => {
7016
+ if (!includeOffline) return;
7017
+ if (selectedLabel && searchInput === selectedLabel) return;
7018
+ const t3 = setTimeout(() => setDebouncedSearch(searchInput), DEBOUNCE_MS);
7019
+ return () => clearTimeout(t3);
7020
+ }, [searchInput, includeOffline, selectedLabel]);
7021
+ const renderOption = ({ option }) => {
7022
+ const p = playerByCitizen.get(option.value);
7023
+ if (!p) return option.label;
7024
+ return /* @__PURE__ */ jsxRuntime.jsxs(core.Group, { justify: "space-between", wrap: "nowrap", gap: "xs", style: { width: "100%" }, children: [
7025
+ /* @__PURE__ */ jsxRuntime.jsx(core.Text, { size: "xs", truncate: true, style: { flex: 1 }, children: formatLabel(p) }),
7026
+ /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: p.online, onlineLabel, offlineLabel })
7027
+ ] });
7028
+ };
7029
+ return /* @__PURE__ */ jsxRuntime.jsx(
7030
+ core.Select,
7031
+ {
7032
+ ...rest,
7033
+ data,
7034
+ value: value ?? null,
7035
+ onChange: (v) => {
7036
+ if (!v) return onChange(null);
7037
+ const player = playerByCitizen.get(v) ?? null;
7038
+ onChange(player);
7039
+ },
7040
+ searchable: searchableProp ?? true,
7041
+ searchValue: includeOffline ? searchInput : void 0,
7042
+ onSearchChange: includeOffline ? setSearchInput : void 0,
7043
+ placeholder,
7044
+ nothingFoundMessage: isFetching ? loadingLabel : nothingFoundMessageProp ?? "No players found",
7045
+ maxDropdownHeight: 300,
7046
+ renderOption,
7047
+ leftSection: selectedPlayer ? /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { online: selectedPlayer.online, onlineLabel, offlineLabel }) : void 0,
7048
+ rightSectionWidth: "3.5vh",
7049
+ rightSectionPointerEvents: "all",
7050
+ rightSection: /* @__PURE__ */ jsxRuntime.jsx(
7051
+ core.ActionIcon,
7052
+ {
7053
+ variant: "subtle",
7054
+ size: "sm",
7055
+ onClick: (e) => {
7056
+ e.stopPropagation();
7057
+ refresh();
7058
+ },
7059
+ "aria-label": refreshLabel,
7060
+ title: refreshLabel,
7061
+ style: { marginRight: "0.6vh" },
7062
+ children: isFetching ? /* @__PURE__ */ jsxRuntime.jsx(core.Loader, { size: "1.2vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: "1.4vh", color })
7063
+ }
7064
+ )
7065
+ }
7066
+ );
7067
+ }
7068
+ function StatusDot({ online, onlineLabel, offlineLabel }) {
7069
+ return /* @__PURE__ */ jsxRuntime.jsx(
7070
+ "span",
7071
+ {
7072
+ title: online ? onlineLabel : offlineLabel,
7073
+ style: {
7074
+ display: "inline-block",
7075
+ width: "0.9vh",
7076
+ height: "0.9vh",
7077
+ borderRadius: "50%",
7078
+ backgroundColor: online ? ONLINE_COLOR : OFFLINE_COLOR,
7079
+ boxShadow: `0 0 0.4vh ${online ? ONLINE_COLOR : OFFLINE_COLOR}`,
7080
+ flexShrink: 0
7081
+ }
7082
+ }
7083
+ );
7084
+ }
7085
+ function formatLabel(p) {
7086
+ const parts = [p.charName || p.citizenId];
7087
+ if (p.online) {
7088
+ if (p.name) parts.push(p.name);
7089
+ if (p.id != null) parts.push(`#${p.id}`);
7090
+ }
7091
+ return parts.join(" \xB7 ");
7092
+ }
7093
+ function usePickDoor() {
7094
+ const begin = useAdminToolStore((s) => s.begin);
7095
+ return async () => {
7096
+ const pending = begin({
7097
+ id: "pickDoor",
7098
+ title: locale("PickDoorTitle"),
7099
+ hint: locale("PickDoorHint"),
7100
+ keys: [
7101
+ { key: "LMB", action: locale("Toggle") },
7102
+ { key: "E", action: locale("Confirm") },
7103
+ { key: "BACKSPACE", action: locale("Cancel") }
7104
+ ]
7105
+ });
7106
+ fetchNui("ADMIN_TOOL_BEGIN", { id: "pickDoor" }).catch(() => {
7107
+ useAdminToolStore.getState().cancelActive();
7108
+ });
7109
+ return await pending;
7110
+ };
7111
+ }
7112
+ function DoorPickerButton({
7113
+ onPick,
7114
+ compact,
7115
+ label,
7116
+ tooltip
7117
+ }) {
7118
+ const theme = core.useMantineTheme();
7119
+ const color = theme.colors[theme.primaryColor][5];
7120
+ const pickDoor = usePickDoor();
7121
+ const onClick = async () => {
7122
+ const picked = await pickDoor();
7123
+ if (picked && picked.doors.length > 0) onPick(picked);
7124
+ };
7125
+ return /* @__PURE__ */ jsxRuntime.jsx(
7126
+ core.Tooltip,
7127
+ {
7128
+ label: tooltip ?? locale("PickDoorTooltip"),
7129
+ position: "top",
7130
+ withArrow: true,
7131
+ withinPortal: true,
7132
+ zIndex: 2e3,
7133
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7134
+ framerMotion.motion.button,
7135
+ {
7136
+ onClick,
7137
+ whileHover: { background: core.alpha(color, 0.18) },
7138
+ whileTap: { scale: 0.95 },
7139
+ style: {
7140
+ background: core.alpha(color, 0.1),
7141
+ border: `0.1vh solid ${core.alpha(color, 0.35)}`,
7142
+ borderRadius: theme.radius.xs,
7143
+ padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
7144
+ cursor: "pointer",
7145
+ display: "flex",
7146
+ alignItems: "center",
7147
+ gap: compact ? "0.3vh" : "0.4vh"
7148
+ },
7149
+ children: [
7150
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DoorOpen, { size: compact ? "1.1vh" : "1.3vh", color }),
7151
+ /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: label ?? locale("PickDoor") })
7152
+ ]
7153
+ }
7154
+ )
7155
+ }
7156
+ );
7157
+ }
7158
+ var MapImpl = react.memo(({
7159
+ children,
7160
+ initialZoom = 2,
7161
+ initialCenter = gameToMap(0, 0),
7162
+ mapStyle = "game"
7163
+ }) => {
7164
+ const mapRef = react.useRef(null);
7165
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7166
+ reactLeaflet.MapContainer,
7167
+ {
7168
+ maxBoundsViscosity: 1,
7169
+ preferCanvas: true,
7170
+ zoom: Math.round(initialZoom),
7171
+ zoomSnap: 1,
7172
+ zoomDelta: 1,
7173
+ zoomControl: false,
7174
+ crs: leaflet.CRS.Simple,
7175
+ style: {
7176
+ height: "100%",
7177
+ width: "100%",
7178
+ overflow: "hidden",
7179
+ outline: "none !important",
7180
+ border: "none !important",
7181
+ boxShadow: "none !important",
7182
+ backgroundColor: "#384950"
7183
+ },
7184
+ center: initialCenter,
7185
+ attributionControl: false,
7186
+ doubleClickZoom: false,
7187
+ inertia: false,
7188
+ zoomAnimation: false,
7189
+ ref: mapRef,
7190
+ maxBounds: [[-250, -250], [250, 250]],
7191
+ children: [
7192
+ /* @__PURE__ */ jsxRuntime.jsx(MapLayer, { mapLayer: mapStyle }),
7193
+ children
7194
+ ]
7195
+ }
7196
+ );
7197
+ });
7198
+ MapImpl.displayName = "DirkMap";
7199
+ var Map2 = MapImpl;
7200
+ var MapLayer = ({ mapLayer }) => {
7201
+ const map = reactLeaflet.useMap();
7202
+ const layerRef = react.useRef(null);
7203
+ react.useEffect(() => {
7204
+ if (layerRef.current) {
7205
+ map.removeLayer(layerRef.current);
7206
+ }
7207
+ const layer = leaflet.tileLayer(
7208
+ `https://s.rsg.sc/sc/images/games/GTAV/map/${mapLayer}/{z}/{x}/{y}.jpg`,
7209
+ {
7210
+ maxZoom: 6,
7211
+ minZoom: 4,
7212
+ bounds: leaflet.latLngBounds(leaflet.latLng(0, 128), leaflet.latLng(-192, 0)),
7213
+ tileSize: 256,
7214
+ updateWhenZooming: false,
7215
+ keepBuffer: 2,
7216
+ opacity: 0.75
7217
+ }
7218
+ );
7219
+ layer.addTo(map);
7220
+ layerRef.current = layer;
7221
+ return () => {
7222
+ if (layerRef.current) {
7223
+ map.removeLayer(layerRef.current);
7224
+ }
7225
+ };
7226
+ }, [mapLayer, map]);
7227
+ return null;
7228
+ };
7229
+ function ZoomControls() {
7230
+ const theme = core.useMantineTheme();
7231
+ const map = reactLeaflet.useMap();
7232
+ const buttons = [
7233
+ { Icon: lucideReact.Plus, fn: () => map.zoomIn() },
7234
+ { Icon: lucideReact.Minus, fn: () => map.zoomOut() }
7235
+ ];
7236
+ return /* @__PURE__ */ jsxRuntime.jsx(
7237
+ framerMotion.motion.div,
7238
+ {
7239
+ style: {
7240
+ position: "absolute",
7241
+ right: "2vh",
7242
+ top: "2vh",
7243
+ display: "flex",
7244
+ flexDirection: "column",
7245
+ zIndex: 999999,
7246
+ boxShadow: `0 0 1vh ${core.alpha(theme.colors.dark[9], 0.85)}`,
7247
+ background: core.alpha(theme.colors.dark[9], 0.85),
7248
+ borderRadius: theme.radius.xs
7249
+ },
7250
+ initial: { opacity: 0, y: -20 },
7251
+ animate: { opacity: 1, y: 0 },
7252
+ exit: { opacity: 0, y: -20 },
7253
+ children: buttons.map(({ Icon, fn }, i) => /* @__PURE__ */ jsxRuntime.jsx(
7254
+ framerMotion.motion.div,
7255
+ {
7256
+ whileHover: { scale: 1.1, filter: "brightness(1.5)" },
7257
+ onClick: fn,
7258
+ style: {
7259
+ padding: theme.spacing.xs,
7260
+ cursor: "pointer",
7261
+ display: "flex"
7262
+ },
7263
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 34, color: theme.colors.gray[5] })
7264
+ },
7265
+ i
7266
+ ))
7267
+ }
7268
+ );
7269
+ }
7270
+ var DEFAULT_SPRITE = 162;
7271
+ var DEFAULT_COLOR = 5;
7272
+ function BlipMarker({
7273
+ position,
7274
+ sprite,
7275
+ color,
7276
+ scale = 1,
7277
+ onClick,
7278
+ selected,
7279
+ disabled,
7280
+ fallbackSprite = DEFAULT_SPRITE,
7281
+ fallbackColor = DEFAULT_COLOR
7282
+ }) {
7283
+ const [hovered, setHovered] = react.useState(false);
7284
+ const mapCoords = react.useMemo(() => gameToMap(position.x, position.y), [position.x, position.y]);
7285
+ const effectiveSprite = sprite ?? fallbackSprite;
7286
+ const effectiveColor = color ?? fallbackColor;
7287
+ const url = blipUrlForSprite(effectiveSprite);
7288
+ const colorHex = getBlipColor(effectiveColor)?.hex ?? "#ffffff";
7289
+ const handleClick = (e) => {
7290
+ e.originalEvent?.stopPropagation?.();
7291
+ if (disabled) return;
7292
+ onClick?.();
7293
+ };
7294
+ const baseSize = 1.8 * scale;
7295
+ const size = `${baseSize}vh`;
7296
+ const ringSize = `${baseSize * 1.6}vh`;
7297
+ return /* @__PURE__ */ jsxRuntime.jsx(
7298
+ reactLeafletComponentMarker.Marker,
7299
+ {
7300
+ position: mapCoords,
7301
+ eventHandlers: onClick ? { click: handleClick } : void 0,
7302
+ icon: /* @__PURE__ */ jsxRuntime.jsxs(
7303
+ framerMotion.motion.div,
7304
+ {
7305
+ onHoverStart: () => setHovered(true),
7306
+ onHoverEnd: () => setHovered(false),
7307
+ style: {
7308
+ position: "relative",
7309
+ display: "flex",
7310
+ alignItems: "center",
7311
+ justifyContent: "center",
7312
+ cursor: disabled ? "not-allowed" : onClick ? "pointer" : "default",
7313
+ opacity: disabled ? 0.35 : 1,
7314
+ width: size,
7315
+ height: size
7316
+ },
7317
+ animate: { scale: hovered && !disabled ? 1.2 : selected ? 1.15 : 1 },
7318
+ transition: { duration: 0.15, ease: "easeOut" },
7319
+ children: [
7320
+ (selected || hovered) && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
7321
+ framerMotion.motion.div,
7322
+ {
7323
+ style: {
7324
+ position: "absolute",
7325
+ width: ringSize,
7326
+ height: ringSize,
7327
+ borderRadius: "50%",
7328
+ border: `0.18vh solid ${core.alpha(colorHex, 0.85)}`,
7329
+ boxShadow: `0 0 1vh ${core.alpha(colorHex, 0.55)}`
7330
+ },
7331
+ initial: { opacity: 0, scale: 0.8 },
7332
+ animate: { opacity: 1, scale: 1 }
7333
+ }
7334
+ ),
7335
+ url && /* @__PURE__ */ jsxRuntime.jsx(
7336
+ "div",
7337
+ {
7338
+ style: {
7339
+ width: size,
7340
+ height: size,
7341
+ backgroundColor: colorHex,
7342
+ WebkitMaskImage: `url(${url})`,
7343
+ maskImage: `url(${url})`,
7344
+ WebkitMaskRepeat: "no-repeat",
7345
+ maskRepeat: "no-repeat",
7346
+ WebkitMaskPosition: "center",
7347
+ maskPosition: "center",
7348
+ WebkitMaskSize: "contain",
7349
+ maskSize: "contain",
7350
+ filter: [
7351
+ "drop-shadow(0.12vh 0 0 #000)",
7352
+ "drop-shadow(-0.12vh 0 0 #000)",
7353
+ "drop-shadow(0 0.12vh 0 #000)",
7354
+ "drop-shadow(0 -0.12vh 0 #000)",
7355
+ `drop-shadow(0 0 0.4vh ${core.alpha("#000", 0.7)})`
7356
+ ].join(" "),
7357
+ pointerEvents: "none",
7358
+ userSelect: "none"
7359
+ }
7360
+ }
7361
+ )
7362
+ ]
7363
+ }
7364
+ )
7365
+ }
7366
+ );
7367
+ }
6542
7368
 
6543
7369
  exports.AccountSelect = AccountSelect;
6544
7370
  exports.AdminPageTitle = AdminPageTitle;
@@ -6547,6 +7373,7 @@ exports.AsyncSaveButton = AsyncSaveButton;
6547
7373
  exports.BlipColorSelect = BlipColorSelect;
6548
7374
  exports.BlipDisplaySelect = BlipDisplaySelect;
6549
7375
  exports.BlipIconSelect = BlipIconSelect;
7376
+ exports.BlipMarker = BlipMarker;
6550
7377
  exports.BorderedIcon = BorderedIcon;
6551
7378
  exports.ConfigPanel = ConfigPanel;
6552
7379
  exports.ConfirmModal = ConfirmModal;
@@ -6554,6 +7381,7 @@ exports.ControlMultiSelect = ControlMultiSelect;
6554
7381
  exports.ControlSelect = ControlSelect;
6555
7382
  exports.Counter = Counter;
6556
7383
  exports.DiscordRoleSelect = DiscordRoleSelect;
7384
+ exports.DoorPickerButton = DoorPickerButton;
6557
7385
  exports.FiveMKeyBindInput = FiveMKeyBindInput;
6558
7386
  exports.FloatingParticles = FloatingParticles;
6559
7387
  exports.GroupName = GroupName;
@@ -6561,8 +7389,11 @@ exports.GroupRank = GroupRank;
6561
7389
  exports.GroupSelect = GroupSelect;
6562
7390
  exports.InfoBox = InfoBox;
6563
7391
  exports.InputContainer = InputContainer;
7392
+ exports.InstructionPanel = InstructionPanel;
6564
7393
  exports.LevelBanner = LevelBanner;
6565
7394
  exports.LevelPanel = LevelPanel;
7395
+ exports.Map = Map2;
7396
+ exports.MapLayer = MapLayer;
6566
7397
  exports.MissingItemsBanner = MissingItemsBanner;
6567
7398
  exports.Modal = Modal;
6568
7399
  exports.ModalContext = ModalContext;
@@ -6574,6 +7405,7 @@ exports.MotionText = MotionText;
6574
7405
  exports.NavBar = NavBar;
6575
7406
  exports.NavigationContext = NavigationContext;
6576
7407
  exports.NavigationProvider = NavigationProvider;
7408
+ exports.PlayerSelect = PlayerSelect;
6577
7409
  exports.PositionPicker = PositionPicker;
6578
7410
  exports.PromptModal = PromptModal;
6579
7411
  exports.ScenarioSelect = ScenarioSelect;
@@ -6587,11 +7419,19 @@ exports.Title = Title;
6587
7419
  exports.Vector4DeleteButton = Vector4DeleteButton;
6588
7420
  exports.Vector4Display = Vector4Display;
6589
7421
  exports.WorldPositionGotoButton = WorldPositionGotoButton;
7422
+ exports.WorldPositionPicker = WorldPositionPicker;
6590
7423
  exports.WorldPositionSetButton = WorldPositionSetButton;
7424
+ exports.ZoomControls = ZoomControls;
7425
+ exports.blipUrl = blipUrl;
7426
+ exports.blipUrlForSprite = blipUrlForSprite;
7427
+ exports.getBlipColor = getBlipColor;
7428
+ exports.getBlipEntry = getBlipEntry;
7429
+ exports.useAdminToolStore = useAdminToolStore;
6591
7430
  exports.useMissingItemsAudit = useMissingItemsAudit;
6592
7431
  exports.useModal = useModal;
6593
7432
  exports.useModalActions = useModalActions;
6594
7433
  exports.useNavigation = useNavigation;
6595
7434
  exports.useNavigationStore = useNavigationStore;
7435
+ exports.usePickDoor = usePickDoor;
6596
7436
  //# sourceMappingURL=index.cjs.map
6597
7437
  //# sourceMappingURL=index.cjs.map