dirk-cfx-react 1.1.53 → 1.1.54

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