dirk-cfx-react 1.1.53 → 1.1.55

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.
@@ -1,12 +1,1062 @@
1
- import { createContext, useRef, useState, useEffect, useContext } from 'react';
2
- import { create, useStore } from 'zustand';
1
+ import { Flex, Text, Image, TextInput, Select, Box, useMantineTheme, alpha, Progress, RingProgress, Portal, Button, Loader, Group, JsonInput } from '@mantine/core';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { createContext, useContext, useRef, useState, useEffect, useMemo } from 'react';
4
+ import { create, useStore, createStore } from 'zustand';
3
5
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
- import { Flex, Text, Image, useMantineTheme, alpha, Progress, RingProgress, Button } from '@mantine/core';
5
- import { jsx, jsxs } from 'react/jsx-runtime';
6
6
  import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
7
7
  import clickSoundUrl from '../click_sound-PNCRRTM4.mp3';
8
8
  import hoverSoundUrl from '../hover_sound-NBUA222C.mp3';
9
- import { useClickOutside } from '@mantine/hooks';
9
+ import { X, AlertTriangle, Trash2, Check, Undo2, Redo2, Save, History, XCircle, Code2, RotateCcw, Search, Filter, User, ChevronDown } from 'lucide-react';
10
+ import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
11
+
12
+ // src/components/BlipSelect.tsx
13
+ var BLIP_ENTRIES = [
14
+ [0, "radar_higher", "gif"],
15
+ [1, "radar_level", "png"],
16
+ [2, "radar_lower", "gif"],
17
+ [3, "radar_police_ped", "gif"],
18
+ [4, "radar_wanted_radius", "png"],
19
+ [5, "radar_area_blip", "png"],
20
+ [6, "radar_centre", "png"],
21
+ [7, "radar_north", "png"],
22
+ [8, "radar_waypoint", "png"],
23
+ [9, "radar_radius_blip", "png"],
24
+ [10, "radar_radius_outline_blip", "png"],
25
+ [11, "radar_weapon_higher", "gif"],
26
+ [12, "radar_weapon_lower", "gif"],
27
+ [13, "radar_higher_ai", "gif"],
28
+ [14, "radar_lower_ai", "gif"],
29
+ [15, "radar_police_heli_spin", "gif"],
30
+ [16, "radar_police_plane_move", "png"],
31
+ [27, "radar_mp_crew", "png"],
32
+ [28, "radar_mp_friendlies", "png"],
33
+ [36, "radar_cable_car", "png"],
34
+ [37, "radar_activities", "png"],
35
+ [38, "radar_raceflag", "png"],
36
+ [40, "radar_safehouse", "png"],
37
+ [41, "radar_police", "gif"],
38
+ [42, "radar_police_chase", "gif"],
39
+ [43, "radar_police_heli", "png"],
40
+ [44, "radar_bomb_a", "png"],
41
+ [47, "radar_snitch", "png"],
42
+ [48, "radar_planning_locations", "png"],
43
+ [50, "radar_crim_carsteal", "png"],
44
+ [51, "radar_crim_drugs", "png"],
45
+ [52, "radar_crim_holdups", "png"],
46
+ [54, "radar_crim_player", "png"],
47
+ [56, "radar_cop_patrol", "png"],
48
+ [57, "radar_cop_player", "png"],
49
+ [58, "radar_crim_wanted", "png"],
50
+ [59, "radar_heist", "png"],
51
+ [60, "radar_police_station", "png"],
52
+ [61, "radar_hospital", "png"],
53
+ [62, "radar_assassins_mark", "png"],
54
+ [63, "radar_elevator", "png"],
55
+ [64, "radar_helicopter", "png"],
56
+ [66, "radar_random_character", "png"],
57
+ [67, "radar_security_van", "png"],
58
+ [68, "radar_tow_truck", "png"],
59
+ [70, "radar_illegal_parking", "png"],
60
+ [71, "radar_barber", "png"],
61
+ [72, "radar_car_mod_shop", "png"],
62
+ [73, "radar_clothes_store", "png"],
63
+ [75, "radar_tattoo", "png"],
64
+ [76, "radar_armenian_family", "png"],
65
+ [77, "radar_lester_family", "png"],
66
+ [78, "radar_michael_family", "png"],
67
+ [79, "radar_trevor_family", "png"],
68
+ [80, "radar_jewelry_heist", "png"],
69
+ [82, "radar_drag_race_finish", "png"],
70
+ [84, "radar_rampage", "png"],
71
+ [85, "radar_vinewood_tours", "png"],
72
+ [86, "radar_lamar_family", "png"],
73
+ [88, "radar_franklin_family", "png"],
74
+ [89, "radar_chinese_strand", "png"],
75
+ [90, "radar_flight_school", "png"],
76
+ [91, "radar_eye_sky", "png"],
77
+ [92, "radar_air_hockey", "png"],
78
+ [93, "radar_bar", "png"],
79
+ [94, "radar_base_jump", "png"],
80
+ [95, "radar_basketball", "png"],
81
+ [96, "radar_biolab_heist", "png"],
82
+ [99, "radar_cabaret_club", "png"],
83
+ [100, "radar_car_wash", "png"],
84
+ [102, "radar_comedy_club", "png"],
85
+ [103, "radar_darts", "png"],
86
+ [104, "radar_docks_heist", "png"],
87
+ [105, "radar_fbi_heist", "png"],
88
+ [106, "radar_fbi_officers_strand", "png"],
89
+ [107, "radar_finale_bank_heist", "png"],
90
+ [108, "radar_financier_strand", "png"],
91
+ [109, "radar_golf", "png"],
92
+ [110, "radar_gun_shop", "png"],
93
+ [111, "radar_internet_cafe", "png"],
94
+ [112, "radar_michael_family_exile", "png"],
95
+ [113, "radar_nice_house_heist", "png"],
96
+ [114, "radar_random_female", "png"],
97
+ [115, "radar_random_male", "png"],
98
+ [118, "radar_rural_bank_heist", "png"],
99
+ [119, "radar_shooting_range", "png"],
100
+ [120, "radar_solomon_strand", "png"],
101
+ [121, "radar_strip_club", "png"],
102
+ [122, "radar_tennis", "png"],
103
+ [123, "radar_trevor_family_exile", "png"],
104
+ [124, "radar_michael_trevor_family", "png"],
105
+ [126, "radar_triathlon", "png"],
106
+ [127, "radar_off_road_racing", "png"],
107
+ [128, "radar_gang_cops", "png"],
108
+ [129, "radar_gang_mexicans", "png"],
109
+ [130, "radar_gang_bikers", "png"],
110
+ [133, "radar_snitch_red", "png"],
111
+ [134, "radar_crim_cuff_keys", "png"],
112
+ [135, "radar_cinema", "png"],
113
+ [136, "radar_music_venue", "png"],
114
+ [137, "radar_police_station_blue", "png"],
115
+ [138, "radar_airport", "png"],
116
+ [139, "radar_crim_saved_vehicle", "png"],
117
+ [140, "radar_weed_stash", "png"],
118
+ [141, "radar_hunting", "png"],
119
+ [142, "radar_pool", "png"],
120
+ [143, "radar_objective_blue", "png"],
121
+ [144, "radar_objective_green", "png"],
122
+ [145, "radar_objective_red", "png"],
123
+ [146, "radar_objective_yellow", "png"],
124
+ [147, "radar_arms_dealing", "png"],
125
+ [148, "radar_mp_friend", "png"],
126
+ [149, "radar_celebrity_theft", "png"],
127
+ [150, "radar_weapon_assault_rifle", "png"],
128
+ [151, "radar_weapon_bat", "png"],
129
+ [152, "radar_weapon_grenade", "png"],
130
+ [153, "radar_weapon_health", "png"],
131
+ [154, "radar_weapon_knife", "png"],
132
+ [155, "radar_weapon_molotov", "png"],
133
+ [156, "radar_weapon_pistol", "png"],
134
+ [157, "radar_weapon_rocket", "png"],
135
+ [158, "radar_weapon_shotgun", "png"],
136
+ [159, "radar_weapon_smg", "png"],
137
+ [160, "radar_weapon_sniper", "png"],
138
+ [161, "radar_mp_noise", "gif"],
139
+ [162, "radar_poi", "png"],
140
+ [163, "radar_passive", "png"],
141
+ [164, "radar_usingmenu", "png"],
142
+ [171, "radar_gang_cops_partner", "png"],
143
+ [173, "radar_weapon_minigun", "png"],
144
+ [175, "radar_weapon_armour", "png"],
145
+ [176, "radar_property_takeover", "png"],
146
+ [177, "radar_gang_mexicans_highlight", "png"],
147
+ [178, "radar_gang_bikers_highlight", "png"],
148
+ [179, "radar_triathlon_cycling", "png"],
149
+ [180, "radar_triathlon_swimming", "png"],
150
+ [181, "radar_property_takeover_bikers", "png"],
151
+ [182, "radar_property_takeover_cops", "png"],
152
+ [183, "radar_property_takeover_vagos", "png"],
153
+ [184, "radar_camera", "png"],
154
+ [185, "radar_centre_red", "png"],
155
+ [186, "radar_handcuff_keys_bikers", "png"],
156
+ [187, "radar_handcuff_keys_vagos", "png"],
157
+ [188, "radar_handcuffs_closed_bikers", "png"],
158
+ [189, "radar_handcuffs_closed_vagos", "png"],
159
+ [192, "radar_camera_badger", "png"],
160
+ [193, "radar_camera_facade", "png"],
161
+ [194, "radar_camera_ifruit", "png"],
162
+ [197, "radar_yoga", "png"],
163
+ [198, "radar_taxi", "png"],
164
+ [205, "radar_shrink", "png"],
165
+ [206, "radar_epsilon", "png"],
166
+ [207, "radar_financier_strand_grey", "png"],
167
+ [208, "radar_trevor_family_grey", "png"],
168
+ [209, "radar_trevor_family_red", "png"],
169
+ [210, "radar_franklin_family_grey", "png"],
170
+ [211, "radar_franklin_family_blue", "png"],
171
+ [212, "radar_franklin_a", "png"],
172
+ [213, "radar_franklin_b", "png"],
173
+ [214, "radar_franklin_c", "png"],
174
+ [225, "radar_gang_vehicle", "png"],
175
+ [226, "radar_gang_vehicle_bikers", "png"],
176
+ [227, "radar_gang_vehicle_cops", "png"],
177
+ [228, "radar_gang_vehicle_vagos", "png"],
178
+ [229, "radar_guncar", "png"],
179
+ [230, "radar_driving_bikers", "png"],
180
+ [231, "radar_driving_cops", "png"],
181
+ [232, "radar_driving_vagos", "png"],
182
+ [233, "radar_gang_cops_highlight", "png"],
183
+ [234, "radar_shield_bikers", "png"],
184
+ [235, "radar_shield_cops", "png"],
185
+ [236, "radar_shield_vagos", "png"],
186
+ [237, "radar_custody_bikers", "png"],
187
+ [238, "radar_custody_vagos", "png"],
188
+ [251, "radar_arms_dealing_air", "png"],
189
+ [252, "radar_playerstate_arrested", "png"],
190
+ [253, "radar_playerstate_custody", "png"],
191
+ [254, "radar_playerstate_driving", "png"],
192
+ [255, "radar_playerstate_keyholder", "png"],
193
+ [256, "radar_playerstate_partner", "png"],
194
+ [262, "radar_ztype", "png"],
195
+ [263, "radar_stinger", "png"],
196
+ [264, "radar_packer", "png"],
197
+ [265, "radar_monroe", "png"],
198
+ [266, "radar_fairground", "png"],
199
+ [267, "radar_property", "png"],
200
+ [268, "radar_gang_highlight", "png"],
201
+ [269, "radar_altruist", "png"],
202
+ [270, "radar_ai", "png"],
203
+ [271, "radar_on_mission", "png"],
204
+ [272, "radar_cash_pickup", "png"],
205
+ [273, "radar_chop", "png"],
206
+ [274, "radar_dead", "png"],
207
+ [275, "radar_territory_locked", "png"],
208
+ [276, "radar_cash_lost", "png"],
209
+ [277, "radar_cash_vagos", "png"],
210
+ [278, "radar_cash_cops", "png"],
211
+ [279, "radar_hooker", "png"],
212
+ [280, "radar_friend", "png"],
213
+ [281, "radar_mission_2to4", "png"],
214
+ [282, "radar_mission_2to8", "png"],
215
+ [283, "radar_mission_2to12", "png"],
216
+ [284, "radar_mission_2to16", "png"],
217
+ [285, "radar_custody_dropoff", "png"],
218
+ [286, "radar_onmission_cops", "png"],
219
+ [287, "radar_onmission_lost", "png"],
220
+ [288, "radar_onmission_vagos", "png"],
221
+ [289, "radar_crim_carsteal_cops", "png"],
222
+ [290, "radar_crim_carsteal_bikers", "png"],
223
+ [291, "radar_crim_carsteal_vagos", "png"],
224
+ [292, "radar_band_strand", "png"],
225
+ [293, "radar_simeon_family", "png"],
226
+ [294, "radar_mission_1", "png"],
227
+ [295, "radar_mission_2", "png"],
228
+ [296, "radar_friend_darts", "png"],
229
+ [297, "radar_friend_comedyclub", "png"],
230
+ [298, "radar_friend_cinema", "png"],
231
+ [299, "radar_friend_tennis", "png"],
232
+ [300, "radar_friend_stripclub", "png"],
233
+ [301, "radar_friend_livemusic", "png"],
234
+ [302, "radar_friend_golf", "png"],
235
+ [303, "radar_bounty_hit", "png"],
236
+ [304, "radar_ugc_mission", "png"],
237
+ [305, "radar_horde", "png"],
238
+ [306, "radar_cratedrop", "png"],
239
+ [307, "radar_plane_drop", "png"],
240
+ [308, "radar_sub", "png"],
241
+ [309, "radar_race", "png"],
242
+ [310, "radar_deathmatch", "png"],
243
+ [311, "radar_arm_wrestling", "png"],
244
+ [312, "radar_mission_1to2", "png"],
245
+ [313, "radar_shootingrange_gunshop", "png"],
246
+ [314, "radar_race_air", "png"],
247
+ [315, "radar_race_land", "png"],
248
+ [316, "radar_race_sea", "png"],
249
+ [317, "radar_tow", "png"],
250
+ [318, "radar_garbage", "png"],
251
+ [319, "radar_drill", "png"],
252
+ [320, "radar_spikes", "png"],
253
+ [321, "radar_firetruck", "png"],
254
+ [322, "radar_minigun2", "png"],
255
+ [323, "radar_bugstar", "png"],
256
+ [324, "radar_submarine", "png"],
257
+ [325, "radar_chinook", "png"],
258
+ [326, "radar_getaway_car", "png"],
259
+ [327, "radar_mission_bikers_1", "png"],
260
+ [328, "radar_mission_bikers_1to2", "png"],
261
+ [329, "radar_mission_bikers_2", "png"],
262
+ [330, "radar_mission_bikers_2to4", "png"],
263
+ [331, "radar_mission_bikers_2to8", "png"],
264
+ [332, "radar_mission_bikers_2to12", "png"],
265
+ [333, "radar_mission_bikers_2to16", "png"],
266
+ [334, "radar_mission_cops_1", "png"],
267
+ [335, "radar_mission_cops_1to2", "png"],
268
+ [336, "radar_mission_cops_2", "png"],
269
+ [337, "radar_mission_cops_2to4", "png"],
270
+ [338, "radar_mission_cops_2to8", "png"],
271
+ [339, "radar_mission_cops_2to12", "png"],
272
+ [340, "radar_mission_cops_2to16", "png"],
273
+ [341, "radar_mission_vagos_1", "png"],
274
+ [342, "radar_mission_vagos_1to2", "png"],
275
+ [343, "radar_mission_vagos_2", "png"],
276
+ [344, "radar_mission_vagos_2to4", "png"],
277
+ [345, "radar_mission_vagos_2to8", "png"],
278
+ [346, "radar_mission_vagos_2to12", "png"],
279
+ [347, "radar_mission_vagos_2to16", "png"],
280
+ [348, "radar_gang_bike", "png"],
281
+ [349, "radar_gas_grenade", "png"],
282
+ [350, "radar_property_for_sale", "png"],
283
+ [351, "radar_gang_attack_package", "png"],
284
+ [352, "radar_martin_madrazzo", "png"],
285
+ [353, "radar_enemy_heli_spin", "gif"],
286
+ [354, "radar_boost", "png"],
287
+ [355, "radar_devin", "png"],
288
+ [356, "radar_dock", "png"],
289
+ [357, "radar_garage", "png"],
290
+ [358, "radar_golf_flag", "png"],
291
+ [359, "radar_hangar", "png"],
292
+ [360, "radar_helipad", "png"],
293
+ [361, "radar_jerry_can", "png"],
294
+ [362, "radar_mask", "png"],
295
+ [363, "radar_heist_prep", "png"],
296
+ [364, "radar_incapacitated", "png"],
297
+ [365, "radar_spawn_point_pickup", "png"],
298
+ [366, "radar_boilersuit", "png"],
299
+ [367, "radar_completed", "png"],
300
+ [368, "radar_rockets", "png"],
301
+ [369, "radar_garage_for_sale", "png"],
302
+ [370, "radar_helipad_for_sale", "png"],
303
+ [371, "radar_dock_for_sale", "png"],
304
+ [372, "radar_hangar_for_sale", "png"],
305
+ [373, "radar_placeholder_6", "png"],
306
+ [374, "radar_business", "png"],
307
+ [375, "radar_business_for_sale", "png"],
308
+ [376, "radar_race_bike", "png"],
309
+ [377, "radar_parachute", "png"],
310
+ [378, "radar_team_deathmatch", "png"],
311
+ [379, "radar_race_foot", "png"],
312
+ [380, "radar_vehicle_deathmatch", "png"],
313
+ [381, "radar_barry", "png"],
314
+ [382, "radar_dom", "png"],
315
+ [383, "radar_maryann", "png"],
316
+ [384, "radar_cletus", "png"],
317
+ [385, "radar_josh", "png"],
318
+ [386, "radar_minute", "png"],
319
+ [387, "radar_omega", "png"],
320
+ [388, "radar_tonya", "png"],
321
+ [389, "radar_paparazzo", "png"],
322
+ [390, "radar_aim", "png"],
323
+ [391, "radar_cratedrop_background", "png"],
324
+ [392, "radar_green_and_net_player1", "png"],
325
+ [393, "radar_green_and_net_player2", "png"],
326
+ [394, "radar_green_and_net_player3", "png"],
327
+ [395, "radar_green_and_friendly", "png"],
328
+ [396, "radar_net_player1_and_net_player2", "png"],
329
+ [397, "radar_net_player1_and_net_player3", "png"],
330
+ [398, "radar_creator", "png"],
331
+ [399, "radar_creator_direction", "png"],
332
+ [400, "radar_abigail", "png"],
333
+ [401, "radar_blimp", "png"],
334
+ [402, "radar_repair", "png"],
335
+ [403, "radar_testosterone", "png"],
336
+ [404, "radar_dinghy", "png"],
337
+ [405, "radar_fanatic", "png"],
338
+ [407, "radar_info_icon", "png"],
339
+ [408, "radar_capture_the_flag", "png"],
340
+ [409, "radar_last_team_standing", "png"],
341
+ [410, "radar_boat", "png"],
342
+ [411, "radar_capture_the_flag_base", "png"],
343
+ [412, "radar_mp_crew", "png"],
344
+ [413, "radar_capture_the_flag_outline", "png"],
345
+ [414, "radar_capture_the_flag_base_nobag", "png"],
346
+ [415, "radar_weapon_jerrycan", "png"],
347
+ [416, "radar_rp", "png"],
348
+ [417, "radar_level_inside", "png"],
349
+ [418, "radar_bounty_hit_inside", "png"],
350
+ [419, "radar_capture_the_usaflag", "png"],
351
+ [420, "radar_capture_the_usaflag_outline", "png"],
352
+ [421, "radar_tank", "png"],
353
+ [422, "radar_player_heli", "gif"],
354
+ [423, "radar_player_plane", "png"],
355
+ [424, "radar_player_jet", "png"],
356
+ [425, "radar_centre_stroke", "png"],
357
+ [426, "radar_player_guncar", "png"],
358
+ [427, "radar_player_boat", "png"],
359
+ [428, "radar_mp_heist", "png"],
360
+ [429, "radar_temp_1", "png"],
361
+ [430, "radar_temp_2", "png"],
362
+ [431, "radar_temp_3", "png"],
363
+ [432, "radar_temp_4", "png"],
364
+ [433, "radar_temp_5", "png"],
365
+ [434, "radar_temp_6", "png"],
366
+ [435, "radar_race_stunt", "png"],
367
+ [436, "radar_hot_property", "png"],
368
+ [437, "radar_urbanwarfare_versus", "png"],
369
+ [438, "radar_king_of_the_castle", "png"],
370
+ [439, "radar_player_king", "png"],
371
+ [440, "radar_dead_drop", "png"],
372
+ [441, "radar_penned_in", "png"],
373
+ [442, "radar_beast", "png"],
374
+ [443, "radar_edge_pointer", "png"],
375
+ [444, "radar_edge_crosstheline", "png"],
376
+ [445, "radar_mp_lamar", "png"],
377
+ [446, "radar_bennys", "png"],
378
+ [447, "radar_corner_number_1", "png"],
379
+ [448, "radar_corner_number_2", "png"],
380
+ [449, "radar_corner_number_3", "png"],
381
+ [450, "radar_corner_number_4", "png"],
382
+ [451, "radar_corner_number_5", "png"],
383
+ [452, "radar_corner_number_6", "png"],
384
+ [453, "radar_corner_number_7", "png"],
385
+ [454, "radar_corner_number_8", "png"],
386
+ [455, "radar_yacht", "png"],
387
+ [456, "radar_finders_keepers", "png"],
388
+ [457, "radar_assault_package", "png"],
389
+ [458, "radar_hunt_the_boss", "png"],
390
+ [459, "radar_sightseer", "png"],
391
+ [460, "radar_turreted_limo", "png"],
392
+ [461, "radar_belly_of_the_beast", "png"],
393
+ [462, "radar_yacht_location", "png"],
394
+ [463, "radar_pickup_beast", "png"],
395
+ [464, "radar_pickup_zoned", "png"],
396
+ [465, "radar_pickup_random", "png"],
397
+ [466, "radar_pickup_slow_time", "png"],
398
+ [467, "radar_pickup_swap", "png"],
399
+ [468, "radar_pickup_thermal", "png"],
400
+ [469, "radar_pickup_weed", "png"],
401
+ [470, "radar_weapon_railgun", "png"],
402
+ [471, "radar_seashark", "png"],
403
+ [472, "radar_pickup_hidden", "png"],
404
+ [473, "radar_warehouse", "png"],
405
+ [474, "radar_warehouse_for_sale", "png"],
406
+ [475, "radar_office", "png"],
407
+ [476, "radar_office_for_sale", "png"],
408
+ [477, "radar_truck", "png"],
409
+ [478, "radar_contraband", "png"],
410
+ [479, "radar_trailer", "png"],
411
+ [480, "radar_vip", "png"],
412
+ [481, "radar_cargobob", "png"],
413
+ [482, "radar_area_outline_blip", "png"],
414
+ [483, "radar_pickup_accelerator", "png"],
415
+ [484, "radar_pickup_ghost", "png"],
416
+ [485, "radar_pickup_detonator", "png"],
417
+ [486, "radar_pickup_bomb", "png"],
418
+ [487, "radar_pickup_armoured", "png"],
419
+ [488, "radar_stunt", "png"],
420
+ [489, "radar_weapon_lives", "png"],
421
+ [490, "radar_stunt_premium", "png"],
422
+ [491, "radar_adversary", "png"],
423
+ [492, "radar_biker_clubhouse", "png"],
424
+ [493, "radar_biker_caged_in", "png"],
425
+ [494, "radar_biker_turf_war", "png"],
426
+ [495, "radar_biker_joust", "png"],
427
+ [496, "radar_production_weed", "png"],
428
+ [497, "radar_production_crack", "png"],
429
+ [498, "radar_production_fake_id", "png"],
430
+ [499, "radar_production_meth", "png"],
431
+ [500, "radar_production_money", "png"],
432
+ [501, "radar_package", "png"],
433
+ [502, "radar_capture_1", "png"],
434
+ [503, "radar_capture_2", "png"],
435
+ [504, "radar_capture_3", "png"],
436
+ [505, "radar_capture_4", "png"],
437
+ [506, "radar_capture_5", "png"],
438
+ [507, "radar_capture_6", "png"],
439
+ [508, "radar_capture_7", "png"],
440
+ [509, "radar_capture_8", "png"],
441
+ [510, "radar_capture_9", "png"],
442
+ [511, "radar_capture_10", "png"],
443
+ [512, "radar_quad", "png"],
444
+ [513, "radar_bus", "png"],
445
+ [514, "radar_drugs_package", "png"],
446
+ [515, "radar_pickup_jump", "png"],
447
+ [516, "radar_adversary_4", "png"],
448
+ [517, "radar_adversary_8", "png"],
449
+ [518, "radar_adversary_10", "png"],
450
+ [519, "radar_adversary_12", "png"],
451
+ [520, "radar_adversary_16", "png"],
452
+ [521, "radar_laptop", "png"],
453
+ [522, "radar_pickup_deadline", "png"],
454
+ [523, "radar_sports_car", "png"],
455
+ [524, "radar_warehouse_vehicle", "png"],
456
+ [525, "radar_reg_papers", "png"],
457
+ [526, "radar_police_station_dropoff", "png"],
458
+ [527, "radar_junkyard", "png"],
459
+ [528, "radar_ex_vech_1", "png"],
460
+ [529, "radar_ex_vech_2", "png"],
461
+ [530, "radar_ex_vech_3", "png"],
462
+ [531, "radar_ex_vech_4", "png"],
463
+ [532, "radar_ex_vech_5", "png"],
464
+ [533, "radar_ex_vech_6", "png"],
465
+ [534, "radar_ex_vech_7", "png"],
466
+ [535, "radar_target_a", "png"],
467
+ [536, "radar_target_b", "png"],
468
+ [537, "radar_target_c", "png"],
469
+ [538, "radar_target_d", "png"],
470
+ [539, "radar_target_e", "png"],
471
+ [540, "radar_target_f", "png"],
472
+ [541, "radar_target_g", "png"],
473
+ [542, "radar_target_h", "png"],
474
+ [543, "radar_jugg", "png"],
475
+ [544, "radar_pickup_repair", "png"],
476
+ [545, "radar_steeringwheel", "png"],
477
+ [546, "radar_trophy", "png"],
478
+ [547, "radar_pickup_rocket_boost", "png"],
479
+ [548, "radar_pickup_homing_rocket", "png"],
480
+ [549, "radar_pickup_machinegun", "png"],
481
+ [550, "radar_pickup_parachute", "png"],
482
+ [551, "radar_pickup_time_5", "png"],
483
+ [552, "radar_pickup_time_10", "png"],
484
+ [553, "radar_pickup_time_15", "png"],
485
+ [554, "radar_pickup_time_20", "png"],
486
+ [555, "radar_pickup_time_30", "png"],
487
+ [556, "radar_supplies", "png"],
488
+ [557, "radar_property_bunker", "png"],
489
+ [558, "radar_gr_wvm_1", "png"],
490
+ [559, "radar_gr_wvm_2", "png"],
491
+ [560, "radar_gr_wvm_3", "png"],
492
+ [561, "radar_gr_wvm_4", "png"],
493
+ [562, "radar_gr_wvm_5", "png"],
494
+ [563, "radar_gr_wvm_6", "png"],
495
+ [564, "radar_gr_covert_ops", "png"],
496
+ [565, "radar_adversary_bunker", "png"],
497
+ [566, "radar_gr_moc_upgrade", "png"],
498
+ [567, "radar_gr_w_upgrade", "png"],
499
+ [568, "radar_sm_cargo", "png"],
500
+ [569, "radar_sm_hangar", "png"],
501
+ [570, "radar_tf_checkpoint", "png"],
502
+ [571, "radar_race_tf", "png"],
503
+ [572, "radar_sm_wp1", "png"],
504
+ [573, "radar_sm_wp2", "png"],
505
+ [574, "radar_sm_wp3", "png"],
506
+ [575, "radar_sm_wp4", "png"],
507
+ [576, "radar_sm_wp5", "png"],
508
+ [577, "radar_sm_wp6", "png"],
509
+ [578, "radar_sm_wp7", "png"],
510
+ [579, "radar_sm_wp8", "png"],
511
+ [580, "radar_sm_wp9", "png"],
512
+ [581, "radar_sm_wp10", "png"],
513
+ [582, "radar_sm_wp11", "png"],
514
+ [583, "radar_sm_wp12", "png"],
515
+ [584, "radar_sm_wp13", "png"],
516
+ [585, "radar_sm_wp14", "png"],
517
+ [586, "radar_nhp_bag", "png"],
518
+ [587, "radar_nhp_chest", "png"],
519
+ [588, "radar_nhp_orbit", "png"],
520
+ [589, "radar_nhp_veh1", "png"],
521
+ [590, "radar_nhp_base", "png"],
522
+ [591, "radar_nhp_overlay", "png"],
523
+ [592, "radar_nhp_turret", "png"],
524
+ [593, "radar_nhp_mg_firewall", "png"],
525
+ [594, "radar_nhp_mg_node", "png"],
526
+ [595, "radar_nhp_wp1", "png"],
527
+ [596, "radar_nhp_wp2", "png"],
528
+ [597, "radar_nhp_wp3", "png"],
529
+ [598, "radar_nhp_wp4", "png"],
530
+ [599, "radar_nhp_wp5", "png"],
531
+ [600, "radar_nhp_wp6", "png"],
532
+ [601, "radar_nhp_wp7", "png"],
533
+ [602, "radar_nhp_wp8", "png"],
534
+ [603, "radar_nhp_wp9", "png"],
535
+ [604, "radar_nhp_cctv", "png"],
536
+ [605, "radar_nhp_starterpack", "png"],
537
+ [606, "radar_nhp_turret_console", "png"],
538
+ [607, "radar_nhp_mg_mir_rotate", "png"],
539
+ [608, "radar_nhp_mg_mir_static", "png"],
540
+ [609, "radar_nhp_mg_proxy", "png"],
541
+ [610, "radar_acsr_race_target", "png"],
542
+ [611, "radar_acsr_race_hotring", "png"],
543
+ [612, "radar_acsr_wp1", "png"],
544
+ [613, "radar_acsr_wp2", "png"],
545
+ [614, "radar_bat_club_property", "png"],
546
+ [615, "radar_bat_cargo", "png"],
547
+ [616, "radar_bat_truck", "png"],
548
+ [617, "radar_bat_hack_jewel", "png"],
549
+ [618, "radar_bat_hack_gold", "png"],
550
+ [619, "radar_bat_keypad", "png"],
551
+ [620, "radar_bat_hack_target", "png"],
552
+ [621, "radar_pickup_dtb_health", "png"],
553
+ [622, "radar_pickup_dtb_blast_increase", "png"],
554
+ [623, "radar_pickup_dtb_blast_decrease", "png"],
555
+ [624, "radar_pickup_dtb_bomb_increase", "png"],
556
+ [625, "radar_pickup_dtb_bomb_decrease", "png"],
557
+ [626, "radar_bat_rival_club", "png"],
558
+ [627, "radar_bat_drone", "png"],
559
+ [628, "radar_bat_cash_reg", "png"],
560
+ [629, "radar_cctv", "png"],
561
+ [630, "radar_bat_assassinate", "png"],
562
+ [631, "radar_bat_pbus", "png"],
563
+ [632, "radar_bat_wp1", "png"],
564
+ [633, "radar_bat_wp2", "png"],
565
+ [634, "radar_bat_wp3", "png"],
566
+ [635, "radar_bat_wp4", "png"],
567
+ [636, "radar_bat_wp5", "png"],
568
+ [637, "radar_bat_wp6", "png"],
569
+ [638, "radar_blimp_2", "png"],
570
+ [639, "radar_oppressor_2", "png"],
571
+ [640, "radar_bat_wp7", "png"],
572
+ [641, "radar_arena_series", "png"],
573
+ [642, "radar_arena_premium", "png"],
574
+ [643, "radar_arena_workshop", "png"],
575
+ [644, "radar_race_wars", "png"],
576
+ [645, "radar_arena_turret", "png"],
577
+ [646, "radar_arena_rc_car", "png"],
578
+ [647, "radar_arena_rc_workshop", "png"],
579
+ [648, "radar_arena_trap_fire", "png"],
580
+ [649, "radar_arena_trap_flip", "png"],
581
+ [650, "radar_arena_trap_sea", "png"],
582
+ [651, "radar_arena_trap_turn", "png"],
583
+ [652, "radar_arena_trap_pit", "png"],
584
+ [653, "radar_arena_trap_mine", "png"],
585
+ [654, "radar_arena_trap_bomb", "png"],
586
+ [655, "radar_arena_trap_wall", "png"],
587
+ [656, "radar_arena_trap_brd", "png"],
588
+ [657, "radar_arena_trap_sbrd", "png"],
589
+ [658, "radar_arena_bruiser", "png"],
590
+ [659, "radar_arena_brutus", "png"],
591
+ [660, "radar_arena_cerberus", "png"],
592
+ [661, "radar_arena_deathbike", "png"],
593
+ [662, "radar_arena_dominator", "png"],
594
+ [663, "radar_arena_impaler", "png"],
595
+ [664, "radar_arena_imperator", "png"],
596
+ [665, "radar_arena_issi", "png"],
597
+ [666, "radar_arena_sasquatch", "png"],
598
+ [667, "radar_arena_scarab", "png"],
599
+ [668, "radar_arena_slamvan", "png"],
600
+ [669, "radar_arena_zr380", "png"],
601
+ [670, "radar_ap", "png"],
602
+ [671, "radar_comic_store", "png"],
603
+ [672, "radar_cop_car", "png"],
604
+ [673, "radar_rc_time_trials", "png"],
605
+ [674, "radar_king_of_the_hill", "png"],
606
+ [675, "radar_king_of_the_hill_teams", "png"],
607
+ [676, "radar_rucksack", "png"],
608
+ [677, "radar_shipping_container", "png"],
609
+ [678, "radar_agatha", "png"],
610
+ [679, "radar_casino", "png"],
611
+ [680, "radar_casino_table_games", "png"],
612
+ [681, "radar_casino_wheel", "png"],
613
+ [682, "radar_casino_concierge", "png"],
614
+ [683, "radar_casino_chips", "png"],
615
+ [684, "radar_casino_horse_racing", "png"],
616
+ [685, "radar_adversary_featured", "png"],
617
+ [686, "radar_roulette_1", "png"],
618
+ [687, "radar_roulette_2", "png"],
619
+ [688, "radar_roulette_3", "png"],
620
+ [689, "radar_roulette_4", "png"],
621
+ [690, "radar_roulette_5", "png"],
622
+ [691, "radar_roulette_6", "png"],
623
+ [692, "radar_roulette_7", "png"],
624
+ [693, "radar_roulette_8", "png"],
625
+ [694, "radar_roulette_9", "png"],
626
+ [695, "radar_roulette_10", "png"],
627
+ [696, "radar_roulette_11", "png"],
628
+ [697, "radar_roulette_12", "png"],
629
+ [698, "radar_roulette_13", "png"],
630
+ [699, "radar_roulette_14", "png"],
631
+ [700, "radar_roulette_15", "png"],
632
+ [701, "radar_roulette_16", "png"],
633
+ [702, "radar_roulette_17", "png"],
634
+ [703, "radar_roulette_18", "png"],
635
+ [704, "radar_roulette_19", "png"],
636
+ [705, "radar_roulette_20", "png"],
637
+ [706, "radar_roulette_21", "png"],
638
+ [707, "radar_roulette_22", "png"],
639
+ [708, "radar_roulette_23", "png"],
640
+ [709, "radar_roulette_24", "png"],
641
+ [710, "radar_roulette_25", "png"],
642
+ [711, "radar_roulette_26", "png"],
643
+ [712, "radar_roulette_27", "png"],
644
+ [713, "radar_roulette_28", "png"],
645
+ [714, "radar_roulette_29", "png"],
646
+ [715, "radar_roulette_30", "png"],
647
+ [716, "radar_roulette_31", "png"],
648
+ [717, "radar_roulette_32", "png"],
649
+ [718, "radar_roulette_33", "png"],
650
+ [719, "radar_roulette_34", "png"],
651
+ [720, "radar_roulette_35", "png"],
652
+ [721, "radar_roulette_36", "png"],
653
+ [722, "radar_roulette_0", "png"],
654
+ [723, "radar_roulette_00", "png"],
655
+ [724, "radar_limo", "png"],
656
+ [725, "radar_weapon_alien", "png"],
657
+ [726, "radar_race_open_wheel", "png"],
658
+ [727, "radar_rappel", "png"],
659
+ [728, "radar_swap_car", "png"],
660
+ [729, "radar_scuba_gear", "png"],
661
+ [730, "radar_cpanel_1", "png"],
662
+ [731, "radar_cpanel_2", "png"],
663
+ [732, "radar_cpanel_3", "png"],
664
+ [733, "radar_cpanel_4", "png"],
665
+ [734, "radar_snow_truck", "png"],
666
+ [735, "radar_buggy_1", "png"],
667
+ [736, "radar_buggy_2", "png"],
668
+ [737, "radar_zhaba", "png"],
669
+ [738, "radar_gerald", "png"],
670
+ [739, "radar_ron", "png"],
671
+ [740, "radar_arcade", "png"],
672
+ [741, "radar_drone_controls", "png"],
673
+ [742, "radar_rc_tank", "png"],
674
+ [743, "radar_stairs", "png"],
675
+ [744, "radar_camera_2", "png"],
676
+ [745, "radar_winky", "png"],
677
+ [746, "radar_mini_sub", "png"],
678
+ [747, "radar_kart_retro", "png"],
679
+ [748, "radar_kart_modern", "png"],
680
+ [749, "radar_military_quad", "png"],
681
+ [750, "radar_military_truck", "png"],
682
+ [751, "radar_ship_wheel", "png"],
683
+ [752, "radar_ufo", "png"],
684
+ [753, "radar_seasparrow2", "png"],
685
+ [754, "radar_dinghy2", "png"],
686
+ [755, "radar_patrol_boat", "png"],
687
+ [756, "radar_retro_sports_car", "png"],
688
+ [757, "radar_squadee", "png"],
689
+ [758, "radar_folding_wing_jet", "png"],
690
+ [759, "radar_valkyrie2", "png"],
691
+ [760, "radar_sub2", "png"],
692
+ [761, "radar_bolt_cutters", "png"],
693
+ [762, "radar_rappel_gear", "png"],
694
+ [763, "radar_keycard", "png"],
695
+ [764, "radar_password", "png"],
696
+ [765, "radar_island_heist_prep", "png"],
697
+ [766, "radar_island_party", "png"],
698
+ [767, "radar_control_tower", "png"],
699
+ [768, "radar_underwater_gate", "png"],
700
+ [769, "radar_power_switch", "png"],
701
+ [770, "radar_compound_gate", "png"],
702
+ [771, "radar_rappel_point", "png"],
703
+ [772, "radar_keypad", "png"],
704
+ [773, "radar_sub_controls", "png"],
705
+ [774, "radar_sub_periscope", "png"],
706
+ [775, "radar_sub_missile", "png"],
707
+ [776, "radar_painting", "png"],
708
+ [777, "radar_car_meet", "png"],
709
+ [778, "radar_car_test_area", "png"],
710
+ [779, "radar_auto_shop_property", "png"],
711
+ [780, "radar_docks_export", "png"],
712
+ [781, "radar_prize_car", "png"],
713
+ [782, "radar_test_car", "png"],
714
+ [783, "radar_car_robbery_board", "png"],
715
+ [784, "radar_car_robbery_prep", "png"],
716
+ [785, "radar_street_race_series", "png"],
717
+ [786, "radar_pursuit_series", "png"],
718
+ [787, "radar_car_meet_organiser", "png"],
719
+ [788, "radar_securoserv", "png"],
720
+ [789, "radar_bounty_collectibles", "png"],
721
+ [790, "radar_movie_collectibles", "png"],
722
+ [791, "radar_trailer_ramp", "png"],
723
+ [792, "radar_race_organiser", "png"],
724
+ [793, "radar_chalkboard_list", "png"],
725
+ [794, "radar_export_vehicle", "png"],
726
+ [795, "radar_train", "png"],
727
+ [796, "radar_heist_diamond", "png"],
728
+ [797, "radar_heist_doomsday", "png"],
729
+ [798, "radar_heist_island", "png"],
730
+ [799, "radar_slamvan2", "png"],
731
+ [800, "radar_crusader", "png"],
732
+ [801, "radar_construction_outfit", "png"],
733
+ [802, "radar_overlay_jammed", "png"],
734
+ [803, "radar_heist_island_unavailable", "png"],
735
+ [804, "radar_heist_diamond_unavailable", "png"],
736
+ [805, "radar_heist_doomsday_unavailable", "png"],
737
+ [806, "radar_placeholder_7", "png"],
738
+ [807, "radar_placeholder_8", "png"],
739
+ [808, "radar_placeholder_9", "png"],
740
+ [809, "radar_featured_series", "png"],
741
+ [810, "radar_vehicle_for_sale", "png"],
742
+ [811, "radar_van_keys", "png"],
743
+ [812, "radar_suv_service", "png"],
744
+ [813, "radar_security_contract", "png"],
745
+ [814, "radar_safe", "png"],
746
+ [815, "radar_ped_r", "png"],
747
+ [816, "radar_ped_e", "png"],
748
+ [817, "radar_payphone", "png"],
749
+ [818, "radar_patriot3", "png"],
750
+ [819, "radar_music_studio", "png"],
751
+ [820, "radar_jubilee", "png"],
752
+ [821, "radar_granger2", "png"],
753
+ [822, "radar_explosive_charge", "png"],
754
+ [823, "radar_deity", "png"],
755
+ [824, "radar_d_champion", "png"],
756
+ [825, "radar_buffalo4", "png"],
757
+ [826, "radar_agency", "png"],
758
+ [827, "radar_biker_bar", "png"],
759
+ [828, "radar_simeon_overlay", "png"],
760
+ [829, "radar_junk_skydive", "png"],
761
+ [830, "radar_luxury_car_showroom", "png"],
762
+ [831, "radar_car_showroom", "png"],
763
+ [832, "radar_car_showroom_simeon", "png"],
764
+ [833, "radar_flaming_skull", "png"],
765
+ [834, "radar_weapon_ammo", "png"],
766
+ [835, "radar_community_series", "png"],
767
+ [836, "radar_cayo_series", "png"],
768
+ [837, "radar_clubhouse_contract", "png"],
769
+ [838, "radar_agent_ulp", "png"],
770
+ [839, "radar_acid", "png"],
771
+ [840, "radar_acid_lab", "png"],
772
+ [841, "radar_dax_overlay", "png"],
773
+ [842, "radar_dead_drop_package", "png"],
774
+ [843, "radar_downtown_cab", "png"],
775
+ [844, "radar_gun_van", "png"],
776
+ [845, "radar_stash_house", "png"],
777
+ [846, "radar_tractor", "png"],
778
+ [847, "radar_warehouse_juggalo", "png"],
779
+ [848, "radar_warehouse_juggalo_dax", "png"],
780
+ [849, "radar_weapon_crowbar", "png"],
781
+ [850, "radar_duffel_bag", "png"],
782
+ [851, "radar_oil_tanker", "png"],
783
+ [852, "radar_acid_lab_tent", "png"],
784
+ [853, "radar_van_burrito", "png"],
785
+ [854, "radar_acid_boost", "png"],
786
+ [855, "radar_ped_gang_leader", "png"],
787
+ [856, "radar_multistorey_garage", "png"],
788
+ [857, "radar_seized_asset_sales", "png"],
789
+ [858, "radar_cayo_attrition", "png"],
790
+ [859, "radar_bicycle", "png"],
791
+ [860, "radar_bicycle_trial", "png"],
792
+ [861, "radar_raiju", "png"],
793
+ [862, "radar_conada2", "png"],
794
+ [863, "radar_overlay_ready_for_sell", "png"],
795
+ [864, "radar_overlay_missing_supplies", "png"],
796
+ [865, "radar_streamer216", "png"],
797
+ [866, "radar_signal_jammer", "png"],
798
+ [867, "radar_salvage_yard", "png"],
799
+ [868, "radar_robbery_prep_equipment", "png"],
800
+ [869, "radar_robbery_prep_overlay", "png"],
801
+ [870, "radar_yusuf", "png"],
802
+ [871, "radar_vincent", "png"],
803
+ [872, "radar_vinewood_garage", "png"],
804
+ [873, "radar_lstb", "png"],
805
+ [874, "radar_cctv_workstation", "png"],
806
+ [875, "radar_hacking_device", "png"],
807
+ [876, "radar_race_drag", "png"],
808
+ [877, "radar_race_drift", "png"],
809
+ [878, "radar_casino_prep", "png"],
810
+ [879, "radar_planning_wall", "png"],
811
+ [880, "radar_weapon_crate", "png"],
812
+ [881, "radar_weapon_snowball", "png"],
813
+ [882, "radar_train_signals_green", "png"],
814
+ [883, "radar_train_signals_red", "png"],
815
+ [884, "radar_office_transporter", "png"],
816
+ [885, "radar_yankton_survival", "png"],
817
+ [886, "radar_daily_bounty", "png"],
818
+ [887, "radar_bounty_target", "png"],
819
+ [888, "radar_filming_schedule", "png"],
820
+ [889, "radar_pizza_this", "png"],
821
+ [890, "radar_aircraft_carrier", "png"],
822
+ [891, "radar_weapon_emp", "png"],
823
+ [892, "radar_maude_eccles", "png"],
824
+ [893, "radar_bail_bonds_office", "png"],
825
+ [894, "radar_weapon_emp_mine", "png"],
826
+ [895, "radar_zombie_disease", "png"],
827
+ [896, "radar_zombie_proximity", "png"],
828
+ [897, "radar_zombie_fire", "png"],
829
+ [898, "radar_animal_possessed", "png"],
830
+ [899, "radar_mobile_phone", "png"],
831
+ [900, "radar_garment_factory", "png"],
832
+ [901, "radar_garment_factory_for_sale", "png"],
833
+ [902, "radar_garment_factory_equipment", "png"],
834
+ [903, "radar_field_hangar", "png"],
835
+ [904, "radar_field_hangar_for_sale", "png"],
836
+ [905, "radar_cargobob_ch53", "png"],
837
+ [906, "radar_chopper_lift_ammo", "png"],
838
+ [907, "radar_chopper_lift_armor", "png"],
839
+ [908, "radar_chopper_lift_explosives", "png"],
840
+ [909, "radar_chopper_lift_upgrade", "png"],
841
+ [910, "radar_chopper_lift_weapon", "png"],
842
+ [911, "radar_cargo_ship", "png"],
843
+ [912, "radar_submarine_missile", "png"],
844
+ [913, "radar_propeller_engine", "png"],
845
+ [914, "radar_shark", "png"],
846
+ [915, "radar_fast_travel", "png"],
847
+ [916, "radar_plane_duster2", "png"],
848
+ [917, "radar_plane_titan2", "png"],
849
+ [918, "radar_collectible", "png"],
850
+ [919, "radar_field_hangar_discount", "png"],
851
+ [920, "radar_garment_factory_discount", "png"],
852
+ [921, "radar_weapon_gusenberg_sweeper", "png"],
853
+ [922, "radar_weapon_tear_gas", "png"],
854
+ [923, "radar_dog", "png"],
855
+ [924, "radar_bobcat_security", "png"],
856
+ [925, "radar_smoke_shop", "png"],
857
+ [926, "radar_smoke_shop_for_sale", "png"],
858
+ [927, "radar_smoke_shop_attention", "png"],
859
+ [928, "radar_helitours", "png"],
860
+ [929, "radar_helitours_for_sale", "png"],
861
+ [930, "radar_helitours_attention", "png"],
862
+ [931, "radar_car_wash_business", "png"],
863
+ [932, "radar_car_wash_business_for_sale", "png"],
864
+ [933, "radar_car_wash_business_attention", "png"],
865
+ [934, "radar_attention", "png"],
866
+ [935, "radar_alarm", "png"],
867
+ [936, "radar_helitours_discount", "png"],
868
+ [937, "radar_smoke_shop_discount", "png"],
869
+ [938, "radar_car_wash_business_discount", "png"],
870
+ [939, "radar_real_estate", "png"],
871
+ [940, "radar_medical_courier", "png"],
872
+ [941, "radar_gruppe_sechs", "png"],
873
+ [942, "radar_fire_station", "png"],
874
+ [943, "radar_fire_truck", "png"],
875
+ [944, "radar_alpha_mail", "png"],
876
+ [945, "radar_ls_meteor", "png"],
877
+ [946, "radar_four20_survival", "png"],
878
+ [947, "radar_community_mission_series", "png"],
879
+ [948, "radar_property_mansion", "png"],
880
+ [949, "radar_ai_keypad", "png"],
881
+ [950, "radar_taxi_self_drive", "png"],
882
+ [951, "radar_train_subway", "png"],
883
+ [952, "radar_trashbag", "png"],
884
+ [953, "radar_mission_creator", "png"],
885
+ [954, "radar_cat", "png"],
886
+ [955, "radar_mansion_ai_m", "png"],
887
+ [956, "radar_mansion_ai_f", "png"],
888
+ [957, "radar_mansion_ai_gang", "png"]
889
+ ];
890
+ var BLIP_BASE = "https://docs.fivem.net/blips/";
891
+ function blipUrl(name, ext) {
892
+ return `${BLIP_BASE}${name}.${ext}`;
893
+ }
894
+ var BLIP_COLORS = [
895
+ [0, "White", "#FFFFFF"],
896
+ [1, "Red", "#E54141"],
897
+ [2, "Green", "#3FA83F"],
898
+ [3, "Blue", "#5B8CCF"],
899
+ [4, "White", "#FFFFFF"],
900
+ [5, "Yellow", "#F0D453"],
901
+ [6, "Light Red", "#E88888"],
902
+ [7, "Violet", "#8C5FA8"],
903
+ [8, "Pink", "#E878C8"],
904
+ [9, "Light Orange", "#F0A861"],
905
+ [10, "Light Brown", "#C1A470"],
906
+ [11, "Light Green", "#94D468"],
907
+ [12, "Light Blue", "#68C8E8"],
908
+ [13, "Light Purple", "#B898E8"],
909
+ [14, "Dark Purple", "#583E8E"],
910
+ [15, "Cyan", "#48C8B8"],
911
+ [16, "Light Yellow", "#E8E898"],
912
+ [17, "Orange", "#E87830"],
913
+ [18, "Light Blue", "#78A8E8"],
914
+ [19, "Dark Pink", "#C83878"],
915
+ [20, "Dark Yellow", "#A0A038"],
916
+ [21, "Dark Orange", "#B07828"],
917
+ [22, "Light Gray", "#B0B0B0"],
918
+ [23, "Light Pink", "#E8A8C0"],
919
+ [24, "Lemon Green", "#88F068"],
920
+ [25, "Forest Green", "#388038"],
921
+ [26, "Electric Blue", "#2060E0"],
922
+ [27, "Bright Purple", "#9840E0"],
923
+ [28, "Dark Yellow", "#7C7C28"],
924
+ [29, "Dark Blue", "#283878"],
925
+ [30, "Dark Cyan", "#287078"],
926
+ [31, "Light Brown", "#A08858"],
927
+ [32, "Light Blue", "#78B0E8"],
928
+ [33, "Light Yellow", "#E8E868"],
929
+ [34, "Light Pink", "#F0A0C0"],
930
+ [35, "Light Red", "#E07868"],
931
+ [36, "Beige", "#D8C898"],
932
+ [37, "White", "#FFFFFF"],
933
+ [38, "Blue", "#4870A0"],
934
+ [39, "Light Gray", "#909898"],
935
+ [40, "Dark Gray", "#585858"],
936
+ [41, "Pink Red", "#E07088"],
937
+ [42, "Blue", "#5090B8"],
938
+ [43, "Light Green", "#88C868"],
939
+ [44, "Light Orange", "#E09048"],
940
+ [45, "White", "#F0F0F0"],
941
+ [46, "Gold", "#D8B838"],
942
+ [47, "Orange", "#E07020"]
943
+ ];
944
+ var BLIP_ICON_DATA = BLIP_ENTRIES.map(([id, name]) => ({
945
+ value: String(id),
946
+ label: `${id} \u2014 ${name}`
947
+ }));
948
+ var BLIP_COLOR_DATA = BLIP_COLORS.map(([id, label]) => ({
949
+ value: String(id),
950
+ label: `${id} \u2014 ${label}`
951
+ }));
952
+ var blipEntryMap = new Map(BLIP_ENTRIES.map(([id, name, ext]) => [String(id), { id, name, ext }]));
953
+ var blipColorMap = new Map(BLIP_COLORS.map(([id, label, hex]) => [String(id), { id, label, hex }]));
954
+ var renderBlipOption = ({ option }) => {
955
+ const entry = blipEntryMap.get(option.value);
956
+ if (!entry) return option.label;
957
+ return /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", children: [
958
+ /* @__PURE__ */ jsx(
959
+ Image,
960
+ {
961
+ src: blipUrl(entry.name, entry.ext),
962
+ alt: entry.name,
963
+ w: 24,
964
+ h: 24,
965
+ fit: "contain",
966
+ style: { imageRendering: "pixelated" }
967
+ }
968
+ ),
969
+ /* @__PURE__ */ jsxs(Text, { size: "xs", truncate: true, children: [
970
+ entry.id,
971
+ " \u2014 ",
972
+ entry.name
973
+ ] })
974
+ ] });
975
+ };
976
+ var renderColorOption = ({ option }) => {
977
+ const entry = blipColorMap.get(option.value);
978
+ if (!entry) return option.label;
979
+ return /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", children: [
980
+ /* @__PURE__ */ jsx(
981
+ Box,
982
+ {
983
+ w: 24,
984
+ h: 24,
985
+ style: {
986
+ borderRadius: 4,
987
+ backgroundColor: entry.hex,
988
+ border: "1px solid rgba(255,255,255,0.15)",
989
+ flexShrink: 0
990
+ }
991
+ }
992
+ ),
993
+ /* @__PURE__ */ jsxs(Text, { size: "xs", truncate: true, children: [
994
+ entry.id,
995
+ " \u2014 ",
996
+ entry.label
997
+ ] })
998
+ ] });
999
+ };
1000
+ function BlipIconSelect({ value, onChange, label = "Blip Icon", size = "xs", ...rest }) {
1001
+ const entry = value != null ? blipEntryMap.get(String(value)) : void 0;
1002
+ return /* @__PURE__ */ jsx(
1003
+ Select,
1004
+ {
1005
+ label,
1006
+ size,
1007
+ ...rest,
1008
+ searchable: true,
1009
+ data: BLIP_ICON_DATA,
1010
+ value: value != null ? String(value) : null,
1011
+ onChange: (val) => val != null && onChange(Number(val)),
1012
+ renderOption: renderBlipOption,
1013
+ maxDropdownHeight: 300,
1014
+ nothingFoundMessage: "No results",
1015
+ leftSection: entry ? /* @__PURE__ */ jsx(
1016
+ Image,
1017
+ {
1018
+ src: blipUrl(entry.name, entry.ext),
1019
+ alt: entry.name,
1020
+ w: 18,
1021
+ h: 18,
1022
+ fit: "contain",
1023
+ style: { imageRendering: "pixelated" }
1024
+ }
1025
+ ) : void 0
1026
+ }
1027
+ );
1028
+ }
1029
+ function BlipColorSelect({ value, onChange, label = "Blip Color", size = "xs", ...rest }) {
1030
+ const entry = value != null ? blipColorMap.get(String(value)) : void 0;
1031
+ return /* @__PURE__ */ jsx(
1032
+ Select,
1033
+ {
1034
+ label,
1035
+ size,
1036
+ ...rest,
1037
+ searchable: true,
1038
+ data: BLIP_COLOR_DATA,
1039
+ value: value != null ? String(value) : null,
1040
+ onChange: (val) => val != null && onChange(Number(val)),
1041
+ renderOption: renderColorOption,
1042
+ maxDropdownHeight: 300,
1043
+ nothingFoundMessage: "No results",
1044
+ leftSection: entry ? /* @__PURE__ */ jsx(
1045
+ Box,
1046
+ {
1047
+ w: 18,
1048
+ h: 18,
1049
+ style: {
1050
+ borderRadius: 4,
1051
+ backgroundColor: entry.hex,
1052
+ border: "1px solid rgba(255,255,255,0.15)",
1053
+ flexShrink: 0
1054
+ }
1055
+ }
1056
+ ) : void 0
1057
+ }
1058
+ );
1059
+ }
10
1060
 
11
1061
  // src/utils/colorWithAlpha.ts
12
1062
  var colorNames = {
@@ -153,11 +1203,11 @@ var colorNames = {
153
1203
  Yellow: { r: 255, g: 255, b: 0 },
154
1204
  YellowGreen: { r: 154, g: 205, b: 50 }
155
1205
  };
156
- function colorWithAlpha(color, alpha5) {
1206
+ function colorWithAlpha(color, alpha8) {
157
1207
  const lowerCasedColor = color.toLowerCase();
158
1208
  if (colorNames[lowerCasedColor]) {
159
1209
  const rgb = colorNames[lowerCasedColor];
160
- return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha5})`;
1210
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha8})`;
161
1211
  }
162
1212
  if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
163
1213
  const hex = color.slice(1);
@@ -165,12 +1215,12 @@ function colorWithAlpha(color, alpha5) {
165
1215
  const r = bigint >> 16 & 255;
166
1216
  const g = bigint >> 8 & 255;
167
1217
  const b = bigint & 255;
168
- return `rgba(${r}, ${g}, ${b}, ${alpha5})`;
1218
+ return `rgba(${r}, ${g}, ${b}, ${alpha8})`;
169
1219
  }
170
1220
  if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
171
1221
  const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
172
1222
  if (result) {
173
- return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha5})`;
1223
+ return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha8})`;
174
1224
  }
175
1225
  }
176
1226
  return color;
@@ -184,6 +1234,7 @@ var useSettings = create(() => ({
184
1234
  primaryColor: "dirk",
185
1235
  primaryShade: 9,
186
1236
  itemImgPath: "",
1237
+ resourceVersion: "dev",
187
1238
  customTheme: [
188
1239
  "#f0f4ff",
189
1240
  "#d9e3ff",
@@ -207,6 +1258,7 @@ async function fetchNui(eventName, data, mockData) {
207
1258
  },
208
1259
  body: JSON.stringify(data)
209
1260
  };
1261
+ if (isEnvBrowser() && mockData !== void 0) return mockData;
210
1262
  if (isEnvBrowser() && mockData === void 0) {
211
1263
  console.warn(
212
1264
  `[fetchNui] Called fetchNui for event "${eventName}" in browser environment without mockData. Returning empty object.`
@@ -241,6 +1293,299 @@ var locale = localeStore.getState().locale;
241
1293
  registerInitialFetch("GET_LOCALES", void 0).then((data) => {
242
1294
  localeStore.setState({ locales: data });
243
1295
  });
1296
+ var useItems = create(() => ({}));
1297
+ var useItemsList = (excludeItemNames = []) => {
1298
+ const excludeSet = new Set(excludeItemNames);
1299
+ return Object.values(useItems.getState()).filter((item) => !excludeSet.has(item.name));
1300
+ };
1301
+ registerInitialFetch("FETCH_ALL_ITEMS", null, {
1302
+ item1: { name: "item1", label: "Item 1", weight: 0.5, image: "item1.png" },
1303
+ item2: { name: "item2", label: "Item 2", weight: 1, image: "item2.png" },
1304
+ item3: { name: "item3", label: "Item 3", weight: 2.5, image: "item3.png" }
1305
+ }).then((fetchedItems) => {
1306
+ if (!fetchedItems) return;
1307
+ useItems.setState(fetchedItems);
1308
+ });
1309
+
1310
+ // src/utils/inputMapper.ts
1311
+ var INPUT_MAPPER_PRIMARY_OPTIONS = [
1312
+ "DIGITALBUTTON_AXIS",
1313
+ "GAME_CONTROLLED",
1314
+ "JOYSTICK_AXIS",
1315
+ "JOYSTICK_AXIS_NEGATIVE",
1316
+ "JOYSTICK_AXIS_POSITIVE",
1317
+ "JOYSTICK_BUTTON",
1318
+ "JOYSTICK_IAXIS",
1319
+ "JOYSTICK_POV",
1320
+ "JOYSTICK_POV_AXIS",
1321
+ "KEYBOARD",
1322
+ "MKB_AXIS",
1323
+ "MOUSE_ABSOLUTEAXIS",
1324
+ "MOUSE_BUTTON",
1325
+ "MOUSE_CENTEREDAXIS",
1326
+ "MOUSE_NORMALIZED",
1327
+ "MOUSE_RELATIVEAXIS",
1328
+ "MOUSE_SCALEDAXIS",
1329
+ "MOUSE_WHEEL",
1330
+ "PAD_ANALOGBUTTON",
1331
+ "PAD_AXIS",
1332
+ "PAD_DEBUGBUTTON",
1333
+ "PAD_DIGITALBUTTON",
1334
+ "TOUCHPAD_ABSOLUTE_AXIS",
1335
+ "TOUCHPAD_CENTERED_AXIS"
1336
+ ];
1337
+ var KEYBOARD_KEYS = [
1338
+ "BACK",
1339
+ "TAB",
1340
+ "RETURN",
1341
+ "PAUSE",
1342
+ "CAPITAL",
1343
+ "ESCAPE",
1344
+ "SPACE",
1345
+ "PAGEUP",
1346
+ "PAGEDOWN",
1347
+ "END",
1348
+ "HOME",
1349
+ "LEFT",
1350
+ "UP",
1351
+ "RIGHT",
1352
+ "DOWN",
1353
+ "INSERT",
1354
+ "DELETE",
1355
+ "0",
1356
+ "1",
1357
+ "2",
1358
+ "3",
1359
+ "4",
1360
+ "5",
1361
+ "6",
1362
+ "7",
1363
+ "8",
1364
+ "9",
1365
+ "A",
1366
+ "B",
1367
+ "C",
1368
+ "D",
1369
+ "E",
1370
+ "F",
1371
+ "G",
1372
+ "H",
1373
+ "I",
1374
+ "J",
1375
+ "K",
1376
+ "L",
1377
+ "M",
1378
+ "N",
1379
+ "O",
1380
+ "P",
1381
+ "Q",
1382
+ "R",
1383
+ "S",
1384
+ "T",
1385
+ "U",
1386
+ "V",
1387
+ "W",
1388
+ "X",
1389
+ "Y",
1390
+ "Z",
1391
+ "F1",
1392
+ "F2",
1393
+ "F3",
1394
+ "F4",
1395
+ "F5",
1396
+ "F6",
1397
+ "F7",
1398
+ "F8",
1399
+ "F9",
1400
+ "F10",
1401
+ "F11",
1402
+ "F12",
1403
+ "NUMPAD0",
1404
+ "NUMPAD1",
1405
+ "NUMPAD2",
1406
+ "NUMPAD3",
1407
+ "NUMPAD4",
1408
+ "NUMPAD5",
1409
+ "NUMPAD6",
1410
+ "NUMPAD7",
1411
+ "NUMPAD8",
1412
+ "NUMPAD9",
1413
+ "MULTIPLY",
1414
+ "ADD",
1415
+ "SUBTRACT",
1416
+ "DECIMAL",
1417
+ "DIVIDE",
1418
+ "NUMPADENTER",
1419
+ "LSHIFT",
1420
+ "RSHIFT",
1421
+ "LCONTROL",
1422
+ "RCONTROL",
1423
+ "LMENU",
1424
+ "RMENU",
1425
+ "LWIN",
1426
+ "RWIN",
1427
+ "APPS",
1428
+ "NUMLOCK",
1429
+ "SCROLL",
1430
+ "OEM_1",
1431
+ "SEMICOLON",
1432
+ "EQUALS",
1433
+ "PLUS",
1434
+ "COMMA",
1435
+ "MINUS",
1436
+ "PERIOD",
1437
+ "SLASH",
1438
+ "OEM_2",
1439
+ "OEM_3",
1440
+ "GRAVE",
1441
+ "LBRACKET",
1442
+ "OEM_4",
1443
+ "BACKSLASH",
1444
+ "OEM_5",
1445
+ "RBRACKET",
1446
+ "OEM_6",
1447
+ "APOSTROPHE",
1448
+ "OEM_7",
1449
+ "OEM_102"
1450
+ ];
1451
+ var MOUSE_BUTTON_KEYS = [
1452
+ "MOUSE_LEFT",
1453
+ "MOUSE_RIGHT",
1454
+ "MOUSE_MIDDLE",
1455
+ "MOUSE_EXTRABTN1",
1456
+ "MOUSE_EXTRABTN2",
1457
+ "MOUSE_EXTRABTN3",
1458
+ "MOUSE_EXTRABTN4",
1459
+ "MOUSE_EXTRABTN5",
1460
+ "IOM_WHEEL_UP",
1461
+ "IOM_WHEEL_DOWN"
1462
+ ];
1463
+ var MOUSE_WHEEL_KEYS = ["IOM_WHEEL_UP", "IOM_WHEEL_DOWN"];
1464
+ var MOUSE_AXIS_KEYS = [
1465
+ "IOM_AXIS_X",
1466
+ "IOM_AXIS_Y",
1467
+ "IOM_AXIS_WHEEL",
1468
+ "IOM_AXIS_WHEEL_DELTA",
1469
+ "IOM_AXIS_WHEEL_RELATIVE",
1470
+ "IOM_IAXIS_X",
1471
+ "IOM_IAXIS_Y",
1472
+ "IOM_IAXIS_WHEEL",
1473
+ "IOM_IAXIS_WHEEL_DELTA",
1474
+ "IOM_IAXIS_WHEEL_RELATIVE",
1475
+ "IOM_AXIS_X_LEFT",
1476
+ "IOM_AXIS_X_RIGHT",
1477
+ "IOM_AXIS_Y_UP",
1478
+ "IOM_AXIS_Y_DOWN",
1479
+ "BASIC_MOUSE_AXIS_MAX",
1480
+ "MOUSE_AXIS_MAX"
1481
+ ];
1482
+ var PAD_BUTTON_KEYS = [
1483
+ "L1_INDEX",
1484
+ "R1_INDEX",
1485
+ "L2_INDEX",
1486
+ "R2_INDEX",
1487
+ "L3_INDEX",
1488
+ "R3_INDEX",
1489
+ "LUP_INDEX",
1490
+ "LRIGHT_INDEX",
1491
+ "LDOWN_INDEX",
1492
+ "LLEFT_INDEX",
1493
+ "RUP_INDEX",
1494
+ "RRIGHT_INDEX",
1495
+ "RDOWN_INDEX",
1496
+ "RLEFT_INDEX",
1497
+ "SELECT_INDEX",
1498
+ "START_INDEX",
1499
+ "TOUCH_INDEX"
1500
+ ];
1501
+ var PAD_DEBUG_KEYS = [
1502
+ "L1",
1503
+ "R1",
1504
+ "L2",
1505
+ "R2",
1506
+ "L3",
1507
+ "R3",
1508
+ "LUP",
1509
+ "LRIGHT",
1510
+ "LDOWN",
1511
+ "LLEFT",
1512
+ "RUP",
1513
+ "RRIGHT",
1514
+ "RDOWN",
1515
+ "RLEFT",
1516
+ "SELECT",
1517
+ "START",
1518
+ "TOUCH"
1519
+ ];
1520
+ var PAD_AXIS_KEYS = [
1521
+ "IOM_AXIS_LX",
1522
+ "IOM_AXIS_LY",
1523
+ "IOM_AXIS_RX",
1524
+ "IOM_AXIS_RY",
1525
+ "IOM_AXIS_LUP",
1526
+ "IOM_AXIS_LDOWN",
1527
+ "IOM_AXIS_LLEFT",
1528
+ "IOM_AXIS_LRIGHT",
1529
+ "IOM_AXIS_LUR",
1530
+ "IOM_AXIS_LUL",
1531
+ "IOM_AXIS_LDR",
1532
+ "IOM_AXIS_LDL",
1533
+ "IOM_AXIS_RUP",
1534
+ "IOM_AXIS_RDOWN",
1535
+ "IOM_AXIS_RLEFT",
1536
+ "IOM_AXIS_RRIGHT",
1537
+ "IOM_AXIS_RUR",
1538
+ "IOM_AXIS_RUL",
1539
+ "IOM_AXIS_RDR",
1540
+ "IOM_AXIS_RDL",
1541
+ "IOM_AXIS_DPADX",
1542
+ "IOM_AXIS_DPADY",
1543
+ "IOM_AXIS_LY_UP",
1544
+ "IOM_AXIS_LY_DOWN",
1545
+ "IOM_AXIS_LX_LEFT",
1546
+ "IOM_AXIS_LX_RIGHT",
1547
+ "IOM_AXIS_RY_UP",
1548
+ "IOM_AXIS_RY_DOWN",
1549
+ "IOM_AXIS_RX_LEFT",
1550
+ "IOM_AXIS_RX_RIGHT"
1551
+ ];
1552
+ var JOYSTICK_AXIS_KEYS = Array.from({ length: 8 }, (_, i) => `IOM_JOYSTICK_AXIS${i + 1}`);
1553
+ var JOYSTICK_BUTTON_KEYS = Array.from({ length: 32 }, (_, i) => `IOM_JOYSTICK_BUTTON${i + 1}`);
1554
+ var JOYSTICK_POV_KEYS = Array.from({ length: 4 }, (_, p) => {
1555
+ const idx = p + 1;
1556
+ return [
1557
+ `IOM_POV${idx}_UP`,
1558
+ `IOM_POV${idx}_RIGHT`,
1559
+ `IOM_POV${idx}_DOWN`,
1560
+ `IOM_POV${idx}_LEFT`
1561
+ ];
1562
+ }).flat();
1563
+ var INPUT_MAPPER_KEYS_BY_PRIMARY = {
1564
+ DIGITALBUTTON_AXIS: [],
1565
+ GAME_CONTROLLED: [],
1566
+ JOYSTICK_AXIS: [...JOYSTICK_AXIS_KEYS],
1567
+ JOYSTICK_AXIS_NEGATIVE: [...JOYSTICK_AXIS_KEYS],
1568
+ JOYSTICK_AXIS_POSITIVE: [...JOYSTICK_AXIS_KEYS],
1569
+ JOYSTICK_BUTTON: [...JOYSTICK_BUTTON_KEYS],
1570
+ JOYSTICK_IAXIS: [...JOYSTICK_AXIS_KEYS],
1571
+ JOYSTICK_POV: [...JOYSTICK_POV_KEYS],
1572
+ JOYSTICK_POV_AXIS: [...JOYSTICK_POV_KEYS],
1573
+ KEYBOARD: [...KEYBOARD_KEYS],
1574
+ MKB_AXIS: [],
1575
+ MOUSE_ABSOLUTEAXIS: [...MOUSE_AXIS_KEYS],
1576
+ MOUSE_BUTTON: [...MOUSE_BUTTON_KEYS],
1577
+ MOUSE_CENTEREDAXIS: [...MOUSE_AXIS_KEYS],
1578
+ MOUSE_NORMALIZED: [...MOUSE_AXIS_KEYS],
1579
+ MOUSE_RELATIVEAXIS: [...MOUSE_AXIS_KEYS],
1580
+ MOUSE_SCALEDAXIS: [...MOUSE_AXIS_KEYS],
1581
+ MOUSE_WHEEL: [...MOUSE_WHEEL_KEYS],
1582
+ PAD_ANALOGBUTTON: [...PAD_BUTTON_KEYS],
1583
+ PAD_AXIS: [...PAD_AXIS_KEYS],
1584
+ PAD_DEBUGBUTTON: [...PAD_DEBUG_KEYS],
1585
+ PAD_DIGITALBUTTON: [...PAD_BUTTON_KEYS],
1586
+ TOUCHPAD_ABSOLUTE_AXIS: [],
1587
+ TOUCHPAD_CENTERED_AXIS: []
1588
+ };
244
1589
  function BorderedIcon(props) {
245
1590
  const theme = useMantineTheme();
246
1591
  return /* @__PURE__ */ jsx(
@@ -1181,6 +2526,195 @@ function LevelPanel(props) {
1181
2526
  }
1182
2527
  );
1183
2528
  }
2529
+ function Modal({
2530
+ title,
2531
+ icon: Icon,
2532
+ iconColor,
2533
+ description,
2534
+ badge,
2535
+ onClose,
2536
+ width = "52vh",
2537
+ maxHeight = "85vh",
2538
+ height,
2539
+ zIndex = 100,
2540
+ clickOutside = true,
2541
+ children
2542
+ }) {
2543
+ const theme = useMantineTheme();
2544
+ return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
2545
+ motion.div,
2546
+ {
2547
+ initial: { opacity: 0 },
2548
+ animate: { opacity: 1 },
2549
+ exit: { opacity: 0 },
2550
+ style: {
2551
+ position: "fixed",
2552
+ inset: 0,
2553
+ zIndex,
2554
+ display: "flex",
2555
+ alignItems: "center",
2556
+ justifyContent: "center",
2557
+ background: "rgba(0,0,0,0.65)"
2558
+ },
2559
+ onClick: clickOutside ? onClose : void 0,
2560
+ children: /* @__PURE__ */ jsxs(
2561
+ motion.div,
2562
+ {
2563
+ initial: { opacity: 0, scale: 0.96, y: 8 },
2564
+ animate: { opacity: 1, scale: 1, y: 0 },
2565
+ exit: { opacity: 0, scale: 0.96, y: 8 },
2566
+ transition: { duration: 0.18, ease: "easeOut" },
2567
+ onClick: (e) => e.stopPropagation(),
2568
+ style: {
2569
+ background: alpha(theme.colors.dark[9], 0.98),
2570
+ border: `0.1vh solid ${theme.colors.dark[7]}`,
2571
+ borderRadius: theme.radius.sm,
2572
+ width,
2573
+ maxHeight,
2574
+ height,
2575
+ display: "flex",
2576
+ flexDirection: "column",
2577
+ overflow: "hidden",
2578
+ userSelect: "none"
2579
+ },
2580
+ children: [
2581
+ /* @__PURE__ */ jsxs(
2582
+ Flex,
2583
+ {
2584
+ justify: "space-between",
2585
+ align: "center",
2586
+ px: "sm",
2587
+ py: "xs",
2588
+ style: {
2589
+ borderBottom: `0.1vh solid ${theme.colors.dark[7]}`,
2590
+ flexShrink: 0
2591
+ },
2592
+ children: [
2593
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
2594
+ Icon && /* @__PURE__ */ jsx(
2595
+ Icon,
2596
+ {
2597
+ color: iconColor ?? "rgba(255,255,255,0.6)",
2598
+ size: "2vh"
2599
+ }
2600
+ ),
2601
+ /* @__PURE__ */ jsx(
2602
+ Text,
2603
+ {
2604
+ ff: "Akrobat Bold",
2605
+ size: "sm",
2606
+ tt: "uppercase",
2607
+ lts: "0.06em",
2608
+ c: "rgba(255,255,255,0.85)",
2609
+ children: title
2610
+ }
2611
+ ),
2612
+ badge && /* @__PURE__ */ jsx(
2613
+ "div",
2614
+ {
2615
+ style: {
2616
+ background: alpha(badge.color, 0.12),
2617
+ border: `0.1vh solid ${alpha(badge.color, 0.35)}`,
2618
+ borderRadius: theme.radius.xs,
2619
+ padding: `0 ${theme.spacing.xxs}`
2620
+ },
2621
+ children: /* @__PURE__ */ jsx(
2622
+ Text,
2623
+ {
2624
+ ff: "Akrobat Bold",
2625
+ size: "xxs",
2626
+ tt: "uppercase",
2627
+ lts: "0.06em",
2628
+ c: badge.color,
2629
+ children: badge.label
2630
+ }
2631
+ )
2632
+ }
2633
+ )
2634
+ ] }),
2635
+ /* @__PURE__ */ jsx(
2636
+ motion.button,
2637
+ {
2638
+ onClick: onClose,
2639
+ whileHover: { background: alpha(theme.colors.dark[7], 0.5) },
2640
+ style: {
2641
+ background: "transparent",
2642
+ border: "none",
2643
+ cursor: "pointer",
2644
+ padding: theme.spacing.xxs,
2645
+ borderRadius: theme.radius.xs,
2646
+ display: "flex"
2647
+ },
2648
+ children: /* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)" })
2649
+ }
2650
+ )
2651
+ ]
2652
+ }
2653
+ ),
2654
+ description && /* @__PURE__ */ jsx(Flex, { px: "sm", pt: "xs", children: /* @__PURE__ */ jsx(
2655
+ Text,
2656
+ {
2657
+ ff: "Akrobat Regular",
2658
+ size: "xs",
2659
+ c: "rgba(255,255,255,0.65)",
2660
+ style: { lineHeight: 1.5 },
2661
+ children: description
2662
+ }
2663
+ ) }),
2664
+ children
2665
+ ]
2666
+ }
2667
+ )
2668
+ }
2669
+ ) });
2670
+ }
2671
+ function PromptModal(props) {
2672
+ const theme = useMantineTheme();
2673
+ return /* @__PURE__ */ jsxs(
2674
+ MotionFlex,
2675
+ {
2676
+ gap: "sm",
2677
+ direction: "column",
2678
+ flex: 1,
2679
+ children: [
2680
+ /* @__PURE__ */ jsx(
2681
+ Text,
2682
+ {
2683
+ size: "xs",
2684
+ c: "rgba(255, 255, 255, 0.8)",
2685
+ children: props.message
2686
+ }
2687
+ ),
2688
+ /* @__PURE__ */ jsx(
2689
+ Flex,
2690
+ {
2691
+ gap: "sm",
2692
+ children: props.buttons.map((button, index) => /* @__PURE__ */ jsx(
2693
+ Button,
2694
+ {
2695
+ variant: button.variant,
2696
+ color: button.color,
2697
+ flex: 0.5,
2698
+ onClick: button.onClick,
2699
+ leftSection: button.icon ? /* @__PURE__ */ jsx(
2700
+ FontAwesomeIcon,
2701
+ {
2702
+ icon: button.icon,
2703
+ style: {
2704
+ fontSize: theme.fontSizes.xs
2705
+ }
2706
+ }
2707
+ ) : void 0,
2708
+ children: button.text
2709
+ },
2710
+ index
2711
+ ))
2712
+ }
2713
+ )
2714
+ ]
2715
+ }
2716
+ );
2717
+ }
1184
2718
  var ModalContext = createContext(null);
1185
2719
  function useModal(selector) {
1186
2720
  const modal = useContext(ModalContext);
@@ -1189,14 +2723,35 @@ function useModal(selector) {
1189
2723
  }
1190
2724
  return useStore(modal, selector);
1191
2725
  }
1192
- function ModalProvider({ children, defaultPage }) {
2726
+ function StoreModal() {
2727
+ const active = useModal((state) => state.active);
2728
+ const { hideModal } = useModalActions();
2729
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: active && /* @__PURE__ */ jsx(
2730
+ Modal,
2731
+ {
2732
+ title: active.title,
2733
+ icon: active.icon,
2734
+ iconColor: active.iconColor,
2735
+ description: active.description,
2736
+ badge: active.badge,
2737
+ onClose: hideModal,
2738
+ width: active.width,
2739
+ maxHeight: active.maxHeight,
2740
+ height: active.height,
2741
+ zIndex: active.zIndex,
2742
+ clickOutside: active.clickOutside,
2743
+ children: active.children
2744
+ }
2745
+ ) });
2746
+ }
2747
+ function ModalProvider({ children }) {
1193
2748
  const storeRef = useRef(
1194
2749
  create(() => ({
1195
2750
  active: null
1196
2751
  }))
1197
2752
  );
1198
2753
  return /* @__PURE__ */ jsxs(ModalContext.Provider, { value: storeRef.current, children: [
1199
- /* @__PURE__ */ jsx(Modal, {}),
2754
+ /* @__PURE__ */ jsx(StoreModal, {}),
1200
2755
  children
1201
2756
  ] });
1202
2757
  }
@@ -1211,173 +2766,1300 @@ function useModalActions() {
1211
2766
  };
1212
2767
  return { showModal, hideModal };
1213
2768
  }
1214
- function Modal() {
1215
- const active = useModal((state) => state.active);
1216
- const { hideModal } = useModalActions();
1217
- const ref = useClickOutside(() => {
1218
- if (!active) return;
1219
- if (active.clickOutside == false) return;
1220
- if (active) {
1221
- hideModal();
1222
- }
1223
- });
2769
+ function ConfirmModal({
2770
+ title,
2771
+ description,
2772
+ confirmLabel = "Delete",
2773
+ confirmText,
2774
+ onConfirm,
2775
+ onClose,
2776
+ zIndex = 200
2777
+ }) {
1224
2778
  const theme = useMantineTheme();
1225
- return /* @__PURE__ */ jsx(AnimatePresence, { children: active && /* @__PURE__ */ jsx(
1226
- MotionFlex,
2779
+ const [typed, setTyped] = useState("");
2780
+ const canConfirm = !confirmText || typed === confirmText;
2781
+ return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
2782
+ motion.div,
1227
2783
  {
1228
- h: "100%",
1229
- w: "100%",
1230
- bg: "rgba(0, 0, 0, 0.3)",
1231
- pos: "absolute",
1232
- style: {
1233
- zIndex: 2e3,
1234
- filter: "drop-shadow(0 0 2vh black)"
1235
- },
1236
2784
  initial: { opacity: 0 },
1237
2785
  animate: { opacity: 1 },
1238
2786
  exit: { opacity: 0 },
1239
- align: "center",
1240
- justify: "center",
2787
+ style: {
2788
+ position: "fixed",
2789
+ inset: 0,
2790
+ zIndex,
2791
+ display: "flex",
2792
+ alignItems: "center",
2793
+ justifyContent: "center",
2794
+ background: "rgba(0,0,0,0.7)"
2795
+ },
2796
+ onClick: onClose,
1241
2797
  children: /* @__PURE__ */ jsxs(
1242
- MotionFlex,
2798
+ motion.div,
1243
2799
  {
1244
- pos: "absolute",
1245
- top: "50%",
1246
- left: "50%",
1247
- ref,
1248
- w: active.width || "40%",
2800
+ initial: { opacity: 0, scale: 0.95, y: 8 },
2801
+ animate: { opacity: 1, scale: 1, y: 0 },
2802
+ exit: { opacity: 0, scale: 0.95, y: 8 },
2803
+ transition: { duration: 0.18, ease: "easeOut" },
2804
+ onClick: (e) => e.stopPropagation(),
1249
2805
  style: {
1250
- transform: "translate(-50%, -50%)",
1251
- borderRadius: theme.radius.xs,
1252
- boxShadow: theme.shadows.xl,
1253
- zIndex: 2100
2806
+ background: alpha(theme.colors.dark[9], 0.98),
2807
+ border: `0.1vh solid ${alpha("#ef4444", 0.3)}`,
2808
+ borderRadius: theme.radius.sm,
2809
+ width: "44vh",
2810
+ display: "flex",
2811
+ flexDirection: "column",
2812
+ overflow: "hidden"
1254
2813
  },
1255
- bg: alpha(theme.colors.dark[9], 0.9),
1256
- initial: { scale: 0.8, opacity: 0, transform: "translate(-50%, -50%)" },
1257
- animate: { scale: 1, opacity: 1, transform: "translate(-50%, -50%)" },
1258
- exit: { scale: 0.8, opacity: 0, transform: "translate(-50%, -50%)" },
1259
- p: "sm",
1260
- direction: "column",
1261
- maw: "70%",
1262
- gap: "xs",
1263
2814
  children: [
1264
2815
  /* @__PURE__ */ jsxs(
1265
2816
  Flex,
1266
2817
  {
1267
- direction: "column",
1268
- w: "100%",
2818
+ justify: "space-between",
2819
+ align: "center",
2820
+ px: "sm",
2821
+ py: "xs",
2822
+ style: {
2823
+ borderBottom: `0.1vh solid ${alpha("#ef4444", 0.2)}`,
2824
+ background: alpha("#ef4444", 0.06),
2825
+ flexShrink: 0
2826
+ },
2827
+ children: [
2828
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
2829
+ /* @__PURE__ */ jsx(AlertTriangle, { size: "1.8vh", color: "#ef4444" }),
2830
+ /* @__PURE__ */ jsx(
2831
+ Text,
2832
+ {
2833
+ ff: "Akrobat Bold",
2834
+ size: "sm",
2835
+ tt: "uppercase",
2836
+ lts: "0.05em",
2837
+ c: "#ef4444",
2838
+ children: title
2839
+ }
2840
+ )
2841
+ ] }),
2842
+ /* @__PURE__ */ jsx(
2843
+ motion.button,
2844
+ {
2845
+ onClick: onClose,
2846
+ whileHover: { background: alpha(theme.colors.dark[7], 0.5) },
2847
+ style: {
2848
+ background: "transparent",
2849
+ border: "none",
2850
+ cursor: "pointer",
2851
+ padding: theme.spacing.xxs,
2852
+ borderRadius: theme.radius.xs,
2853
+ display: "flex"
2854
+ },
2855
+ children: /* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)" })
2856
+ }
2857
+ )
2858
+ ]
2859
+ }
2860
+ ),
2861
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "sm", p: "sm", children: [
2862
+ /* @__PURE__ */ jsx(
2863
+ Text,
2864
+ {
2865
+ ff: "Akrobat Regular",
2866
+ size: "xs",
2867
+ c: "rgba(255,255,255,0.65)",
2868
+ style: { lineHeight: 1.5 },
2869
+ children: description
2870
+ }
2871
+ ),
2872
+ confirmText && /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", children: [
2873
+ /* @__PURE__ */ jsxs(
2874
+ Text,
2875
+ {
2876
+ ff: "Akrobat Bold",
2877
+ size: "xxs",
2878
+ tt: "uppercase",
2879
+ lts: "0.07em",
2880
+ c: "rgba(255,255,255,0.35)",
2881
+ children: [
2882
+ "Type",
2883
+ " ",
2884
+ /* @__PURE__ */ jsx(Text, { component: "span", ff: "Akrobat Bold", c: "#ef4444", children: confirmText }),
2885
+ " ",
2886
+ "to confirm"
2887
+ ]
2888
+ }
2889
+ ),
2890
+ /* @__PURE__ */ jsx(
2891
+ TextInput,
2892
+ {
2893
+ size: "xs",
2894
+ placeholder: confirmText,
2895
+ value: typed,
2896
+ onChange: (e) => setTyped(e.currentTarget.value),
2897
+ styles: (t) => ({
2898
+ input: {
2899
+ backgroundColor: alpha(t.colors.dark[7], 0.5),
2900
+ border: `0.1vh solid ${alpha(
2901
+ typed === confirmText ? "#ef4444" : t.colors.dark[5],
2902
+ 0.5
2903
+ )}`,
2904
+ color: "rgba(255,255,255,0.85)",
2905
+ fontFamily: "Akrobat Regular"
2906
+ }
2907
+ }),
2908
+ autoFocus: true
2909
+ }
2910
+ )
2911
+ ] })
2912
+ ] }),
2913
+ /* @__PURE__ */ jsxs(
2914
+ Flex,
2915
+ {
2916
+ justify: "flex-end",
2917
+ gap: "xs",
2918
+ px: "sm",
2919
+ py: "sm",
2920
+ style: {
2921
+ borderTop: `0.1vh solid ${theme.colors.dark[7]}`,
2922
+ flexShrink: 0
2923
+ },
1269
2924
  children: [
1270
2925
  /* @__PURE__ */ jsxs(
1271
- Flex,
2926
+ motion.button,
1272
2927
  {
1273
- w: "100%",
1274
- align: "center",
1275
- gap: "xs",
2928
+ onClick: onClose,
2929
+ whileHover: { background: alpha(theme.colors.dark[7], 0.5) },
2930
+ whileTap: { scale: 0.97 },
2931
+ style: {
2932
+ background: "transparent",
2933
+ border: `0.1vh solid ${theme.colors.dark[6]}`,
2934
+ borderRadius: theme.radius.xs,
2935
+ padding: "0.5vh 1vh",
2936
+ cursor: "pointer",
2937
+ display: "flex",
2938
+ alignItems: "center",
2939
+ gap: "0.4vh"
2940
+ },
1276
2941
  children: [
1277
- active.icon && /* @__PURE__ */ jsx(
1278
- FontAwesomeIcon,
1279
- {
1280
- icon: active.icon,
1281
- style: {
1282
- fontSize: theme.fontSizes.xs
1283
- }
1284
- }
1285
- ),
2942
+ /* @__PURE__ */ jsx(X, { size: "1.4vh", color: "rgba(255,255,255,0.4)" }),
1286
2943
  /* @__PURE__ */ jsx(
1287
2944
  Text,
1288
2945
  {
1289
- size: "sm",
1290
- children: active.title
1291
- }
1292
- ),
1293
- /* @__PURE__ */ jsx(
1294
- MotionIcon,
1295
- {
1296
- icon: "times",
1297
- color: "rgba(255, 255, 255, 0.7)",
1298
- whileHover: {
1299
- scale: 1.1,
1300
- filter: "brightness(1.2)"
1301
- },
1302
- style: {
1303
- marginLeft: "auto",
1304
- cursor: "pointer",
1305
- fontSize: theme.fontSizes.sm
1306
- },
1307
- onClick: () => {
1308
- hideModal();
1309
- }
2946
+ ff: "Akrobat Bold",
2947
+ size: "xxs",
2948
+ tt: "uppercase",
2949
+ lts: "0.05em",
2950
+ c: "rgba(255,255,255,0.4)",
2951
+ children: "Cancel"
1310
2952
  }
1311
2953
  )
1312
2954
  ]
1313
2955
  }
1314
2956
  ),
1315
- active.description && /* @__PURE__ */ jsx(
1316
- Text,
2957
+ /* @__PURE__ */ jsxs(
2958
+ motion.button,
1317
2959
  {
1318
- size: "xs",
1319
- c: "rgba(255, 255, 255, 0.7)",
1320
- children: active.description
2960
+ onClick: () => {
2961
+ if (canConfirm) {
2962
+ onConfirm();
2963
+ onClose();
2964
+ }
2965
+ },
2966
+ whileHover: canConfirm ? {
2967
+ background: alpha("#ef4444", 0.22),
2968
+ borderColor: alpha("#ef4444", 0.6)
2969
+ } : void 0,
2970
+ whileTap: canConfirm ? { scale: 0.97 } : void 0,
2971
+ style: {
2972
+ background: alpha("#ef4444", canConfirm ? 0.14 : 0.05),
2973
+ border: `0.1vh solid ${alpha(
2974
+ "#ef4444",
2975
+ canConfirm ? 0.45 : 0.15
2976
+ )}`,
2977
+ borderRadius: theme.radius.xs,
2978
+ padding: "0.5vh 1vh",
2979
+ cursor: canConfirm ? "pointer" : "not-allowed",
2980
+ display: "flex",
2981
+ alignItems: "center",
2982
+ gap: "0.4vh",
2983
+ opacity: canConfirm ? 1 : 0.45,
2984
+ transition: "opacity 0.15s"
2985
+ },
2986
+ children: [
2987
+ /* @__PURE__ */ jsx(Trash2, { size: "1.4vh", color: "#ef4444" }),
2988
+ /* @__PURE__ */ jsx(
2989
+ Text,
2990
+ {
2991
+ ff: "Akrobat Bold",
2992
+ size: "xxs",
2993
+ tt: "uppercase",
2994
+ lts: "0.05em",
2995
+ c: "#ef4444",
2996
+ children: confirmLabel
2997
+ }
2998
+ )
2999
+ ]
1321
3000
  }
1322
3001
  )
1323
3002
  ]
1324
3003
  }
1325
- ),
1326
- active.children
3004
+ )
1327
3005
  ]
1328
3006
  }
1329
3007
  )
1330
3008
  }
1331
3009
  ) });
1332
3010
  }
1333
- function PromptModal(props) {
3011
+ function getNested(obj, path) {
3012
+ return path.split(".").reduce((acc, key) => acc ? acc[key] : void 0, obj);
3013
+ }
3014
+ function setNested(obj, path, value) {
3015
+ const keys = path.split(".");
3016
+ const root = Array.isArray(obj) ? [...obj] : { ...obj };
3017
+ let current = root;
3018
+ for (let i = 0; i < keys.length - 1; i++) {
3019
+ const key = keys[i];
3020
+ const nextKey = keys[i + 1];
3021
+ const isIndex = !isNaN(Number(nextKey));
3022
+ const existing = current[key];
3023
+ current[key] = existing != null ? Array.isArray(existing) ? [...existing] : { ...existing } : isIndex ? [] : {};
3024
+ current = current[key];
3025
+ }
3026
+ current[keys[keys.length - 1]] = value;
3027
+ return root;
3028
+ }
3029
+ function deleteNested(obj, path) {
3030
+ const keys = path.split(".");
3031
+ const newObj = { ...obj };
3032
+ let current = newObj;
3033
+ for (let i = 0; i < keys.length - 1; i++) {
3034
+ const key = keys[i];
3035
+ if (!current[key]) return obj;
3036
+ current[key] = { ...current[key] };
3037
+ current = current[key];
3038
+ }
3039
+ delete current[keys[keys.length - 1]];
3040
+ return newObj;
3041
+ }
3042
+ function isPlainObject(value) {
3043
+ return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
3044
+ }
3045
+ function collectChangedPaths(values, initial, prefix = "") {
3046
+ if (Object.is(values, initial)) return [];
3047
+ const valuesIsObj = isPlainObject(values);
3048
+ const initialIsObj = isPlainObject(initial);
3049
+ const valuesIsArr = Array.isArray(values);
3050
+ const initialIsArr = Array.isArray(initial);
3051
+ if (valuesIsArr || initialIsArr) {
3052
+ const maxLen = Math.max(values?.length ?? 0, initial?.length ?? 0);
3053
+ const fields = [];
3054
+ for (let i = 0; i < maxLen; i++) {
3055
+ const nextPrefix = prefix ? `${prefix}.${i}` : `${i}`;
3056
+ fields.push(...collectChangedPaths(values?.[i], initial?.[i], nextPrefix));
3057
+ }
3058
+ return fields;
3059
+ }
3060
+ if (valuesIsObj || initialIsObj) {
3061
+ const keys = /* @__PURE__ */ new Set([
3062
+ ...Object.keys(values ?? {}),
3063
+ ...Object.keys(initial ?? {})
3064
+ ]);
3065
+ const fields = [];
3066
+ for (const key of keys) {
3067
+ const nextPrefix = prefix ? `${prefix}.${key}` : key;
3068
+ fields.push(...collectChangedPaths(values?.[key], initial?.[key], nextPrefix));
3069
+ }
3070
+ return fields;
3071
+ }
3072
+ return prefix ? [prefix] : [];
3073
+ }
3074
+ function computeChangedState(values, initialVals) {
3075
+ const fields = collectChangedPaths(values, initialVals);
3076
+ let partial = {};
3077
+ for (const path of fields) {
3078
+ partial = setNested(partial, path, getNested(values, path));
3079
+ }
3080
+ return { fields, partial };
3081
+ }
3082
+ function flattenRules(rules, prefix = "") {
3083
+ const result = {};
3084
+ for (const key in rules) {
3085
+ const fullPath = prefix ? `${prefix}.${key}` : key;
3086
+ const val = rules[key];
3087
+ if (typeof val === "function") result[fullPath] = val;
3088
+ else if (typeof val === "object")
3089
+ Object.assign(result, flattenRules(val, fullPath));
3090
+ }
3091
+ return result;
3092
+ }
3093
+ async function runRule(rule, value, values) {
3094
+ const result = rule(value, values);
3095
+ return result instanceof Promise ? await result : result;
3096
+ }
3097
+ function createFormStore(initialValues, validationRules, onSubmit) {
3098
+ const flatRules = validationRules ? flattenRules(validationRules) : {};
3099
+ const history = [];
3100
+ const future = [];
3101
+ const changed = /* @__PURE__ */ new Set();
3102
+ return createStore((set, get) => ({
3103
+ initialValues,
3104
+ values: initialValues,
3105
+ errors: {},
3106
+ partialChanged: {},
3107
+ canBack: false,
3108
+ canForward: false,
3109
+ changedFields: [],
3110
+ changedCount: 0,
3111
+ onSubmit,
3112
+ submit: async () => {
3113
+ const state = get();
3114
+ const isValid = await state.validate();
3115
+ if (isValid && state.onSubmit) {
3116
+ state.onSubmit(get());
3117
+ }
3118
+ },
3119
+ getInputProps: (path) => {
3120
+ return {
3121
+ value: getNested(get().values, path) ?? "",
3122
+ error: get().errors[path],
3123
+ onChange: (e) => {
3124
+ get().setValue(path, e.target.value, { validate: true });
3125
+ }
3126
+ };
3127
+ },
3128
+ resetChangeCount: () => {
3129
+ changed.clear();
3130
+ set({ changedFields: [], changedCount: 0, partialChanged: {} });
3131
+ },
3132
+ setInitialValues: (newInitialValues) => set({ initialValues: newInitialValues }),
3133
+ setValue: (path, value, options) => {
3134
+ const state = get();
3135
+ const currentValues = state.values;
3136
+ const newValues = setNested(currentValues, path, value);
3137
+ const oldValue = getNested(state.initialValues, path);
3138
+ const hasChanged = value !== oldValue;
3139
+ history.push(currentValues);
3140
+ future.length = 0;
3141
+ let newPartial = state.partialChanged;
3142
+ if (hasChanged) {
3143
+ changed.add(path);
3144
+ newPartial = setNested(newPartial, path, value);
3145
+ } else {
3146
+ changed.delete(path);
3147
+ newPartial = deleteNested(newPartial, path);
3148
+ }
3149
+ set({
3150
+ values: newValues,
3151
+ partialChanged: newPartial,
3152
+ canBack: history.length > 0,
3153
+ canForward: false,
3154
+ changedFields: Array.from(changed),
3155
+ changedCount: changed.size
3156
+ });
3157
+ if (!options?.validate) return;
3158
+ const rule = flatRules[path];
3159
+ if (!rule) return;
3160
+ Promise.resolve(runRule(rule, value, newValues)).then((error) => {
3161
+ if (error)
3162
+ set((s) => ({ errors: setNested(s.errors, path, error) }));
3163
+ else
3164
+ set((s) => ({ errors: deleteNested(s.errors, path) }));
3165
+ });
3166
+ },
3167
+ setError: (path, message) => set((s) => ({ errors: setNested(s.errors, path, message) })),
3168
+ clearError: (path) => set((s) => ({ errors: deleteNested(s.errors, path) })),
3169
+ validateField: async (path) => {
3170
+ const state = get();
3171
+ const rule = flatRules[path];
3172
+ if (!rule) return true;
3173
+ const value = getNested(state.values, path);
3174
+ const error = await runRule(rule, value, state.values);
3175
+ if (error) {
3176
+ set((s) => ({ errors: setNested(s.errors, path, error) }));
3177
+ return false;
3178
+ }
3179
+ set((s) => ({ errors: deleteNested(s.errors, path) }));
3180
+ return true;
3181
+ },
3182
+ validate: async () => {
3183
+ const state = get();
3184
+ let isValid = true;
3185
+ let newErrors = {};
3186
+ for (const path in flatRules) {
3187
+ const rule = flatRules[path];
3188
+ const value = getNested(state.values, path);
3189
+ const error = await runRule(rule, value, state.values);
3190
+ if (error) {
3191
+ isValid = false;
3192
+ newErrors = setNested(newErrors, path, error);
3193
+ }
3194
+ }
3195
+ set({ errors: newErrors });
3196
+ return isValid;
3197
+ },
3198
+ reset: () => {
3199
+ history.length = 0;
3200
+ future.length = 0;
3201
+ changed.clear();
3202
+ set({
3203
+ values: get().initialValues,
3204
+ errors: {},
3205
+ partialChanged: {},
3206
+ canBack: false,
3207
+ canForward: false,
3208
+ changedFields: [],
3209
+ changedCount: 0
3210
+ });
3211
+ },
3212
+ reinitialize: (newValues) => {
3213
+ history.length = 0;
3214
+ future.length = 0;
3215
+ changed.clear();
3216
+ set({
3217
+ values: newValues,
3218
+ initialValues: newValues,
3219
+ errors: {},
3220
+ partialChanged: {},
3221
+ canBack: false,
3222
+ canForward: false,
3223
+ changedFields: [],
3224
+ changedCount: 0
3225
+ });
3226
+ },
3227
+ back: () => {
3228
+ if (!history.length) return;
3229
+ const prev = history.pop();
3230
+ future.push(get().values);
3231
+ const { fields, partial } = computeChangedState(prev, get().initialValues);
3232
+ set({
3233
+ values: prev,
3234
+ partialChanged: partial,
3235
+ canBack: history.length > 0,
3236
+ canForward: true,
3237
+ changedFields: fields,
3238
+ changedCount: fields.length
3239
+ });
3240
+ },
3241
+ forward: () => {
3242
+ if (!future.length) return;
3243
+ const next = future.pop();
3244
+ history.push(get().values);
3245
+ const { fields, partial } = computeChangedState(next, get().initialValues);
3246
+ set({
3247
+ values: next,
3248
+ partialChanged: partial,
3249
+ canBack: true,
3250
+ canForward: future.length > 0,
3251
+ changedFields: fields,
3252
+ changedCount: fields.length
3253
+ });
3254
+ }
3255
+ }));
3256
+ }
3257
+ var FormContext = createContext(null);
3258
+ function FormProvider({
3259
+ initialValues,
3260
+ validate,
3261
+ onSubmit,
3262
+ children
3263
+ }) {
3264
+ const storeRef = useRef(
3265
+ createFormStore(initialValues, validate, onSubmit)
3266
+ );
3267
+ return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children });
3268
+ }
3269
+ function useForm() {
3270
+ const store = useContext(FormContext);
3271
+ if (!store) {
3272
+ throw new Error("useForm must be used inside <FormProvider>");
3273
+ }
3274
+ const state = useStore(store);
3275
+ const changedFields = useMemo(() => {
3276
+ return collectChangedPaths(state.values, state.initialValues);
3277
+ }, [state.values, state.initialValues]);
3278
+ return { ...state, changedFields, changedCount: changedFields.length };
3279
+ }
3280
+ function getScriptSettingsInstance() {
3281
+ throw new Error("[dirk-cfx-react] createScriptSettings must be called before using SettingsPanel");
3282
+ }
3283
+ var settingsPanelQueryClient = new QueryClient({
3284
+ defaultOptions: { queries: { staleTime: 3e4, gcTime: 5 * 6e4 } }
3285
+ });
3286
+ function NavItemButton({
3287
+ icon: Icon,
3288
+ label,
3289
+ active,
3290
+ onClick
3291
+ }) {
1334
3292
  const theme = useMantineTheme();
3293
+ const color = theme.colors[theme.primaryColor][5];
1335
3294
  return /* @__PURE__ */ jsxs(
1336
- MotionFlex,
3295
+ motion.button,
1337
3296
  {
1338
- gap: "sm",
1339
- direction: "column",
1340
- flex: 1,
3297
+ onClick,
3298
+ whileHover: { background: active ? alpha(color, 0.15) : "rgba(255,255,255,0.04)" },
3299
+ whileTap: { scale: 0.97 },
3300
+ style: {
3301
+ width: "100%",
3302
+ background: active ? alpha(color, 0.12) : "transparent",
3303
+ border: "none",
3304
+ borderLeft: `0.2vh solid ${active ? color : "transparent"}`,
3305
+ borderRadius: `0 ${theme.radius.xs} ${theme.radius.xs} 0`,
3306
+ padding: "0.7vh 1vh",
3307
+ cursor: "pointer",
3308
+ display: "flex",
3309
+ alignItems: "center",
3310
+ gap: "0.7vh",
3311
+ transition: "border-color 0.15s, background 0.15s"
3312
+ },
1341
3313
  children: [
1342
- /* @__PURE__ */ jsx(
1343
- Text,
3314
+ /* @__PURE__ */ jsx(Icon, { color: active ? color : "rgba(255,255,255,0.35)" }),
3315
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.06em", c: active ? color : "rgba(255,255,255,0.35)", children: label }),
3316
+ active && /* @__PURE__ */ jsx(
3317
+ motion.div,
1344
3318
  {
1345
- size: "xs",
1346
- c: "rgba(255, 255, 255, 0.8)",
1347
- children: props.message
3319
+ layoutId: "nav-active-dot",
3320
+ style: { marginLeft: "auto", width: "0.4vh", height: "0.4vh", borderRadius: "50%", background: color }
1348
3321
  }
1349
- ),
3322
+ )
3323
+ ]
3324
+ }
3325
+ );
3326
+ }
3327
+ function SettingsJsonModal({
3328
+ onClose,
3329
+ schema
3330
+ }) {
3331
+ const theme = useMantineTheme();
3332
+ const color = theme.colors[theme.primaryColor][5];
3333
+ const form = useForm();
3334
+ const [json, setJson] = useState(() => JSON.stringify(form.values, null, 2));
3335
+ const [error, setError] = useState(null);
3336
+ const handleSave = () => {
3337
+ try {
3338
+ const parsed = JSON.parse(json);
3339
+ if (schema) {
3340
+ const result = schema.safeParse(parsed);
3341
+ if (!result.success) {
3342
+ setError(result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("\n"));
3343
+ return;
3344
+ }
3345
+ const current = form.values;
3346
+ Object.keys(result.data).forEach((key) => {
3347
+ if (JSON.stringify(result.data[key]) !== JSON.stringify(current[key])) {
3348
+ form.setValue(key, result.data[key]);
3349
+ }
3350
+ });
3351
+ } else {
3352
+ const current = form.values;
3353
+ Object.keys(parsed).forEach((key) => {
3354
+ if (JSON.stringify(parsed[key]) !== JSON.stringify(current[key])) {
3355
+ form.setValue(key, parsed[key]);
3356
+ }
3357
+ });
3358
+ }
3359
+ onClose();
3360
+ } catch (e) {
3361
+ setError(e.message);
3362
+ }
3363
+ };
3364
+ return /* @__PURE__ */ jsxs(Modal, { title: "Settings JSON", icon: Code2, iconColor: color, onClose, width: "60vh", maxHeight: "80vh", zIndex: 200, children: [
3365
+ /* @__PURE__ */ jsxs(Box, { flex: 1, p: "0.8vh", style: { overflowY: "auto" }, children: [
3366
+ /* @__PURE__ */ jsx(
3367
+ JsonInput,
3368
+ {
3369
+ value: json,
3370
+ spellCheck: false,
3371
+ onChange: setJson,
3372
+ rows: 22,
3373
+ formatOnBlur: true,
3374
+ validationError: "Invalid JSON",
3375
+ styles: () => ({
3376
+ input: { fontFamily: "monospace", fontSize: "1.3vh", lineHeight: 1.6, resize: "none" }
3377
+ })
3378
+ }
3379
+ ),
3380
+ error && /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "#ef4444", mt: "xxs", children: error })
3381
+ ] }),
3382
+ /* @__PURE__ */ jsxs(Flex, { justify: "flex-end", gap: "xs", px: "sm", py: "xs", style: { borderTop: `0.1vh solid ${theme.colors.dark[7]}`, flexShrink: 0 }, children: [
3383
+ /* @__PURE__ */ jsxs(
3384
+ motion.button,
3385
+ {
3386
+ onClick: onClose,
3387
+ whileHover: { background: alpha(theme.colors.dark[7], 0.5) },
3388
+ whileTap: { scale: 0.97 },
3389
+ 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 },
3390
+ children: [
3391
+ /* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)" }),
3392
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "Cancel" })
3393
+ ]
3394
+ }
3395
+ ),
3396
+ /* @__PURE__ */ jsxs(
3397
+ motion.button,
3398
+ {
3399
+ onClick: handleSave,
3400
+ whileHover: { background: alpha(color, 0.25) },
3401
+ whileTap: { scale: 0.97 },
3402
+ 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 },
3403
+ children: [
3404
+ /* @__PURE__ */ jsx(Check, { color }),
3405
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: color, children: "Apply" })
3406
+ ]
3407
+ }
3408
+ )
3409
+ ] })
3410
+ ] });
3411
+ }
3412
+ function formatValue(value) {
3413
+ if (value === null) return "null";
3414
+ if (value === void 0) return "undefined";
3415
+ if (typeof value === "string") return value;
3416
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
3417
+ try {
3418
+ return JSON.stringify(value);
3419
+ } catch {
3420
+ return String(value);
3421
+ }
3422
+ }
3423
+ function formatHistoryDateTime(entry) {
3424
+ if (entry.at_unix) {
3425
+ const date = new Date(entry.at_unix * 1e3);
3426
+ if (!Number.isNaN(date.getTime())) {
3427
+ return date.toLocaleString(void 0, { year: "numeric", month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" });
3428
+ }
3429
+ }
3430
+ if (entry.at_utc) {
3431
+ const date = new Date(entry.at_utc);
3432
+ if (!Number.isNaN(date.getTime())) {
3433
+ return date.toLocaleString(void 0, { year: "numeric", month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" });
3434
+ }
3435
+ }
3436
+ return "Unknown time";
3437
+ }
3438
+ function historyEntryKey(entry, index) {
3439
+ return `${entry.at_unix}-${entry.applied_version}-${index}`;
3440
+ }
3441
+ function ChangeDetails({ entry }) {
3442
+ const theme = useMantineTheme();
3443
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.45vh", p: "0.8vh", style: { border: `0.1vh solid ${alpha(theme.colors.dark[6], 0.8)}`, borderRadius: theme.radius.xs, background: alpha(theme.colors.dark[9], 0.35) }, children: [
3444
+ /* @__PURE__ */ jsxs(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: [
3445
+ "Version ",
3446
+ entry.expected_version ?? "?",
3447
+ " ",
3448
+ "\u2192",
3449
+ " ",
3450
+ entry.applied_version ?? "?"
3451
+ ] }),
3452
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "minmax(18vh, 22vh) minmax(0, 1fr) minmax(0, 1fr)", gap: "0.1vh", border: `0.1vh solid ${alpha(theme.colors.dark[6], 0.9)}`, borderRadius: theme.radius.xs, overflow: "hidden", background: alpha(theme.colors.dark[6], 0.8) }, children: [
3453
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", px: "0.6vh", py: "0.45vh", style: { background: alpha(theme.colors.dark[8], 0.85) }, children: "Path" }),
3454
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", px: "0.6vh", py: "0.45vh", style: { background: alpha(theme.colors.dark[8], 0.85) }, children: "From" }),
3455
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", px: "0.6vh", py: "0.45vh", style: { background: alpha(theme.colors.dark[8], 0.85) }, children: "To" }),
3456
+ (entry.changes || []).map((change, idx) => {
3457
+ const bg = idx % 2 === 0 ? alpha(theme.colors.dark[9], 0.5) : alpha(theme.colors.dark[8], 0.42);
3458
+ return [
3459
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "#8ad1ff", px: "0.6vh", py: "0.55vh", style: { background: bg, wordBreak: "break-word" }, children: change.path }, `${idx}-p`),
3460
+ /* @__PURE__ */ jsx(Text, { ff: "monospace", size: "xxs", c: "rgba(255,255,255,0.5)", px: "0.6vh", py: "0.55vh", style: { background: bg, wordBreak: "break-word", whiteSpace: "pre-wrap" }, children: formatValue(change.old) }, `${idx}-o`),
3461
+ /* @__PURE__ */ jsx(Text, { ff: "monospace", size: "xxs", c: "rgba(255,255,255,0.78)", px: "0.6vh", py: "0.55vh", style: { background: bg, wordBreak: "break-word", whiteSpace: "pre-wrap" }, children: formatValue(change.new) }, `${idx}-n`)
3462
+ ];
3463
+ })
3464
+ ] })
3465
+ ] });
3466
+ }
3467
+ function HistoryTableRow({ entry, expanded, onToggle }) {
3468
+ const theme = useMantineTheme();
3469
+ const admin = entry.admin?.name || entry.admin?.identifier || "unknown";
3470
+ const firstPath = entry.changes?.[0]?.path || "-";
3471
+ const changeCount = entry.changes?.length || 0;
3472
+ const versionText = `${entry.expected_version ?? "?"} \u2192 ${entry.applied_version ?? "?"}`;
3473
+ return /* @__PURE__ */ jsx(motion.div, { layout: true, initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.16, ease: "easeOut" }, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.45vh", children: [
3474
+ /* @__PURE__ */ jsx(
3475
+ motion.button,
3476
+ {
3477
+ onClick: onToggle,
3478
+ whileHover: { scale: 1.002 },
3479
+ whileTap: { scale: 0.997 },
3480
+ transition: { duration: 0.12 },
3481
+ style: { background: expanded ? alpha(theme.colors.dark[7], 0.45) : alpha(theme.colors.dark[8], 0.35), border: `0.1vh solid ${expanded ? alpha(theme.colors[theme.primaryColor][5], 0.35) : alpha(theme.colors.dark[6], 0.75)}`, borderRadius: theme.radius.xs, padding: "0.65vh 0.75vh", cursor: "pointer", textAlign: "left" },
3482
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "2.2vh 20vh 12vh 6vh 1fr minmax(16vh, auto)", gap: "0.8vh", alignItems: "center" }, children: [
3483
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx(motion.div, { animate: { rotate: expanded ? 0 : -90 }, transition: { duration: 0.18, ease: "easeOut" }, children: /* @__PURE__ */ jsx(ChevronDown, { size: "1.5vh", color: expanded ? "rgba(255,255,255,0.6)" : "rgba(255,255,255,0.45)" }) }) }),
3484
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.75)", lineClamp: 1, children: formatHistoryDateTime(entry) }),
3485
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.68)", lineClamp: 1, children: admin }),
3486
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.68)", children: changeCount }),
3487
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.58)", lineClamp: 1, children: firstPath }),
3488
+ /* @__PURE__ */ jsx(Text, { ff: "monospace", size: "xxs", c: "rgba(255,255,255,0.68)", children: versionText })
3489
+ ] })
3490
+ }
3491
+ ),
3492
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: expanded && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0, height: 0, y: -4 }, animate: { opacity: 1, height: "auto", y: 0 }, exit: { opacity: 0, height: 0, y: -4 }, transition: { duration: 0.2, ease: "easeInOut" }, style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx(ChangeDetails, { entry }) }, "details") })
3493
+ ] }) });
3494
+ }
3495
+ function HistoryTableHeader() {
3496
+ const theme = useMantineTheme();
3497
+ return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "2.2vh 20vh 12vh 6vh 1fr minmax(16vh, auto)", gap: "0.8vh", alignItems: "center", border: `0.1vh solid ${alpha(theme.colors.dark[6], 0.8)}`, borderRadius: theme.radius.xs, background: alpha(theme.colors.dark[8], 0.55), padding: "0.55vh 0.75vh" }, children: [
3498
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.35)", children: " " }),
3499
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "Time" }),
3500
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "Admin" }),
3501
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "#" }),
3502
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "First Change" }),
3503
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: "Version" })
3504
+ ] });
3505
+ }
3506
+ function SettingsHistoryModal({
3507
+ onClose
3508
+ }) {
3509
+ const { getHistory } = getScriptSettingsInstance();
3510
+ const theme = useMantineTheme();
3511
+ const color = theme.colors[theme.primaryColor][5];
3512
+ const [queryInput, setQueryInput] = useState("");
3513
+ const [pathInput, setPathInput] = useState("");
3514
+ const [adminInput, setAdminInput] = useState("");
3515
+ const [query, setQuery] = useState("");
3516
+ const [path, setPath] = useState("");
3517
+ const [admin, setAdmin] = useState("");
3518
+ const [expandedKey, setExpandedKey] = useState(null);
3519
+ const filters = useMemo(() => ({ query, path, admin }), [query, path, admin]);
3520
+ const historyQuery = useInfiniteQuery({
3521
+ queryKey: ["scriptSettingsHistory", filters],
3522
+ initialPageParam: 0,
3523
+ queryFn: async ({ pageParam }) => {
3524
+ const response = await getHistory({
3525
+ offset: pageParam,
3526
+ limit: 25,
3527
+ query: filters.query || void 0,
3528
+ path: filters.path || void 0,
3529
+ admin: filters.admin || void 0
3530
+ });
3531
+ if (!response?.success || !response.data) {
3532
+ throw new Error(response?._error || "Failed to load settings history");
3533
+ }
3534
+ return response.data;
3535
+ },
3536
+ getNextPageParam: (lastPage) => lastPage.nextOffset
3537
+ });
3538
+ const rows = historyQuery.data?.pages.flatMap((page) => page.items) ?? [];
3539
+ const total = historyQuery.data?.pages[0]?.total ?? 0;
3540
+ const handleListScroll = (e) => {
3541
+ const el = e.currentTarget;
3542
+ if (el.scrollHeight - el.scrollTop - el.clientHeight < 280 && historyQuery.hasNextPage && !historyQuery.isFetchingNextPage) {
3543
+ historyQuery.fetchNextPage();
3544
+ }
3545
+ };
3546
+ return /* @__PURE__ */ jsxs(Modal, { title: "Settings History", icon: History, iconColor: color, onClose, width: "88vh", maxHeight: "82vh", zIndex: 260, children: [
3547
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minHeight: 0 }, children: [
3548
+ /* @__PURE__ */ jsxs(Flex, { gap: "xs", p: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[7], 0.8)}` }, children: [
3549
+ /* @__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 } }),
3550
+ /* @__PURE__ */ jsx(TextInput, { leftSection: /* @__PURE__ */ jsx(Filter, { size: "1.4vh" }), placeholder: "Path filter (e.g. basic.weightUnit)", value: pathInput, onChange: (e) => setPathInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
3551
+ /* @__PURE__ */ jsx(TextInput, { leftSection: /* @__PURE__ */ jsx(User, { size: "1.4vh" }), placeholder: "Admin filter", value: adminInput, onChange: (e) => setAdminInput(e.currentTarget.value), size: "xs", style: { flex: 1 } }),
1350
3552
  /* @__PURE__ */ jsx(
1351
- Flex,
3553
+ motion.button,
1352
3554
  {
1353
- gap: "sm",
1354
- children: props.buttons.map((button, index) => /* @__PURE__ */ jsx(
1355
- Button,
1356
- {
1357
- variant: button.variant,
1358
- color: button.color,
1359
- flex: 0.5,
1360
- onClick: button.onClick,
1361
- leftSection: button.icon ? /* @__PURE__ */ jsx(
1362
- FontAwesomeIcon,
1363
- {
1364
- icon: button.icon,
1365
- style: {
1366
- fontSize: theme.fontSizes.xs
1367
- }
1368
- }
1369
- ) : void 0,
1370
- children: button.text
1371
- },
1372
- index
1373
- ))
3555
+ onClick: () => {
3556
+ setExpandedKey(null);
3557
+ setQuery(queryInput.trim());
3558
+ setPath(pathInput.trim().toLowerCase());
3559
+ setAdmin(adminInput.trim().toLowerCase());
3560
+ },
3561
+ whileHover: { background: alpha(color, 0.2) },
3562
+ whileTap: { scale: 0.97 },
3563
+ style: { background: alpha(color, 0.12), border: `0.1vh solid ${alpha(color, 0.35)}`, borderRadius: theme.radius.xs, padding: "0.55vh 0.85vh", cursor: "pointer" },
3564
+ children: /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: color, children: "Apply" })
1374
3565
  }
1375
3566
  )
3567
+ ] }),
3568
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xs", p: "sm", style: { flex: 1, minHeight: 0, overflowY: "auto" }, onScroll: handleListScroll, children: [
3569
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.45)", children: historyQuery.isFetching && !historyQuery.data ? "Loading history..." : `${total} entries` }),
3570
+ /* @__PURE__ */ jsx(HistoryTableHeader, {}),
3571
+ historyQuery.isError && /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", c: "#ef4444", children: historyQuery.error.message }),
3572
+ !historyQuery.isLoading && rows.length === 0 && !historyQuery.isError && /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", c: "rgba(255,255,255,0.45)", children: "No history found for current filters." }),
3573
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: rows.map((entry, index) => {
3574
+ const key = historyEntryKey(entry, index);
3575
+ return /* @__PURE__ */ jsx(HistoryTableRow, { entry, expanded: expandedKey === key, onToggle: () => setExpandedKey(expandedKey === key ? null : key) }, key);
3576
+ }) }),
3577
+ (historyQuery.isFetchingNextPage || historyQuery.isLoading) && /* @__PURE__ */ jsx(Flex, { justify: "center", py: "sm", children: /* @__PURE__ */ jsx(Loader, { size: "sm", color }) })
3578
+ ] })
3579
+ ] }),
3580
+ /* @__PURE__ */ jsx(Flex, { justify: "flex-end", gap: "xs", px: "sm", py: "xs", style: { borderTop: `0.1vh solid ${theme.colors.dark[7]}`, flexShrink: 0 }, children: /* @__PURE__ */ jsxs(
3581
+ motion.button,
3582
+ {
3583
+ onClick: onClose,
3584
+ whileHover: { background: alpha(theme.colors.dark[7], 0.5) },
3585
+ whileTap: { scale: 0.97 },
3586
+ 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 },
3587
+ children: [
3588
+ /* @__PURE__ */ jsx(X, { color: "rgba(255,255,255,0.4)", size: "1.5vh" }),
3589
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.05em", c: "rgba(255,255,255,0.4)", children: "Close" })
3590
+ ]
3591
+ }
3592
+ ) })
3593
+ ] });
3594
+ }
3595
+ function SettingsPanelInner({
3596
+ navItems,
3597
+ title,
3598
+ subtitle,
3599
+ children,
3600
+ isSaving,
3601
+ onClose,
3602
+ schema,
3603
+ resetConfirmText,
3604
+ defaultSettings,
3605
+ width,
3606
+ height
3607
+ }) {
3608
+ const { updateSettings, getHistory } = getScriptSettingsInstance();
3609
+ const form = useForm();
3610
+ const theme = useMantineTheme();
3611
+ const color = theme.colors[theme.primaryColor][5];
3612
+ const version = useSettings((s) => s.resourceVersion);
3613
+ const [activeTab, setActiveTab] = useState(navItems[0]?.id ?? "");
3614
+ const [jsonOpen, setJsonOpen] = useState(false);
3615
+ const [historyOpen, setHistoryOpen] = useState(false);
3616
+ const [resetOpen, setResetOpen] = useState(false);
3617
+ const [closeConfirmOpen, setCloseConfirmOpen] = useState(false);
3618
+ const changedCount = form.changedCount ?? 0;
3619
+ const isDirty = changedCount > 0;
3620
+ useEffect(() => {
3621
+ function handleKeyDown(e) {
3622
+ if (e.key !== "Escape") return;
3623
+ if (isDirty) {
3624
+ e.preventDefault();
3625
+ setCloseConfirmOpen(true);
3626
+ return;
3627
+ }
3628
+ onClose();
3629
+ }
3630
+ window.addEventListener("keydown", handleKeyDown);
3631
+ return () => window.removeEventListener("keydown", handleKeyDown);
3632
+ }, [isDirty, onClose]);
3633
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3634
+ /* @__PURE__ */ jsx(AnimatePresence, { children: jsonOpen && /* @__PURE__ */ jsx(SettingsJsonModal, { onClose: () => setJsonOpen(false), schema }) }),
3635
+ /* @__PURE__ */ jsx(AnimatePresence, { children: historyOpen && /* @__PURE__ */ jsx(SettingsHistoryModal, { onClose: () => setHistoryOpen(false) }) }),
3636
+ /* @__PURE__ */ jsx(AnimatePresence, { children: resetOpen && /* @__PURE__ */ jsx(
3637
+ ConfirmModal,
3638
+ {
3639
+ title: "Reset to Defaults",
3640
+ description: "This will permanently reset ALL settings back to their defaults. Every setting you have configured will be overwritten. This cannot be undone.",
3641
+ confirmLabel: "Reset Settings",
3642
+ confirmText: resetConfirmText,
3643
+ onConfirm: () => {
3644
+ updateSettings(defaultSettings).then(() => form.reinitialize(cloneSettings(defaultSettings)));
3645
+ setResetOpen(false);
3646
+ },
3647
+ onClose: () => setResetOpen(false),
3648
+ zIndex: 300
3649
+ }
3650
+ ) }),
3651
+ /* @__PURE__ */ jsx(AnimatePresence, { children: closeConfirmOpen && /* @__PURE__ */ jsx(
3652
+ ConfirmModal,
3653
+ {
3654
+ title: "Discard Unsaved Changes?",
3655
+ description: "You have unsaved changes. Closing now will discard them.",
3656
+ confirmLabel: "Close Without Saving",
3657
+ onConfirm: () => {
3658
+ setCloseConfirmOpen(false);
3659
+ onClose();
3660
+ },
3661
+ onClose: () => setCloseConfirmOpen(false),
3662
+ zIndex: 300
3663
+ }
3664
+ ) }),
3665
+ /* @__PURE__ */ jsxs(
3666
+ MotionFlex,
3667
+ {
3668
+ pos: "absolute",
3669
+ left: "50%",
3670
+ top: "50%",
3671
+ bg: alpha(theme.colors.dark[9], 0.9),
3672
+ w: width ?? "120vh",
3673
+ h: height ?? "80vh",
3674
+ bdrs: "sm",
3675
+ style: {
3676
+ userSelect: "none",
3677
+ overflow: "hidden",
3678
+ transform: "translate(-50%, -50%)",
3679
+ boxShadow: "0 0 10px rgba(0,0,0,0.5)",
3680
+ border: `0.1vh solid ${theme.colors.dark[7]}`
3681
+ },
3682
+ direction: "row",
3683
+ initial: { scale: 0.3, opacity: 0, transform: "translate(-50%, -50%)" },
3684
+ animate: { scale: 1, opacity: 1, transform: "translate(-50%, -50%)" },
3685
+ exit: { scale: 0.3, opacity: 0, transform: "translate(-50%, -50%)" },
3686
+ children: [
3687
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { width: "18vh", flexShrink: 0, borderRight: `0.1vh solid ${alpha(theme.colors.dark[6], 0.8)}`, background: alpha(theme.colors.dark[8], 0.6), overflow: "hidden" }, children: [
3688
+ /* @__PURE__ */ jsxs(Flex, { align: "baseline", gap: "0.3vh", px: "sm", py: "sm", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3689
+ /* @__PURE__ */ jsx(Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", children: title }),
3690
+ subtitle && /* @__PURE__ */ jsx(Text, { tt: "uppercase", fw: 600, c: color, children: subtitle })
3691
+ ] }),
3692
+ /* @__PURE__ */ jsxs(Flex, { gap: "xxs", px: "xs", py: "xs", style: { borderBottom: `0.1vh solid ${alpha(theme.colors.dark[6], 0.4)}`, flexShrink: 0 }, children: [
3693
+ /* @__PURE__ */ jsx(
3694
+ motion.button,
3695
+ {
3696
+ title: "Undo",
3697
+ onClick: () => form.canBack && form.back(),
3698
+ disabled: !form.canBack,
3699
+ whileHover: form.canBack ? { background: "rgba(255,255,255,0.07)" } : void 0,
3700
+ whileTap: form.canBack ? { scale: 0.97 } : void 0,
3701
+ style: { flex: 1, aspectRatio: "1 / 1", background: "transparent", border: `0.1vh solid ${alpha(theme.colors.dark[5], form.canBack ? 0.6 : 0.3)}`, borderRadius: theme.radius.xs, cursor: form.canBack ? "pointer" : "default", display: "flex", alignItems: "center", justifyContent: "center", opacity: form.canBack ? 1 : 0.35, transition: "opacity 0.2s" },
3702
+ children: /* @__PURE__ */ jsx(Undo2, { size: "1.5vh", color: "rgba(255,255,255,0.7)" })
3703
+ }
3704
+ ),
3705
+ /* @__PURE__ */ jsx(
3706
+ motion.button,
3707
+ {
3708
+ title: "Redo",
3709
+ onClick: () => form.canForward && form.forward(),
3710
+ disabled: !form.canForward,
3711
+ whileHover: form.canForward ? { background: "rgba(255,255,255,0.07)" } : void 0,
3712
+ whileTap: form.canForward ? { scale: 0.97 } : void 0,
3713
+ style: { flex: 1, aspectRatio: "1 / 1", background: "transparent", border: `0.1vh solid ${alpha(theme.colors.dark[5], form.canForward ? 0.6 : 0.3)}`, borderRadius: theme.radius.xs, cursor: form.canForward ? "pointer" : "default", display: "flex", alignItems: "center", justifyContent: "center", opacity: form.canForward ? 1 : 0.35, transition: "opacity 0.2s" },
3714
+ children: /* @__PURE__ */ jsx(Redo2, { size: "1.5vh", color: "rgba(255,255,255,0.7)" })
3715
+ }
3716
+ ),
3717
+ /* @__PURE__ */ jsx(
3718
+ motion.button,
3719
+ {
3720
+ title: isSaving ? "Saving..." : isDirty ? `Save (${changedCount})` : "Save",
3721
+ onClick: () => isDirty && !isSaving && form.submit(),
3722
+ disabled: !isDirty || isSaving,
3723
+ whileHover: isDirty && !isSaving ? { background: alpha(color, 0.25), borderColor: alpha(color, 0.5) } : void 0,
3724
+ whileTap: isDirty && !isSaving ? { scale: 0.97 } : void 0,
3725
+ style: { flex: 1, aspectRatio: "1 / 1", background: isDirty ? alpha(color, 0.14) : "transparent", border: `0.1vh solid ${isDirty ? alpha(color, 0.35) : alpha(theme.colors.dark[5], 0.3)}`, borderRadius: theme.radius.xs, cursor: isDirty && !isSaving ? "pointer" : "default", display: "flex", alignItems: "center", justifyContent: "center", opacity: isDirty ? 1 : 0.35, transition: "opacity 0.2s, background 0.15s" },
3726
+ children: isSaving ? /* @__PURE__ */ jsx(Loader, { size: "1.5vh", color, type: "dots" }) : /* @__PURE__ */ jsx(Save, { color: isDirty ? color : "rgba(255,255,255,0.35)", size: "1.5vh" })
3727
+ }
3728
+ ),
3729
+ /* @__PURE__ */ jsx(
3730
+ motion.button,
3731
+ {
3732
+ title: "History",
3733
+ onClick: () => setHistoryOpen(true),
3734
+ whileHover: { background: alpha("#22d3ee", 0.16), borderColor: alpha("#22d3ee", 0.5) },
3735
+ whileTap: { scale: 0.97 },
3736
+ style: { flex: 1, aspectRatio: "1 / 1", background: alpha("#22d3ee", 0.07), border: `0.1vh solid ${alpha("#22d3ee", 0.25)}`, borderRadius: theme.radius.xs, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" },
3737
+ children: /* @__PURE__ */ jsx(History, { color: "#22d3ee", size: "1.5vh" })
3738
+ }
3739
+ )
3740
+ ] }),
3741
+ /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "xxs", p: "xs", style: { flex: 1, overflowY: "auto" }, children: navItems.map((item) => /* @__PURE__ */ jsx(NavItemButton, { icon: item.icon, label: item.label, active: activeTab === item.id, onClick: () => setActiveTab(item.id) }, item.id)) }),
3742
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", p: "xs", gap: "xs", style: { borderTop: `0.1vh solid ${alpha(theme.colors.dark[6], 0.5)}`, flexShrink: 0 }, children: [
3743
+ /* @__PURE__ */ jsxs(
3744
+ motion.button,
3745
+ {
3746
+ onClick: () => isDirty && form.reset(),
3747
+ disabled: !isDirty,
3748
+ whileHover: isDirty ? { background: alpha("#f97316", 0.12), borderColor: alpha("#f97316", 0.45) } : void 0,
3749
+ whileTap: isDirty ? { scale: 0.97 } : void 0,
3750
+ 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" },
3751
+ children: [
3752
+ /* @__PURE__ */ jsx(XCircle, { color: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", size: "1.6vh" }),
3753
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: isDirty ? "#f97316" : "rgba(255,255,255,0.35)", children: "Discard" })
3754
+ ]
3755
+ }
3756
+ ),
3757
+ /* @__PURE__ */ jsx("div", { style: { height: "0.05vh", background: "rgba(255,255,255,0.07)", margin: "0.1vh 0" } }),
3758
+ /* @__PURE__ */ jsxs(
3759
+ motion.button,
3760
+ {
3761
+ onClick: () => setJsonOpen(true),
3762
+ whileHover: { background: alpha(color, 0.16), borderColor: alpha(color, 0.45) },
3763
+ whileTap: { scale: 0.97 },
3764
+ 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" },
3765
+ children: [
3766
+ /* @__PURE__ */ jsx(Code2, { color, size: "1.6vh" }),
3767
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: "Manual Edit" })
3768
+ ]
3769
+ }
3770
+ ),
3771
+ /* @__PURE__ */ jsxs(
3772
+ motion.button,
3773
+ {
3774
+ onClick: () => setResetOpen(true),
3775
+ whileHover: { background: alpha("#ef4444", 0.16), borderColor: alpha("#ef4444", 0.5) },
3776
+ whileTap: { scale: 0.97 },
3777
+ 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" },
3778
+ children: [
3779
+ /* @__PURE__ */ jsx(RotateCcw, { color: "#ef4444", size: "1.6vh" }),
3780
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: "#ef4444", children: "Reset Defaults" })
3781
+ ]
3782
+ }
3783
+ ),
3784
+ version && /* @__PURE__ */ jsxs(Text, { size: "0.95vh", c: "dimmed", ta: "center", style: { letterSpacing: "0.04em", opacity: 0.8 }, children: [
3785
+ "Version ",
3786
+ version
3787
+ ] })
3788
+ ] })
3789
+ ] }),
3790
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
3791
+ motion.div,
3792
+ {
3793
+ initial: { opacity: 0, y: 4 },
3794
+ animate: { opacity: 1, y: 0 },
3795
+ exit: { opacity: 0, y: -4 },
3796
+ transition: { duration: 0.15 },
3797
+ style: { flex: 1, display: "flex", flexDirection: "column", overflowY: "auto" },
3798
+ children: children(activeTab)
3799
+ },
3800
+ activeTab
3801
+ ) })
3802
+ ]
3803
+ }
3804
+ )
3805
+ ] });
3806
+ }
3807
+ function cloneSettings(value) {
3808
+ return JSON.parse(JSON.stringify(value));
3809
+ }
3810
+ var defaultOnClose = () => fetchNui("CLOSE_ADMIN_SECTION");
3811
+ function SettingsPanel(props) {
3812
+ const { open, onClose = defaultOnClose } = props;
3813
+ const { store, updateSettings, fetchSettings } = getScriptSettingsInstance();
3814
+ const [isSaving, setIsSaving] = useState(false);
3815
+ const [loaded, setLoaded] = useState(false);
3816
+ useEffect(() => {
3817
+ if (!open) {
3818
+ setLoaded(false);
3819
+ return;
3820
+ }
3821
+ let cancelled = false;
3822
+ fetchSettings().then(() => {
3823
+ if (!cancelled) setLoaded(true);
3824
+ }).catch(() => {
3825
+ if (!cancelled) setLoaded(true);
3826
+ });
3827
+ return () => {
3828
+ cancelled = true;
3829
+ };
3830
+ }, [open]);
3831
+ if (!open || !loaded) return null;
3832
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: settingsPanelQueryClient, children: /* @__PURE__ */ jsx(
3833
+ FormProvider,
3834
+ {
3835
+ initialValues: cloneSettings(store.getState()),
3836
+ onSubmit: async (form) => {
3837
+ if (isSaving) return;
3838
+ setIsSaving(true);
3839
+ try {
3840
+ const result = await updateSettings(form.values);
3841
+ if (result?.success) {
3842
+ form.reinitialize(cloneSettings(form.values));
3843
+ settingsPanelQueryClient.invalidateQueries({ queryKey: ["scriptSettingsHistory"] });
3844
+ return;
3845
+ }
3846
+ form.reinitialize(cloneSettings(store.getState()));
3847
+ if (result?._error) {
3848
+ console.warn(`[SettingsPanel] settings save failed: ${result._error}`);
3849
+ }
3850
+ } finally {
3851
+ setIsSaving(false);
3852
+ }
3853
+ },
3854
+ children: /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(
3855
+ SettingsPanelInner,
3856
+ {
3857
+ ...props,
3858
+ onClose,
3859
+ isSaving
3860
+ }
3861
+ ) })
3862
+ }
3863
+ ) });
3864
+ }
3865
+ function LazyImage({ src, alt, style }) {
3866
+ const [visible, setVisible] = useState(false);
3867
+ const ref = useRef(null);
3868
+ useEffect(() => {
3869
+ const observer = new IntersectionObserver(([entry]) => {
3870
+ if (entry.isIntersecting) {
3871
+ setVisible(true);
3872
+ observer.disconnect();
3873
+ }
3874
+ });
3875
+ if (ref.current) observer.observe(ref.current);
3876
+ return () => observer.disconnect();
3877
+ }, []);
3878
+ return /* @__PURE__ */ jsx("div", { ref, style: { width: "4vh", height: "4vh" }, children: visible && /* @__PURE__ */ jsx(Image, { src, alt, fit: "contain", style }) });
3879
+ }
3880
+ function SelectItem(props) {
3881
+ const invItems = useItems();
3882
+ const formattedItems = useMemo(() => {
3883
+ const seen = /* @__PURE__ */ new Set();
3884
+ return useItemsList(props.excludeItemNames ?? []).filter((item) => {
3885
+ if (seen.has(item.name)) return false;
3886
+ seen.add(item.name);
3887
+ return true;
3888
+ }).map((item) => ({ value: item.name, label: item.label, image: item.image }));
3889
+ }, [invItems, props.excludeItemNames]);
3890
+ return /* @__PURE__ */ jsx(
3891
+ Select,
3892
+ {
3893
+ maxDropdownHeight: "30vh",
3894
+ label: locale(props.label),
3895
+ size: "xs",
3896
+ flex: 1,
3897
+ style: props.style,
3898
+ limit: 50,
3899
+ value: props.value,
3900
+ onChange: (v) => props.onChange(v),
3901
+ data: formattedItems,
3902
+ allowDeselect: false,
3903
+ searchable: true,
3904
+ leftSectionWidth: "4vh",
3905
+ leftSection: props.value ? /* @__PURE__ */ jsx(
3906
+ Image,
3907
+ {
3908
+ fallbackSrc: "/placeholder.png",
3909
+ src: invItems[props.value]?.image || "",
3910
+ alt: props.value,
3911
+ fit: "contain",
3912
+ maw: "4vh",
3913
+ style: { aspectRatio: "1 / 1" }
3914
+ }
3915
+ ) : null,
3916
+ nothingFoundMessage: locale("NoItemsFound"),
3917
+ renderOption: (item) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", w: "100%", children: [
3918
+ /* @__PURE__ */ jsx(
3919
+ LazyImage,
3920
+ {
3921
+ src: invItems[item.option.value]?.image || "",
3922
+ alt: item.option.label,
3923
+ style: { aspectRatio: "1 / 1" }
3924
+ }
3925
+ ),
3926
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
3927
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: item.option.label }),
3928
+ /* @__PURE__ */ jsx(Text, { size: "xxs", c: "dimmed", children: item.option.value })
3929
+ ] })
3930
+ ] })
3931
+ }
3932
+ );
3933
+ }
3934
+ var KeyBindContext = createContext(null);
3935
+ function useKeyBindContext() {
3936
+ const ctx = useContext(KeyBindContext);
3937
+ if (!ctx) {
3938
+ throw new Error("FiveMKeyBindInput.* must be used inside <FiveMKeyBindInput>");
3939
+ }
3940
+ return ctx;
3941
+ }
3942
+ function Root({ value, onChange, children }) {
3943
+ return /* @__PURE__ */ jsx(KeyBindContext.Provider, { value: { value, onChange }, children: /* @__PURE__ */ jsx(Flex, { gap: "xs", style: { flex: 1 }, children }) });
3944
+ }
3945
+ function Category({ label = "Primary" }) {
3946
+ const { value, onChange } = useKeyBindContext();
3947
+ return /* @__PURE__ */ jsx(
3948
+ Select,
3949
+ {
3950
+ label,
3951
+ size: "xs",
3952
+ style: { flex: 1 },
3953
+ value: value._type,
3954
+ data: [...INPUT_MAPPER_PRIMARY_OPTIONS],
3955
+ onChange: (nextType) => {
3956
+ if (!nextType) return;
3957
+ const keyOptions = INPUT_MAPPER_KEYS_BY_PRIMARY[nextType] ?? [];
3958
+ const hasCurrentKey = keyOptions.includes(value._key);
3959
+ const nextKey = hasCurrentKey ? value._key : keyOptions[0] ?? value._key;
3960
+ onChange({
3961
+ ...value,
3962
+ _type: nextType,
3963
+ _key: nextKey
3964
+ });
3965
+ },
3966
+ searchable: true,
3967
+ allowDeselect: false
3968
+ }
3969
+ );
3970
+ }
3971
+ function Key({ label = "Key" }) {
3972
+ const { value, onChange } = useKeyBindContext();
3973
+ const keyOptions = INPUT_MAPPER_KEYS_BY_PRIMARY[value._type] ?? [];
3974
+ if (keyOptions.length === 0) {
3975
+ return /* @__PURE__ */ jsx(
3976
+ TextInput,
3977
+ {
3978
+ label,
3979
+ size: "xs",
3980
+ style: { flex: 1 },
3981
+ value: value._key,
3982
+ onChange: (e) => onChange({ ...value, _key: e.currentTarget.value }),
3983
+ placeholder: "Type key value"
3984
+ }
3985
+ );
3986
+ }
3987
+ return /* @__PURE__ */ jsx(
3988
+ Select,
3989
+ {
3990
+ label,
3991
+ size: "xs",
3992
+ style: { flex: 1 },
3993
+ value: value._key,
3994
+ data: keyOptions,
3995
+ onChange: (nextKey) => {
3996
+ if (!nextKey) return;
3997
+ onChange({ ...value, _key: nextKey });
3998
+ },
3999
+ searchable: true,
4000
+ allowDeselect: false
4001
+ }
4002
+ );
4003
+ }
4004
+ var FiveMKeyBindInput = Object.assign(Root, {
4005
+ Category,
4006
+ Key
4007
+ });
4008
+ function AsyncSaveButton({
4009
+ onSave,
4010
+ color,
4011
+ label = "Save Changes",
4012
+ style
4013
+ }) {
4014
+ const theme = useMantineTheme();
4015
+ const [state, setState] = useState("idle");
4016
+ const handleClick = async () => {
4017
+ if (state === "pending") return;
4018
+ setState("pending");
4019
+ try {
4020
+ const result = await onSave();
4021
+ setState(result?.success === false ? "error" : "success");
4022
+ } catch {
4023
+ setState("error");
4024
+ }
4025
+ setTimeout(() => setState("idle"), 2e3);
4026
+ };
4027
+ const c = state === "error" ? "#ef4444" : color;
4028
+ return /* @__PURE__ */ jsxs(
4029
+ motion.button,
4030
+ {
4031
+ onClick: handleClick,
4032
+ disabled: state === "pending",
4033
+ whileHover: state === "pending" ? {} : { background: alpha(c, 0.25) },
4034
+ whileTap: state === "pending" ? {} : { scale: 0.98 },
4035
+ style: {
4036
+ background: alpha(c, 0.14),
4037
+ border: `0.1vh solid ${alpha(c, 0.4)}`,
4038
+ borderRadius: theme.radius.xs,
4039
+ padding: `${theme.spacing.xxs} ${theme.spacing.xs}`,
4040
+ cursor: state === "pending" ? "default" : "pointer",
4041
+ display: "flex",
4042
+ alignItems: "center",
4043
+ justifyContent: "center",
4044
+ gap: theme.spacing.xxs,
4045
+ transition: "background 0.2s, border-color 0.2s",
4046
+ alignSelf: "flex-end",
4047
+ ...style
4048
+ },
4049
+ children: [
4050
+ state === "pending" ? /* @__PURE__ */ jsx(Loader, { size: "1.4vh", color: c, type: "oval" }) : state === "error" ? /* @__PURE__ */ jsx(X, { size: "1.4vh", color: c }) : /* @__PURE__ */ jsx(Check, { size: "1.4vh", color: c }),
4051
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.06em", c, children: state === "success" ? "Saved!" : state === "error" ? "Failed!" : label })
1376
4052
  ]
1377
4053
  }
1378
4054
  );
1379
4055
  }
4056
+ function AdminPageTitle(props) {
4057
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", children: [
4058
+ /* @__PURE__ */ jsx(props.icon, { color: props.color }),
4059
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", tt: "uppercase", lts: "0.1em", size: "sm", c: "rgba(255,255,255,0.6)", children: locale(props.title) })
4060
+ ] });
4061
+ }
1380
4062
 
1381
- export { BorderedIcon, Counter, FloatingParticles, InfoBox, InputContainer, LevelBanner, LevelPanel, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PromptModal, SegmentedControl, SegmentedProgress, Title, useModal, useModalActions, useNavigation, useNavigationStore };
4063
+ export { AdminPageTitle, AsyncSaveButton, BlipColorSelect, BlipIconSelect, BorderedIcon, ConfirmModal, Counter, FiveMKeyBindInput, FloatingParticles, InfoBox, InputContainer, LevelBanner, LevelPanel, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PromptModal, SegmentedControl, SegmentedProgress, SelectItem, SettingsPanel, Title, useModal, useModalActions, useNavigation, useNavigationStore };
1382
4064
  //# sourceMappingURL=index.js.map
1383
4065
  //# sourceMappingURL=index.js.map