From f3e847ae3581f6ddf5251515a88ba3e90d7caedc Mon Sep 17 00:00:00 2001 From: Mr Sneaky <123227860+MrSne7aky@users.noreply.github.com> Date: Fri, 15 Aug 2025 07:48:22 +0200 Subject: [PATCH 01/25] fix(server/main.lua): ensure player has weapon before removal Added a check to ensure the player actually has the weapon before removing it. This prevents players from triggering a bug or exploiting the armory callback. Signed-off-by: Mr Sneaky <123227860+MrSne7aky@users.noreply.github.com> --- [esx_addons]/esx_policejob/server/main.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/[esx_addons]/esx_policejob/server/main.lua b/[esx_addons]/esx_policejob/server/main.lua index fc0042cc..2c887840 100644 --- a/[esx_addons]/esx_policejob/server/main.lua +++ b/[esx_addons]/esx_policejob/server/main.lua @@ -252,10 +252,12 @@ end) ESX.RegisterServerCallback('esx_policejob:addArmoryWeapon', function(source, cb, weaponName, removeWeapon) local xPlayer = ESX.GetPlayerFromId(source) - - if removeWeapon then - xPlayer.removeWeapon(weaponName) - end + + if removeWeapon and xPlayer.hasWeapon(weaponName) then + xPlayer.removeWeapon(weaponName) + else + return cb() + end TriggerEvent('esx_datastore:getSharedDataStore', 'society_police', function(store) local weapons = store.get('weapons') or {} From ad23050875af1dcbbe508c225d61fb35d6e4521a Mon Sep 17 00:00:00 2001 From: Mr Sneaky <123227860+MrSne7aky@users.noreply.github.com> Date: Fri, 15 Aug 2025 21:50:35 +0200 Subject: [PATCH 02/25] ix(server/main.lua): ensure player has weapon before removal Signed-off-by: Mr Sneaky <123227860+MrSne7aky@users.noreply.github.com> --- [esx_addons]/esx_policejob/server/main.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/[esx_addons]/esx_policejob/server/main.lua b/[esx_addons]/esx_policejob/server/main.lua index 2c887840..aadf60e3 100644 --- a/[esx_addons]/esx_policejob/server/main.lua +++ b/[esx_addons]/esx_policejob/server/main.lua @@ -253,10 +253,11 @@ end) ESX.RegisterServerCallback('esx_policejob:addArmoryWeapon', function(source, cb, weaponName, removeWeapon) local xPlayer = ESX.GetPlayerFromId(source) - if removeWeapon and xPlayer.hasWeapon(weaponName) then + if removeWeapon then + if not xPlayer.hasWeapon(weaponName) then + return cb() + end xPlayer.removeWeapon(weaponName) - else - return cb() end TriggerEvent('esx_datastore:getSharedDataStore', 'society_police', function(store) From ecfb592a8b6f3074d59b4f739a2150d238ca12f4 Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Mon, 1 Sep 2025 19:30:45 +0100 Subject: [PATCH 03/25] Remove outdated check for `esx_hud` Repo deprecated, moved to ESX-Legacy-Addons --- [esx_addons]/esx_hud/fxmanifest.lua | 2 +- [esx_addons]/esx_hud/locales/da.lua | 7 +- [esx_addons]/esx_hud/locales/de.lua | 7 +- [esx_addons]/esx_hud/locales/en.lua | 7 +- [esx_addons]/esx_hud/locales/fi.lua | 5 -- [esx_addons]/esx_hud/locales/fr.lua | 5 -- [esx_addons]/esx_hud/locales/hu.lua | 27 +++---- [esx_addons]/esx_hud/locales/it.lua | 5 -- [esx_addons]/esx_hud/locales/nl.lua | 5 -- [esx_addons]/esx_hud/locales/pt.lua | 5 -- [esx_addons]/esx_hud/locales/sr.lua | 5 -- [esx_addons]/esx_hud/locales/sv.lua | 5 -- [esx_addons]/esx_hud/locales/tr.lua | 5 -- [esx_addons]/esx_hud/server/main.lua | 104 --------------------------- 14 files changed, 14 insertions(+), 180 deletions(-) delete mode 100644 [esx_addons]/esx_hud/server/main.lua diff --git a/[esx_addons]/esx_hud/fxmanifest.lua b/[esx_addons]/esx_hud/fxmanifest.lua index b2ad203b..db931645 100644 --- a/[esx_addons]/esx_hud/fxmanifest.lua +++ b/[esx_addons]/esx_hud/fxmanifest.lua @@ -4,7 +4,7 @@ lua54 "yes" description "The default HUD resource for ESX-Legacy." version "1.10.2" -legacyversion '1.13.3' +legacyversion '1.13.4' shared_scripts { "@es_extended/imports.lua", diff --git a/[esx_addons]/esx_hud/locales/da.lua b/[esx_addons]/esx_hud/locales/da.lua index e7ae4dcd..a8e1c1ba 100644 --- a/[esx_addons]/esx_hud/locales/da.lua +++ b/[esx_addons]/esx_hud/locales/da.lua @@ -7,10 +7,5 @@ Locales["da"] = { resource_not_built = "Ressourcen er ikke lavet, download venligst udgivelsesversionen", settingsSaveSuccess = "De nuværende indstillinger er gemt", settingsResetSuccess = "Indstillingerne blev nulstillet", - currentVersion = "Seneste version: ", - yourVersion = "Din version: ", - latestVersion = "Du bruger den seneste version!", - needUpdateResource = "Du skal downloade den nyeste version! Du bruger en gammel version i øjeblikket!", - errorGetCurrentVersion = "Der opstod en fejl under forsøget på at hente den nuværende version!", job_off_duty = " (Ikke på vagt)", -} +} \ No newline at end of file diff --git a/[esx_addons]/esx_hud/locales/de.lua b/[esx_addons]/esx_hud/locales/de.lua index e6642da5..664a8f57 100644 --- a/[esx_addons]/esx_hud/locales/de.lua +++ b/[esx_addons]/esx_hud/locales/de.lua @@ -7,10 +7,5 @@ Locales["de"] = { resource_not_built = "Resource ist gebuilded! Downloade die neuste version!", settingsSaveSuccess = "Erfolgreich die derzeitigen einstellungen gespeichert!", settingsResetSuccess = "Einstellungen erfolgreich zurückgesetzt", - currentVersion = "Letzte Version: ", - yourVersion = "Deine Version: ", - latestVersion = "Du nutzt die neuste Version von esx_hud!", - needUpdateResource = "Du musst die letze Version downloaden! Installiere die neuste Version!", - errorGetCurrentVersion = "Ein Fehler kam als die Versionsabfrage durchgeführt wurde!", job_off_duty = " (Außer Dienst)", -} +} \ No newline at end of file diff --git a/[esx_addons]/esx_hud/locales/en.lua b/[esx_addons]/esx_hud/locales/en.lua index dbfe0843..ee1c3cc5 100644 --- a/[esx_addons]/esx_hud/locales/en.lua +++ b/[esx_addons]/esx_hud/locales/en.lua @@ -7,10 +7,5 @@ Locales["en"] = { resource_not_built = "Resource are not built, please download the release version", settingsSaveSuccess = "Successfully save current settings", settingsResetSuccess = "Successfully reset settings", - currentVersion = "Latest version: ", - yourVersion = "Your version: ", - latestVersion = "You are using the latest version!", - needUpdateResource = "You need download latest version! You are using an old version at the moment!", - errorGetCurrentVersion = "An error occurred while trying to get the current version!", job_off_duty = " (Off-Duty)", -} +} \ No newline at end of file diff --git a/[esx_addons]/esx_hud/locales/fi.lua b/[esx_addons]/esx_hud/locales/fi.lua index 45f0ab49..8bbc617f 100644 --- a/[esx_addons]/esx_hud/locales/fi.lua +++ b/[esx_addons]/esx_hud/locales/fi.lua @@ -7,10 +7,5 @@ Locales["fi"] = { resource_not_built = "Resursseja ei ole rakennettu, lataa julkaisuversio", settingsSaveSuccess = "Nykyisten asetusten tallentaminen onnistui", settingsResetSuccess = "Asetusten nollaus onnistui", - currentVersion = "Uusin versio: ", - yourVersion = "Sinun versio: ", - latestVersion = "Käytät uusinta versiota!", - needUpdateResource = "Sinun on ladattava uusin versio! Käytät tällä hetkellä vanhaa versiota!", - errorGetCurrentVersion = "Virhe yritettäessä saada nykyinen versio!", job_off_duty = " (Vapaalla)", } diff --git a/[esx_addons]/esx_hud/locales/fr.lua b/[esx_addons]/esx_hud/locales/fr.lua index 8e0575ff..d7706038 100644 --- a/[esx_addons]/esx_hud/locales/fr.lua +++ b/[esx_addons]/esx_hud/locales/fr.lua @@ -7,10 +7,5 @@ Locales["fr"] = { resource_not_built = "La ressource n'est pas build, télécharger une version officielle ou compilez la ressource vous même", settingsSaveSuccess = "Les paramètres actuels ont bien été sauvegardés", settingsResetSuccess = "Les paramètres ont bien été réinitialisés", - currentVersion = "Dernière version: ", - yourVersion = "Votre version: ", - latestVersion = "Vous utilisez la dernière version!", - needUpdateResource = "Vous devez télécharger la dernière version! Vous utilisez actuellement une ancienne version!", - errorGetCurrentVersion = "Une erreur s'est produite lors de la tentative d'obtention de la version actuelle!", job_off_duty = " (Hors service)", } diff --git a/[esx_addons]/esx_hud/locales/hu.lua b/[esx_addons]/esx_hud/locales/hu.lua index 70cbe924..c6b343f5 100644 --- a/[esx_addons]/esx_hud/locales/hu.lua +++ b/[esx_addons]/esx_hud/locales/hu.lua @@ -1,18 +1,11 @@ Locales["hu"] = { - toggleHud = "Hud ki / be kapcsolása", - indicatorLeft = "Bal index", - indicatorRight = "Jobb index", - toggleEngine = "Motor ki / be kapcsolása", - increaseSpeed = "(Tempomat) Sebbeség nővelése", - decreaseSpeed = "(Tempomat) Sebbeség csökkenentése", - speedChanged = "Sebesség megváltoztatva, új sebbeség: ", - resource_not_built = "Nincs le buildelve a resource, kérlek töltsd le a release-t", - settingsSaveSuccess = "Sikeresen megtörtént a mentése beállításoknak!", - settingsResetSuccess = "Sikeresen megtörtént a visszaállítása a beállításoknak!", - latestVersion = "Legújabb verziót használod!", - currentVersion = "Legfrissebb verzió: ", - yourVersion = "Jelenlegi verziód: ", - needUpdateResource = "Elavult a verziód töltsd le a legújabbat!", - errorGetCurrentVersion = "Hiba történt a verzió lekérdezés közben!", - job_off_duty = " (Szabadnapos)", -} + toggleHud = "HUD be/ki kapcsolása", + indicatorLeft = "Bal irányjelző", + indicatorRight = "Jobb irányjelző", + toggleEngine = "Motor be/ki kapcsolása", + speedChanged = "Sebesség megváltoztatva, új sebesség: ", + resource_not_built = "Az erőforrás nincs lefordítva, töltsd le a kiadott verziót", + settingsSaveSuccess = "A jelenlegi beállítások sikeresen elmentve", + settingsResetSuccess = "A beállítások sikeresen visszaállítva", + job_off_duty = " (Szolgálaton kívül)", +} \ No newline at end of file diff --git a/[esx_addons]/esx_hud/locales/it.lua b/[esx_addons]/esx_hud/locales/it.lua index 99fc0516..adef39f3 100644 --- a/[esx_addons]/esx_hud/locales/it.lua +++ b/[esx_addons]/esx_hud/locales/it.lua @@ -7,10 +7,5 @@ Locales["it"] = { resource_not_built = "La risorsa non è stata buildata, scarica la versione release, non il source code!", settingsSaveSuccess = "Salvataggio delle impostazioni correnti riuscito", settingsResetSuccess = "Ripristino impostazioni riuscito", - currentVersion = "Ultima versione ", - yourVersion = "La tua versione:", - latestVersion = "Stai utilizzando l'ultima versione!", - needUpdateResource = "Devi scaricare l'ultima versione! Al momento stai usando una vecchia versione!", - errorGetCurrentVersion = "Si è verificato un errore durante il tentativo di ottenere la versione corrente!", job_off_duty = " (Fuori servizio)", } diff --git a/[esx_addons]/esx_hud/locales/nl.lua b/[esx_addons]/esx_hud/locales/nl.lua index 31bae3c6..bfa12d6f 100644 --- a/[esx_addons]/esx_hud/locales/nl.lua +++ b/[esx_addons]/esx_hud/locales/nl.lua @@ -7,10 +7,5 @@ Locales["nl"] = { resource_not_built = "Resource is niet gebouwd, download de releaseversie", settingsSaveSuccess = "De instellingen zijn succesvol opgeslagen", settingsResetSuccess = "De instellingen zijn succesvol gereset", - currentVersion = "Laatste versie: ", - yourVersion = "Jouw versie: ", - latestVersion = "Je gebruikt de laatste versie !", - needUpdateResource = "Je bent een oude versie aan het gebruiken ! download de nieuwste versie !", - errorGetCurrentVersion = "Er is een error ontstaan tijdens het ophalen van de huidige versie !", job_off_duty = " (Niet in dienst)", } diff --git a/[esx_addons]/esx_hud/locales/pt.lua b/[esx_addons]/esx_hud/locales/pt.lua index afd70543..27ba7279 100644 --- a/[esx_addons]/esx_hud/locales/pt.lua +++ b/[esx_addons]/esx_hud/locales/pt.lua @@ -7,10 +7,5 @@ Locales["pt"] = { resource_not_built = 'O resource não foi construido, por favor faz download da versão "Release"', settingsSaveSuccess = "Salvaste as atuais definições com sucesso", settingsResetSuccess = "Formataste as definições com sucesso", - currentVersion = "Versão mais recente: ", - yourVersion = "A tua versão: ", - latestVersion = "Estás a usar a versão mais recente!", - needUpdateResource = "Precisas de descarregar a versão mais recente! Neste momento, estás a utilizar uma versão antiga!", - errorGetCurrentVersion = "Ocorreu um erro ao tentar obter a versão atual!", job_off_duty = " (Fora de serviço)", } diff --git a/[esx_addons]/esx_hud/locales/sr.lua b/[esx_addons]/esx_hud/locales/sr.lua index 3927d575..8a8b3148 100644 --- a/[esx_addons]/esx_hud/locales/sr.lua +++ b/[esx_addons]/esx_hud/locales/sr.lua @@ -7,10 +7,5 @@ Locales["sr"] = { resource_not_built = "Resurs nije napravljen, preuzmite release verziju resursa!", settingsSaveSuccess = "Trenutna podešavanja uspešno sačuvana", settingsResetSuccess = "Podešavanja uspešno resetovana", - currentVersion = "Poslednja verzija: ", - yourVersion = "Vaša verzija: ", - latestVersion = "Vi koristite poslednju verziju!", - needUpdateResource = "Morate preuzeti najnoviju verziju. Trenutno koristite staru verziju.", - errorGetCurrentVersion = "Došlo je do greške prilikom provere trenutne verzije resursa!", job_off_duty = " (Van dužnosti)", } diff --git a/[esx_addons]/esx_hud/locales/sv.lua b/[esx_addons]/esx_hud/locales/sv.lua index 21a87bd2..6a3e19be 100644 --- a/[esx_addons]/esx_hud/locales/sv.lua +++ b/[esx_addons]/esx_hud/locales/sv.lua @@ -7,10 +7,5 @@ Locales["sv"] = { resource_not_built = "Resource är inte byggd, ladda ner release versionen", settingsSaveSuccess = "Inställningar sparade", settingsResetSuccess = "Inställningar återställda", - currentVersion = "Senaste version: ", - yourVersion = "Din version: ", - latestVersion = "Du använder den senaste versionen!", - needUpdateResource = "Du behöver ladda ner den senaste versionen! Du använder en gammal version just nu!", - errorGetCurrentVersion = "Ett fel inträffade med att ladda ner den senaste versionen!", job_off_duty = " (Ledig)", } diff --git a/[esx_addons]/esx_hud/locales/tr.lua b/[esx_addons]/esx_hud/locales/tr.lua index b286439f..d371e7e5 100644 --- a/[esx_addons]/esx_hud/locales/tr.lua +++ b/[esx_addons]/esx_hud/locales/tr.lua @@ -7,10 +7,5 @@ Locales["tr"] = { resource_not_built = "Kaynak kurulmamış, lütfen son sürümü indirin", settingsSaveSuccess = "Ayarlar başarıyla kaydedildi", settingsResetSuccess = "Ayarlar başarıyla sıfırlandı", - currentVersion = "En son sürüm: ", - yourVersion = "Sizin sürümünüz: ", - latestVersion = "Şu anda en son sürümü kullanıyorsunuz!", - needUpdateResource = "En son sürümü indirmeniz gerekiyor! Şu anda eski bir sürümü kullanıyorsunuz!", - errorGetCurrentVersion = "Geçerli sürümü alırken bir hata oluştu!", job_off_duty = " (Görev dışı)", } diff --git a/[esx_addons]/esx_hud/server/main.lua b/[esx_addons]/esx_hud/server/main.lua deleted file mode 100644 index 3fe1fd8c..00000000 --- a/[esx_addons]/esx_hud/server/main.lua +++ /dev/null @@ -1,104 +0,0 @@ -HUD.VersionCheckURL = "https://api.github.com/repos/esx-framework/esx-hud/releases/latest" - -function HUD:ErrorHandle(msg) - print(("[^1ERROR^7] ^3esx_hud^7: %s"):format(msg)) -end - -function HUD:InfoHandle(msg, color) - if color == "green" then - color = 2 - elseif color == "red" then - color = 1 - elseif color == "blue" then - color = 4 - else - color = 3 - end - print(("[^9INFO^7] ^3esx_hud^7: ^" .. color .. "%s^7"):format(msg)) -end - -VERSION = { - Check = function(err, response, headers) - --Credit: OX_lib version checker by Linden - local currentVersion = GetResourceMetadata(GetCurrentResourceName(), "version", 0) - local latestVersion - if not currentVersion then - return - end - - if err ~= 200 then - HUD:ErrorHandle(Translate("errorGetCurrentVersion")) - return - end - if response then - response = json.decode(response) - if not response.tag_name then - return - end - - latestVersion = response.tag_name:match("%d%.%d+%.%d+") - currentVersion = currentVersion:match("%d%.%d+%.%d+") - - if not latestVersion then - return - end - - if currentVersion == latestVersion then - HUD:InfoHandle(Translate("latestVersion"), "green") - return - end - - local currentVersionSplitted = { string.strsplit(".", currentVersion) } - local latestVersionSplitted = { string.strsplit(".", latestVersion) } - - HUD:InfoHandle(Translate("currentVersion") .. latestVersion, "green") - HUD:InfoHandle(Translate("yourVersion") .. currentVersion, "blue") - - for i = 1, #currentVersionSplitted do - local current, latest = tonumber(currentVersionSplitted[i]), tonumber(latestVersionSplitted[i]) - if current ~= latest then - if not current or not latest then - return - end - if current < latest then - HUD:InfoHandle(Translate("needUpdateResource"), "red") - else - break - end - end - end - end - end, - - RunVersionChecker = function() - CreateThread(function() - PerformHttpRequest(HUD.VersionCheckURL, VERSION.Check, "GET") - end) - end, -} - -RegisterNetEvent("esx_hud:ErrorHandle", function(msg) - HUD:ErrorHandle(msg) -end) - -AddEventHandler("onResourceStart", function(resourceName) - local currentName = GetCurrentResourceName() - if resourceName ~= currentName then - return - end - local built = LoadResourceFile(currentName, "./web/dist/index.html") - - Wait(100) - - --Run version checker - VERSION:RunVersionChecker() - - if not built then - CreateThread(function() - while true do - HUD:ErrorHandle(Translate("resource_not_built")) - Wait(10000) - end - end) - end -end) From 85ad0616efce89cc34af88a0b5bf791bcd96104f Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Mon, 1 Sep 2025 19:40:17 +0100 Subject: [PATCH 04/25] Switch to ESX TextUI Update client/main.lua --- [esx_addons]/esx_dmvschool/client/main.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/[esx_addons]/esx_dmvschool/client/main.lua b/[esx_addons]/esx_dmvschool/client/main.lua index 719cce1c..e0225ee9 100644 --- a/[esx_addons]/esx_dmvschool/client/main.lua +++ b/[esx_addons]/esx_dmvschool/client/main.lua @@ -186,11 +186,13 @@ AddEventHandler('esx_dmvschool:hasEnteredMarker', function(zone) CurrentActionMsg = TranslateCap('press_open_menu') CurrentActionData = {} end + ESX.TextUI(CurrentActionMsg) end) AddEventHandler('esx_dmvschool:hasExitedMarker', function(zone) CurrentAction = nil ESX.CloseContext() + ESX.HideUI() end) RegisterNetEvent('esx_dmvschool:loadLicenses') @@ -277,7 +279,6 @@ CreateThread(function() if CurrentAction then sleep = 0 - ESX.ShowHelpNotification(CurrentActionMsg) if (IsControlJustReleased(0, 38)) and (CurrentAction == 'dmvschool_menu') then OpenDMVSchoolMenu() From 3e759de6a51814d7bc2686ad6b35d43be82d2f22 Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Mon, 1 Sep 2025 19:48:43 +0100 Subject: [PATCH 05/25] Switch to ESX TextUI Update client/main.lua --- [esx_addons]/esx_accessories/client/main.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/[esx_addons]/esx_accessories/client/main.lua b/[esx_addons]/esx_accessories/client/main.lua index 8d7a5d32..77d0872f 100644 --- a/[esx_addons]/esx_accessories/client/main.lua +++ b/[esx_addons]/esx_accessories/client/main.lua @@ -124,11 +124,13 @@ AddEventHandler('esx_accessories:hasEnteredMarker', function(zone) CurrentAction = 'shop_menu' CurrentActionMsg = TranslateCap('press_access') CurrentActionData = { accessory = zone } + ESX.TextUI(CurrentActionMsg) end) AddEventHandler('esx_accessories:hasExitedMarker', function(zone) ESX.CloseContext() CurrentAction = nil + ESX.HideUI() end) -- Create Blips -- @@ -212,7 +214,6 @@ CreateThread(function() if CurrentAction then Sleep = 0 - ESX.ShowHelpNotification(CurrentActionMsg) if IsControlJustReleased(0, 38) and CurrentActionData.accessory then OpenShopMenu(CurrentActionData.accessory) From a10dd80c868a71867aed1e4e6fcff9d6c6fe7f8c Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Mon, 1 Sep 2025 20:12:29 +0100 Subject: [PATCH 06/25] refactor(esx_accessories/client/main): switch to ESX:TextUI ### Description This PR replaces ESX.ShowHelpNotification with the new ESX:TextUI system for better consistency across the ESX framework. ### PR Checklist - [X] My commit messages and PR title follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/?utm_source=chatgpt.com) standard. - [X] My changes have been tested locally and function as expected. - [X] My PR does not introduce any breaking changes. - [X] I have provided a clear explanation of what my PR does, including the reasoning behind the changes and any relevant context. --- [esx_addons]/esx_accessories/client/main.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/[esx_addons]/esx_accessories/client/main.lua b/[esx_addons]/esx_accessories/client/main.lua index 77d0872f..8d7a5d32 100644 --- a/[esx_addons]/esx_accessories/client/main.lua +++ b/[esx_addons]/esx_accessories/client/main.lua @@ -124,13 +124,11 @@ AddEventHandler('esx_accessories:hasEnteredMarker', function(zone) CurrentAction = 'shop_menu' CurrentActionMsg = TranslateCap('press_access') CurrentActionData = { accessory = zone } - ESX.TextUI(CurrentActionMsg) end) AddEventHandler('esx_accessories:hasExitedMarker', function(zone) ESX.CloseContext() CurrentAction = nil - ESX.HideUI() end) -- Create Blips -- @@ -214,6 +212,7 @@ CreateThread(function() if CurrentAction then Sleep = 0 + ESX.ShowHelpNotification(CurrentActionMsg) if IsControlJustReleased(0, 38) and CurrentActionData.accessory then OpenShopMenu(CurrentActionData.accessory) From da9c59644b841e6f2e579d7733d702303647618a Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Tue, 2 Sep 2025 21:46:05 +0100 Subject: [PATCH 07/25] refactor(esx_drugs): switch to ESX:TextUI This PR replaces ESX.ShowHelpNotification with the new ESX:TextUI system for better consistency across the ESX framework. --- [esx_addons]/esx_taxijob/client/main.lua | 14 ++------------ [esx_addons]/esx_taxijob/fxmanifest.lua | 2 +- [esx_addons]/esx_taxijob/locales/de.lua | 11 +++++------ [esx_addons]/esx_taxijob/locales/en.lua | 1 - [esx_addons]/esx_taxijob/locales/es.lua | 1 - [esx_addons]/esx_taxijob/locales/fi.lua | 11 +++++------ [esx_addons]/esx_taxijob/locales/fr.lua | 1 - [esx_addons]/esx_taxijob/locales/hu.lua | 1 - [esx_addons]/esx_taxijob/locales/it.lua | 1 - [esx_addons]/esx_taxijob/locales/nl.lua | 11 +++++------ [esx_addons]/esx_taxijob/locales/pl.lua | 11 +++++------ [esx_addons]/esx_taxijob/locales/sr.lua | 11 +++++------ [esx_addons]/esx_taxijob/locales/zh-cn.lua | 11 +++++------ 13 files changed, 33 insertions(+), 54 deletions(-) diff --git a/[esx_addons]/esx_taxijob/client/main.lua b/[esx_addons]/esx_taxijob/client/main.lua index a558e524..c901e110 100644 --- a/[esx_addons]/esx_taxijob/client/main.lua +++ b/[esx_addons]/esx_taxijob/client/main.lua @@ -440,22 +440,13 @@ AddEventHandler('esx_taxijob:hasEnteredMarker', function(zone) CurrentActionMsg = TranslateCap('cloakroom_prompt') CurrentActionData = {} end + ESX.TextUI(CurrentActionMsg) end) AddEventHandler('esx_taxijob:hasExitedMarker', function(zone) ESX.CloseContext() CurrentAction = nil -end) - -RegisterNetEvent('esx_phone:loaded') -AddEventHandler('esx_phone:loaded', function(phoneNumber, contacts) - local specialContact = { - name = TranslateCap('phone_taxi'), - number = 'taxi', - base64Icon = 'data:image/png;base64,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' - } - - TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon) + ESX.HideUI() end) -- Create Blips @@ -697,7 +688,6 @@ CreateThread(function() local sleep = 1500 if CurrentAction and not ESX.PlayerData.dead then sleep = 0 - ESX.ShowHelpNotification(CurrentActionMsg) if IsControlJustReleased(0, 38) and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then if CurrentAction == 'taxi_actions_menu' then diff --git a/[esx_addons]/esx_taxijob/fxmanifest.lua b/[esx_addons]/esx_taxijob/fxmanifest.lua index 2449e42e..dd31755f 100644 --- a/[esx_addons]/esx_taxijob/fxmanifest.lua +++ b/[esx_addons]/esx_taxijob/fxmanifest.lua @@ -5,7 +5,7 @@ game 'gta5' description 'Allows players to be a taxi driver (Pickup and drop-off NPCs)' lua54 'yes' version '1.0' -legacyversion '1.13.3' +legacyversion '1.13.4' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_taxijob/locales/de.lua b/[esx_addons]/esx_taxijob/locales/de.lua index b258f55e..baa07936 100644 --- a/[esx_addons]/esx_taxijob/locales/de.lua +++ b/[esx_addons]/esx_taxijob/locales/de.lua @@ -49,12 +49,11 @@ Locales['de'] = { ['have_deposited'] = 'Du zahlst ein ~y~x%s~s~ ~b~%s~s~€', ['player_cannot_hold'] = 'Du hast ~r~nicht~s~ genügend ~y~freien platz~s~ in deinem Inventar!', ['blip_taxi'] = 'Taxi', - ['phone_taxi'] = 'Taxi', ['taxi'] = 'Taxi', ['taxi_stock'] = 'Lager', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "Betrag", + ['bill_amount'] = "Zu berechnender Betrag..", + ['deposit_amount'] = "Einzuzahlender Betrag..", + ['withdraw_amount'] = "Abzuhebender Betrag..", + ['confirm'] = "Bestätigen", } diff --git a/[esx_addons]/esx_taxijob/locales/en.lua b/[esx_addons]/esx_taxijob/locales/en.lua index bad2fa1d..5b5244d0 100644 --- a/[esx_addons]/esx_taxijob/locales/en.lua +++ b/[esx_addons]/esx_taxijob/locales/en.lua @@ -49,7 +49,6 @@ Locales['en'] = { ['have_deposited'] = 'you have deposited x%s %s', ['player_cannot_hold'] = 'you do ~r~not have enough free space in your inventory!', ['blip_taxi'] = 'downtown Cab Co.', - ['phone_taxi'] = 'downtown Cab Co.', ['taxi'] = 'taxi', ['taxi_stock'] = 'taxi Stock', ['amount'] = "Amount", diff --git a/[esx_addons]/esx_taxijob/locales/es.lua b/[esx_addons]/esx_taxijob/locales/es.lua index 41886e5d..ad5f115a 100644 --- a/[esx_addons]/esx_taxijob/locales/es.lua +++ b/[esx_addons]/esx_taxijob/locales/es.lua @@ -50,7 +50,6 @@ Locales['es'] = { ['have_deposited'] = 'Has depositado x%s %s', ['player_cannot_hold'] = '~r~No tienes suficiente espacio libre en tu inventario', ['blip_taxi'] = 'Downtown Cab Co.', - ['phone_taxi'] = 'Downtown Cab Co.', ['taxi'] = 'Taxi', ['taxi_stock'] = 'Inventario de Taxistas', ['amount'] = "Cantidad", diff --git a/[esx_addons]/esx_taxijob/locales/fi.lua b/[esx_addons]/esx_taxijob/locales/fi.lua index 22f722ba..8b147965 100644 --- a/[esx_addons]/esx_taxijob/locales/fi.lua +++ b/[esx_addons]/esx_taxijob/locales/fi.lua @@ -49,12 +49,11 @@ Locales['fi'] = { ['have_deposited'] = 'Sinä talletit x%s %s', ['player_cannot_hold'] = 'Sinulla ~r~ei ole enempää vapaata tilaa repussasi!', ['blip_taxi'] = 'Taksi', - ['phone_taxi'] = 'Taksi', ['taxi'] = 'Taksi', ['taxi_stock'] = 'Taksi varasto', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "Summa", + ['bill_amount'] = "Laskutettava summa..", + ['deposit_amount'] = "Talletettava summa..", + ['withdraw_amount'] = "Nostettava summa..", + ['confirm'] = "Vahvista", } diff --git a/[esx_addons]/esx_taxijob/locales/fr.lua b/[esx_addons]/esx_taxijob/locales/fr.lua index 5f4602ac..93689744 100644 --- a/[esx_addons]/esx_taxijob/locales/fr.lua +++ b/[esx_addons]/esx_taxijob/locales/fr.lua @@ -49,7 +49,6 @@ Locales['fr'] = { ['have_deposited'] = 'vous avez déposé x%s %s', ['player_cannot_hold'] = 'vous n\'avez pas assez de place dans votre inventaire!', ['blip_taxi'] = 'taxi', - ['phone_taxi'] = 'taxi', ['taxi'] = 'taxi', ['taxi_stock'] = 'taxi Stock', ['amount'] = "Montant", diff --git a/[esx_addons]/esx_taxijob/locales/hu.lua b/[esx_addons]/esx_taxijob/locales/hu.lua index 247683f9..60f3690e 100644 --- a/[esx_addons]/esx_taxijob/locales/hu.lua +++ b/[esx_addons]/esx_taxijob/locales/hu.lua @@ -47,7 +47,6 @@ Locales['hu'] = { ['have_deposited'] = 'betettél x%s %s', ['player_cannot_hold'] = '~r~nincs elég üres helyed az inventoryban!', ['blip_taxi'] = 'Taxitársaság', - ['phone_taxi'] = 'Taxi Hívás', ['taxi'] = 'taxi', ['taxi_stock'] = 'taxi tároló', ['vehicle_spawned'] = 'Sikeresen lehívtad: ~b~%s!', diff --git a/[esx_addons]/esx_taxijob/locales/it.lua b/[esx_addons]/esx_taxijob/locales/it.lua index 72107e18..d13d251d 100644 --- a/[esx_addons]/esx_taxijob/locales/it.lua +++ b/[esx_addons]/esx_taxijob/locales/it.lua @@ -52,7 +52,6 @@ Locales['it'] = { ['have_deposited'] = 'hai depositato x%s %s', ['player_cannot_hold'] = '~r~non hai abbastanza spazio libero nel tuo inventario!', ['blip_taxi'] = 'Downtown Cab Co.', - ['phone_taxi' ] = ' downtown Cab Co.', ['taxi' ] = 'taxi', ['taxi_stock'] = 'deposito dei taxi', ['menu_return'] = 'Indietro', diff --git a/[esx_addons]/esx_taxijob/locales/nl.lua b/[esx_addons]/esx_taxijob/locales/nl.lua index 0504b761..880f7f32 100644 --- a/[esx_addons]/esx_taxijob/locales/nl.lua +++ b/[esx_addons]/esx_taxijob/locales/nl.lua @@ -49,12 +49,11 @@ Locales['nl'] = { ['have_deposited'] = 'je hebt x%s %s weggelegd', ['player_cannot_hold'] = 'Je hebt ~r~niet genoeg vrije ruimte in je inventory!', ['blip_taxi'] = 'downtown Cab Co.', - ['phone_taxi'] = 'downtown Cab Co.', ['taxi'] = 'taxi', ['taxi_stock'] = 'taxi voorraad', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "Bedrag", + ['bill_amount'] = "Te factureren bedrag..", + ['deposit_amount'] = "Te storten bedrag..", + ['withdraw_amount'] = "Op te nemen bedrag..", + ['confirm'] = "Bevestigen", } diff --git a/[esx_addons]/esx_taxijob/locales/pl.lua b/[esx_addons]/esx_taxijob/locales/pl.lua index 35fb474d..877cfab3 100644 --- a/[esx_addons]/esx_taxijob/locales/pl.lua +++ b/[esx_addons]/esx_taxijob/locales/pl.lua @@ -49,12 +49,11 @@ Locales['pl'] = { ['have_deposited'] = 'deponujesz x%s %s', ['player_cannot_hold'] = '~r~Nie masz wystarczająco wolnego miejsca w swoim ekwipunku!', ['blip_taxi'] = 'taxi', - ['phone_taxi'] = 'taxi', ['taxi'] = 'taxi', ['taxi_stock'] = 'taxi Stock', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "Kwota", + ['bill_amount'] = "Kwota do zapłaty..", + ['deposit_amount'] = "Kwota do wpłaty..", + ['withdraw_amount'] = "Kwota do wypłaty..", + ['confirm'] = "Potwierdź", } diff --git a/[esx_addons]/esx_taxijob/locales/sr.lua b/[esx_addons]/esx_taxijob/locales/sr.lua index 0c8b3881..2ea53cc0 100644 --- a/[esx_addons]/esx_taxijob/locales/sr.lua +++ b/[esx_addons]/esx_taxijob/locales/sr.lua @@ -49,12 +49,11 @@ Locales['sr'] = { ['have_deposited'] = 'Ostavili ste x%s %s', ['player_cannot_hold'] = 'Nemate prostora u inventaru!', ['blip_taxi'] = 'downtown Cab Co.', - ['phone_taxi'] = 'downtown Cab Co.', ['taxi'] = 'Taxi', ['taxi_stock'] = 'Taxi Ostava', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "Iznos", + ['bill_amount'] = "Iznos za naplatu..", + ['deposit_amount'] = "Iznos za uplatu..", + ['withdraw_amount'] = "Iznos za isplatu..", + ['confirm'] = "Potvrdi", } diff --git a/[esx_addons]/esx_taxijob/locales/zh-cn.lua b/[esx_addons]/esx_taxijob/locales/zh-cn.lua index 77ece2f4..a789f02a 100644 --- a/[esx_addons]/esx_taxijob/locales/zh-cn.lua +++ b/[esx_addons]/esx_taxijob/locales/zh-cn.lua @@ -49,12 +49,11 @@ Locales['zh-cn'] = { ['have_deposited'] = '你存入了 x%s %s ', ['player_cannot_hold'] = '你的物品库没有足够的空间!', ['blip_taxi'] = '滴滴司机', - ['phone_taxi'] = '滴滴司机', ['taxi'] = '滴滴', ['taxi_stock'] = '滴滴物品', - ['amount'] = "Amount", --not translated - ['bill_amount'] = "Amount to bill..", --not translated - ['deposit_amount'] = "Amount to deposit..", --not translated - ['withdraw_amount'] = "Amount to withdraw..", --not translated - ['confirm'] = "Confirm", --not translated + ['amount'] = "金额", + ['bill_amount'] = "账单金额..", + ['deposit_amount'] = "存入金额..", + ['withdraw_amount'] = "取款金额..", + ['confirm'] = "确认", } From 638aa14bbf212201b80784e884ae7cdb37615bce Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Wed, 3 Sep 2025 18:19:36 +0100 Subject: [PATCH 08/25] refactor(esx_accessories/client/main): switch to ESX:TextUI --- [esx_addons]/esx_accessories/client/main.lua | 108 +++++-------------- [esx_addons]/esx_accessories/fxmanifest.lua | 2 +- [esx_addons]/esx_accessories/locales/cs.lua | 2 +- [esx_addons]/esx_accessories/locales/es.lua | 2 +- [esx_addons]/esx_accessories/locales/fi.lua | 2 +- [esx_addons]/esx_accessories/locales/hu.lua | 2 +- [esx_addons]/esx_accessories/locales/nl.lua | 2 +- [esx_addons]/esx_accessories/locales/pl.lua | 2 +- [esx_addons]/esx_accessories/locales/sl.lua | 2 +- 9 files changed, 36 insertions(+), 88 deletions(-) diff --git a/[esx_addons]/esx_accessories/client/main.lua b/[esx_addons]/esx_accessories/client/main.lua index 8d7a5d32..d2ed1156 100644 --- a/[esx_addons]/esx_accessories/client/main.lua +++ b/[esx_addons]/esx_accessories/client/main.lua @@ -1,6 +1,4 @@ -local HasAlreadyEnteredMarker = false -local LastZone, CurrentAction, CurrentActionMsg -local CurrentActionData = {} +local show_text = false function OpenAccessoryMenu() local elements = { @@ -104,33 +102,13 @@ function OpenShopMenu(accessory) ESX.CloseContext() end - CurrentAction = 'shop_menu' - CurrentActionMsg = TranslateCap('press_access') - CurrentActionData = {} end, function(menu) - CurrentAction = 'shop_menu' - CurrentActionMsg = TranslateCap('press_access') - CurrentActionData = {} end) end, function(data, menu) menu.close() - CurrentAction = 'shop_menu' - CurrentActionMsg = TranslateCap('press_access') - CurrentActionData = {} end, restrict) end -AddEventHandler('esx_accessories:hasEnteredMarker', function(zone) - CurrentAction = 'shop_menu' - CurrentActionMsg = TranslateCap('press_access') - CurrentActionData = { accessory = zone } -end) - -AddEventHandler('esx_accessories:hasExitedMarker', function(zone) - ESX.CloseContext() - CurrentAction = nil -end) - -- Create Blips -- CreateThread(function() for k,v in pairs(Config.ShopsBlips) do @@ -152,74 +130,44 @@ CreateThread(function() end end) -local nearMarker = false --- Display markers CreateThread(function() while true do - local sleep = 1500 - local coords = GetEntityCoords(PlayerPedId()) + local interval = true + local playerCoords = GetEntityCoords(PlayerPedId()) + local isInMarker = false + for k,v in pairs(Config.Zones) do for i = 1, #v.Pos, 1 do - if(Config.Type ~= -1 and #(coords - v.Pos[i]) < Config.DrawDistance) then + local distance = #(playerCoords - v.Pos[i]) + + if Config.Type ~= -1 and distance < Config.DrawDistance then DrawMarker(Config.Type, v.Pos[i], 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.Size.x, Config.Size.y, Config.Size.z, Config.Color.r, Config.Color.g, Config.Color.b, 255, true, false, 2, true, false, false, false) - sleep = 0 - break + interval = false end - end - end - if sleep == 0 then nearMarker = true else nearMarker = false end - Wait(sleep) - end -end) - -CreateThread(function() - while true do - local sleep = 1500 - if nearMarker then - sleep = 0 - local coords = GetEntityCoords(PlayerPedId()) - local isInMarker = false - local currentZone = nil - for k,v in pairs(Config.Zones) do - for i = 1, #v.Pos, 1 do - if #(coords - v.Pos[i]) < Config.Size.x then - isInMarker = true - currentZone = k - break + + if distance < Config.Size.x then + isInMarker = true + interval = false + if IsControlJustReleased(0, 38) then + OpenShopMenu(k) end end end - - if (isInMarker and not HasAlreadyEnteredMarker) or (isInMarker and LastZone ~= currentZone) then - HasAlreadyEnteredMarker = true - LastZone = currentZone - TriggerEvent('esx_accessories:hasEnteredMarker', currentZone) - end - - if not isInMarker and HasAlreadyEnteredMarker then - HasAlreadyEnteredMarker = false - TriggerEvent('esx_accessories:hasExitedMarker', LastZone) - end end - Wait(sleep) - end -end) - --- Key controls -CreateThread(function() - while true do - local Sleep = 1500 - if CurrentAction then - Sleep = 0 - ESX.ShowHelpNotification(CurrentActionMsg) - - if IsControlJustReleased(0, 38) and CurrentActionData.accessory then - OpenShopMenu(CurrentActionData.accessory) - CurrentAction = nil - end + if isInMarker and not show_text then + ESX.TextUI(TranslateCap('press_access')) + show_text = true + elseif not isInMarker and show_text then + ESX.HideUI() + show_text = false + end + + if interval then + Wait(500) + else + Wait(0) end - Wait(Sleep) end end) @@ -229,4 +177,4 @@ if Config.EnableControls then OpenAccessoryMenu() end end) -end +end \ No newline at end of file diff --git a/[esx_addons]/esx_accessories/fxmanifest.lua b/[esx_addons]/esx_accessories/fxmanifest.lua index 5cab8c1d..52579f75 100644 --- a/[esx_addons]/esx_accessories/fxmanifest.lua +++ b/[esx_addons]/esx_accessories/fxmanifest.lua @@ -6,7 +6,7 @@ description 'Provides a way for players to customise their appearence with acces lua54 'yes' version '1.1' -legacyversion '1.13.3' +legacyversion '1.13.4' shared_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_accessories/locales/cs.lua b/[esx_addons]/esx_accessories/locales/cs.lua index 7145d462..552ef4ca 100644 --- a/[esx_addons]/esx_accessories/locales/cs.lua +++ b/[esx_addons]/esx_accessories/locales/cs.lua @@ -16,5 +16,5 @@ Locales ['cs'] = { ['no_helmet'] = 'nemáte helmu', ['no_mask'] = 'nemáte masku', ['you_paid'] = 'zaplatili jste $%s', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Otevřít nabídku doplňků', } diff --git a/[esx_addons]/esx_accessories/locales/es.lua b/[esx_addons]/esx_accessories/locales/es.lua index d7e1a9f8..2455bbd7 100644 --- a/[esx_addons]/esx_accessories/locales/es.lua +++ b/[esx_addons]/esx_accessories/locales/es.lua @@ -16,5 +16,5 @@ Locales ['es'] = { ['no_helmet'] = 'No tienes ningún casco', ['no_mask'] = 'No tienes ninguna máscara', ['you_paid'] = 'Pagaste %s$', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Abrir menú de accesorios', } diff --git a/[esx_addons]/esx_accessories/locales/fi.lua b/[esx_addons]/esx_accessories/locales/fi.lua index dd47eb1e..d1143eff 100644 --- a/[esx_addons]/esx_accessories/locales/fi.lua +++ b/[esx_addons]/esx_accessories/locales/fi.lua @@ -16,5 +16,5 @@ Locales ['fi'] = { ['no_helmet'] = 'sinulla ei ole kypäriä', ['no_mask'] = 'sinulla ei ole maskeja', ['you_paid'] = 'sinä maksoit $%s', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Avaa asustevalikko', } diff --git a/[esx_addons]/esx_accessories/locales/hu.lua b/[esx_addons]/esx_accessories/locales/hu.lua index 051324e9..4cd9dfae 100644 --- a/[esx_addons]/esx_accessories/locales/hu.lua +++ b/[esx_addons]/esx_accessories/locales/hu.lua @@ -16,5 +16,5 @@ Locales ['hu'] = { ['no_helmet'] = 'Nincsen sapkád', ['no_mask'] = 'Nincsen maszkod', ['you_paid'] = 'Fizettél $%s', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Kiegészítő menü megnyitása', } diff --git a/[esx_addons]/esx_accessories/locales/nl.lua b/[esx_addons]/esx_accessories/locales/nl.lua index 16d0a640..ec23f927 100644 --- a/[esx_addons]/esx_accessories/locales/nl.lua +++ b/[esx_addons]/esx_accessories/locales/nl.lua @@ -16,5 +16,5 @@ Locales ['nl'] = { ['no_helmet'] = 'je hebt geen helm', ['no_mask'] = 'je hebt geen masker', ['you_paid'] = 'je betaalde €%s', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Accessoiremenu openen', } diff --git a/[esx_addons]/esx_accessories/locales/pl.lua b/[esx_addons]/esx_accessories/locales/pl.lua index 38a910c4..ebd1fa0d 100644 --- a/[esx_addons]/esx_accessories/locales/pl.lua +++ b/[esx_addons]/esx_accessories/locales/pl.lua @@ -16,5 +16,5 @@ Locales ['pl'] = { ['no_helmet'] = 'nie posiadasz nakrycia głowy', ['no_mask'] = 'nie posiadasz maski', ['you_paid'] = 'płacisz %s $', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Otwórz menu akcesoriów', } diff --git a/[esx_addons]/esx_accessories/locales/sl.lua b/[esx_addons]/esx_accessories/locales/sl.lua index a21ae745..67684534 100644 --- a/[esx_addons]/esx_accessories/locales/sl.lua +++ b/[esx_addons]/esx_accessories/locales/sl.lua @@ -16,5 +16,5 @@ Locales ['sl'] = { ['no_helmet'] = 'Vi nimate kape/klobuka', ['no_mask'] = 'Vi nimate maske!', ['you_paid'] = 'Vi ste plačali $%s', - ['keymap'] = 'Open Accessory Menu', --not translated + ['keymap'] = 'Odpri meni dodatkov' } From cf8a18f0530c55801aec516404e0d4d20fec6098 Mon Sep 17 00:00:00 2001 From: Rafael Antunes <147253092+Fellow1990@users.noreply.github.com> Date: Wed, 3 Sep 2025 22:14:55 +0100 Subject: [PATCH 09/25] refactor(esx_taxijob): switch to ESX:TextUI --- [esx_addons]/esx_taxijob/client/main.lua | 123 ++++++++------------- [esx_addons]/esx_taxijob/locales/de.lua | 3 +- [esx_addons]/esx_taxijob/locales/en.lua | 3 +- [esx_addons]/esx_taxijob/locales/es.lua | 4 +- [esx_addons]/esx_taxijob/locales/fi.lua | 3 +- [esx_addons]/esx_taxijob/locales/fr.lua | 3 +- [esx_addons]/esx_taxijob/locales/hu.lua | 4 +- [esx_addons]/esx_taxijob/locales/it.lua | 3 +- [esx_addons]/esx_taxijob/locales/nl.lua | 3 +- [esx_addons]/esx_taxijob/locales/pl.lua | 3 +- [esx_addons]/esx_taxijob/locales/sr.lua | 3 +- [esx_addons]/esx_taxijob/locales/zh-cn.lua | 3 +- [esx_addons]/esx_taxijob/server/main.lua | 1 - 13 files changed, 73 insertions(+), 86 deletions(-) diff --git a/[esx_addons]/esx_taxijob/client/main.lua b/[esx_addons]/esx_taxijob/client/main.lua index c901e110..23a0ccb4 100644 --- a/[esx_addons]/esx_taxijob/client/main.lua +++ b/[esx_addons]/esx_taxijob/client/main.lua @@ -1,6 +1,6 @@ -local HasAlreadyEnteredMarker, OnJob, IsNearCustomer, CustomerIsEnteringVehicle, CustomerEnteredVehicle, +local show_text, OnJob, IsNearCustomer, CustomerIsEnteringVehicle, CustomerEnteredVehicle, CurrentActionData = false, false, false, false, false, {} -local CurrentCustomer, CurrentCustomerBlip, DestinationBlip, targetCoords, LastZone, CurrentAction, CurrentActionMsg, lastSelectedNPC +local CurrentCustomer, CurrentCustomerBlip, DestinationBlip, targetCoords, CurrentAction, CurrentActionMsg, lastSelectedNPC RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(xPlayer) @@ -414,40 +414,7 @@ function OpenPutStocksMenu() end) end -AddEventHandler('esx_taxijob:hasEnteredMarker', function(zone) - if zone == 'VehicleSpawner' then - CurrentAction = 'vehicle_spawner' - CurrentActionMsg = TranslateCap('spawner_prompt') - CurrentActionData = {} - elseif zone == 'VehicleDeleter' then - local playerPed = PlayerPedId() - local vehicle = GetVehiclePedIsIn(playerPed, false) - - if IsPedInAnyVehicle(playerPed, false) and GetPedInVehicleSeat(vehicle, -1) == playerPed then - CurrentAction = 'delete_vehicle' - CurrentActionMsg = TranslateCap('store_veh') - CurrentActionData = { - vehicle = vehicle - } - end - elseif zone == 'TaxiActions' then - CurrentAction = 'taxi_actions_menu' - CurrentActionMsg = TranslateCap('press_to_open') - CurrentActionData = {} - elseif zone == 'Cloakroom' then - CurrentAction = 'cloakroom' - CurrentActionMsg = TranslateCap('cloakroom_prompt') - CurrentActionData = {} - end - ESX.TextUI(CurrentActionMsg) -end) - -AddEventHandler('esx_taxijob:hasExitedMarker', function(zone) - ESX.CloseContext() - CurrentAction = nil - ESX.HideUI() -end) -- Create Blips CreateThread(function() @@ -465,18 +432,16 @@ CreateThread(function() EndTextCommandSetBlipName(blip) end) --- Enter / Exit marker events, and draw markers CreateThread(function() while true do local sleep = 1500 + local playerCoords = GetEntityCoords(PlayerPedId()) + local isInMarker = false + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then - - local coords = GetEntityCoords(PlayerPedId()) - local isInMarker, currentZone = false - for k, v in pairs(Config.Zones) do local zonePos = vector3(v.Pos.x, v.Pos.y, v.Pos.z) - local distance = #(coords - zonePos) + local distance = #(playerCoords - zonePos) if v.Type ~= -1 and distance < Config.DrawDistance then sleep = 0 @@ -484,21 +449,54 @@ CreateThread(function() v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, false, 2, v.Rotate, nil, nil, false) end - if distance < v.Size.x then - isInMarker, currentZone = true, k + if distance < v.Size.x and v.Type ~= -1 then + if k == 'VehicleDeleter' then + local playerPed = PlayerPedId() + local vehicle = GetVehiclePedIsIn(playerPed, false) + + if IsPedInAnyVehicle(playerPed, false) and GetPedInVehicleSeat(vehicle, -1) == playerPed then + isInMarker = true + CurrentAction = 'delete_vehicle' + CurrentActionMsg = TranslateCap('store_veh') + CurrentActionData = { + vehicle = vehicle + } + end + else + isInMarker = true + CurrentAction = k:lower() + CurrentActionMsg = TranslateCap(k:lower() .. '_prompt') + CurrentActionData = {} + end end end + end + + if isInMarker and not show_text then + show_text = true + ESX.TextUI(CurrentActionMsg) + elseif not isInMarker and show_text then + show_text = false + ESX.HideUI() + CurrentAction = nil + end + + if CurrentAction and not ESX.PlayerData.dead then + if IsControlJustReleased(0, 38) and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then + if CurrentAction == 'taxiactions' then + OpenTaxiActionsMenu() + elseif CurrentAction == 'cloakroom' then + OpenCloakroom() + elseif CurrentAction == 'vehiclespawner' then + OpenVehicleSpawnerMenu() + elseif CurrentAction == 'delete_vehicle' then + DeleteJobVehicle() + end - if (isInMarker and not HasAlreadyEnteredMarker) or (isInMarker and LastZone ~= currentZone) then - HasAlreadyEnteredMarker, LastZone = true, currentZone - TriggerEvent('esx_taxijob:hasEnteredMarker', currentZone) - end - - if not isInMarker and HasAlreadyEnteredMarker then - HasAlreadyEnteredMarker = false - TriggerEvent('esx_taxijob:hasExitedMarker', LastZone) + CurrentAction = nil end end + Wait(sleep) end end) @@ -682,30 +680,7 @@ CreateThread(function() end end) --- Key Controls -CreateThread(function() - while true do - local sleep = 1500 - if CurrentAction and not ESX.PlayerData.dead then - sleep = 0 - - if IsControlJustReleased(0, 38) and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then - if CurrentAction == 'taxi_actions_menu' then - OpenTaxiActionsMenu() - elseif CurrentAction == 'cloakroom' then - OpenCloakroom() - elseif CurrentAction == 'vehicle_spawner' then - OpenVehicleSpawnerMenu() - elseif CurrentAction == 'delete_vehicle' then - DeleteJobVehicle() - end - CurrentAction = nil - end - end - Wait(sleep) - end -end) RegisterCommand('taximenu', function() if not ESX.PlayerData.dead and Config.EnablePlayerManagement and ESX.PlayerData.job and ESX.PlayerData.job.name == diff --git a/[esx_addons]/esx_taxijob/locales/de.lua b/[esx_addons]/esx_taxijob/locales/de.lua index baa07936..675a232b 100644 --- a/[esx_addons]/esx_taxijob/locales/de.lua +++ b/[esx_addons]/esx_taxijob/locales/de.lua @@ -7,6 +7,7 @@ Locales['de'] = { -- garage ['spawner_prompt'] = 'Drücke ~INPUT_CONTEXT~ um die ~y~garage~s~ zu öffnen!.', + ['vehiclespawner_prompt'] = 'Drücke ~INPUT_CONTEXT~ um die ~y~garage~s~ zu öffnen!.', ["vehicle_spawned"] = "%s erfolgreich geparkt !", ['store_veh'] = 'Drücke ~INPUT_CONTEXT~ um das Fahrzeug zu parken', ['spawn_veh'] = 'Fahrzeug ausparken', @@ -19,6 +20,7 @@ Locales['de'] = { ['full_service'] = 'Voller Service: ', ['amount_invalid'] = 'Betrag ungültig', ['press_to_open'] = 'Drücke ~INPUT_CONTEXT~ um das Menü zu öffnen', + ['taxiactions_prompt'] = 'Drücke ~INPUT_CONTEXT~ um das Menü zu öffnen', ['billing'] = 'Rechnung', ['billing_sent'] = 'Die rechnung wurde registriert!!', ['invoice_amount'] = 'Rechnugsbetrag', @@ -44,7 +46,6 @@ Locales['de'] = { ['quantity'] = 'Anzahl', ['quantity_invalid'] = 'Ungültige Anzahl!!', ['inventory'] = 'Inventar', - ['taxi_client'] = 'Taxi Client', ['have_withdrawn'] = 'Du zahlst aus ~y~x%s~s~ ~b~%s~s~€', ['have_deposited'] = 'Du zahlst ein ~y~x%s~s~ ~b~%s~s~€', ['player_cannot_hold'] = 'Du hast ~r~nicht~s~ genügend ~y~freien platz~s~ in deinem Inventar!', diff --git a/[esx_addons]/esx_taxijob/locales/en.lua b/[esx_addons]/esx_taxijob/locales/en.lua index 5b5244d0..d63259c8 100644 --- a/[esx_addons]/esx_taxijob/locales/en.lua +++ b/[esx_addons]/esx_taxijob/locales/en.lua @@ -7,6 +7,7 @@ Locales['en'] = { -- garage ['spawner_prompt'] = 'press [E] to access the Garage.', + ['vehiclespawner_prompt'] = 'press [E] to access the Garage.', ["vehicle_spawned"] = "Successfully Spawned A ~b~%s!", ['store_veh'] = 'press [E] to store the vehicle', ['spawn_veh'] = 'spawn vehicle', @@ -19,6 +20,7 @@ Locales['en'] = { ['full_service'] = 'full service: ', ['amount_invalid'] = 'amount invalid', ['press_to_open'] = 'press [E] to access the menu', + ['taxiactions_prompt'] = 'press [E] to access the menu', ['billing'] = 'billing', ['billing_sent'] = 'the bill has been registered!', ['invoice_amount'] = 'invoice amount', @@ -44,7 +46,6 @@ Locales['en'] = { ['quantity'] = 'quantity', ['quantity_invalid'] = 'that is an invalid quantity!', ['inventory'] = 'inventory', - ['taxi_client'] = 'taxi Client', ['have_withdrawn'] = 'you have withdrawn x%s %s', ['have_deposited'] = 'you have deposited x%s %s', ['player_cannot_hold'] = 'you do ~r~not have enough free space in your inventory!', diff --git a/[esx_addons]/esx_taxijob/locales/es.lua b/[esx_addons]/esx_taxijob/locales/es.lua index ad5f115a..a1a62ede 100644 --- a/[esx_addons]/esx_taxijob/locales/es.lua +++ b/[esx_addons]/esx_taxijob/locales/es.lua @@ -7,6 +7,7 @@ Locales['es'] = { -- Garaje ['spawner_prompt'] = 'Presiona [E] para acceder al Garaje.', + ['vehiclespawner_prompt'] = 'Presiona [E] para acceder al Garaje.', ['store_veh'] = 'Presiona [E] para almacenar el vehículo', ['spawn_veh'] = 'Vehículo de generación', ['spawnpoint_blocked'] = '¡Hay un vehículo bloqueando el punto de generación!', @@ -20,6 +21,7 @@ Locales['es'] = { ['full_service'] = 'Servicio completo: ', ['amount_invalid'] = 'Cantidad inválida', ['press_to_open'] = 'Presiona [E] para acceder al menú', + ['taxiactions_prompt'] = 'Presiona [E] para acceder al menú', ['billing'] = 'Facturación', ['billing_sent'] = 'La factura ha sido registrada', ['invoice_amount'] = 'Factura inválida', @@ -45,7 +47,6 @@ Locales['es'] = { ['quantity'] = 'Cantidad', ['quantity_invalid'] = 'Cantidad inválida', ['inventory'] = 'Inventario', - ['taxi_client'] = 'Cliente', ['have_withdrawn'] = 'Has retirado x%s %s', ['have_deposited'] = 'Has depositado x%s %s', ['player_cannot_hold'] = '~r~No tienes suficiente espacio libre en tu inventario', @@ -53,6 +54,7 @@ Locales['es'] = { ['taxi'] = 'Taxi', ['taxi_stock'] = 'Inventario de Taxistas', ['amount'] = "Cantidad", + ['bill_amount'] = "Cantidad a facturar...", ['deposit_amount'] = "Cantidad a depositar...", ['withdraw_amount'] = "Cantidad a retirar...", ['confirm'] = "Confirmar", diff --git a/[esx_addons]/esx_taxijob/locales/fi.lua b/[esx_addons]/esx_taxijob/locales/fi.lua index 8b147965..6fdbee67 100644 --- a/[esx_addons]/esx_taxijob/locales/fi.lua +++ b/[esx_addons]/esx_taxijob/locales/fi.lua @@ -7,6 +7,7 @@ Locales['fi'] = { -- garage ['spawner_prompt'] = 'Paina [E] avataksesi talli.', + ['vehiclespawner_prompt'] = 'Paina [E] avataksesi talli.', ['store_veh'] = 'Paina [E] laittaaksesi ajoneuvo talliin', ['spawn_veh'] = 'Luo ajoneuvo', ['spawnpoint_blocked'] = 'Jokin ajoneuvo estää ajoneuvon luomisen!', @@ -19,6 +20,7 @@ Locales['fi'] = { ['full_service'] = 'Täysi palvelu: ', ['amount_invalid'] = 'Virheellinen summa', ['press_to_open'] = 'Paina [E] avataksesi valikko', + ['taxiactions_prompt'] = 'Paina [E] avataksesi valikko', ['billing'] = 'Laskutus', ['billing_sent'] = 'Lasku on rekisteröity!', ['invoice_amount'] = 'Laskun määrä', @@ -44,7 +46,6 @@ Locales['fi'] = { ['quantity'] = 'Määrä', ['quantity_invalid'] = 'Virheellinen määrä', ['inventory'] = 'Reppu', - ['taxi_client'] = 'Taksi asiakas', ['have_withdrawn'] = 'Sinä nostit x%s %s', ['have_deposited'] = 'Sinä talletit x%s %s', ['player_cannot_hold'] = 'Sinulla ~r~ei ole enempää vapaata tilaa repussasi!', diff --git a/[esx_addons]/esx_taxijob/locales/fr.lua b/[esx_addons]/esx_taxijob/locales/fr.lua index 93689744..9fad8d9d 100644 --- a/[esx_addons]/esx_taxijob/locales/fr.lua +++ b/[esx_addons]/esx_taxijob/locales/fr.lua @@ -7,6 +7,7 @@ Locales['fr'] = { -- garage ['spawner_prompt'] = 'appuyez sur [E] pour ouvrir le garage.', + ['vehiclespawner_prompt'] = 'appuyez sur [E] pour ouvrir le garage.', ['store_veh'] = 'appuyez sur [E] pour ranger le véhicule', ['spawn_veh'] = 'sortir véhicule', ['spawnpoint_blocked'] = 'un véhicule bloque la sortie!!', @@ -19,6 +20,7 @@ Locales['fr'] = { ['full_service'] = 'service complet : ', ['amount_invalid'] = 'montant invalide', ['press_to_open'] = 'appuyez sur [E] pour accéder au menu', + ['taxiactions_prompt'] = 'appuyez sur [E] pour accéder au menu', ['billing'] = 'facuration', ['billing_sent'] = 'la facture a bien été enregistrée!', ['invoice_amount'] = 'montant de la facture', @@ -44,7 +46,6 @@ Locales['fr'] = { ['quantity'] = 'Quantité', ['quantity_invalid'] = 'Quantité invalide', ['inventory'] = 'Inventaire', - ['taxi_client'] = 'client Taxi', ['have_withdrawn'] = 'vous avez pris x%s %s', ['have_deposited'] = 'vous avez déposé x%s %s', ['player_cannot_hold'] = 'vous n\'avez pas assez de place dans votre inventaire!', diff --git a/[esx_addons]/esx_taxijob/locales/hu.lua b/[esx_addons]/esx_taxijob/locales/hu.lua index 60f3690e..d87232d9 100644 --- a/[esx_addons]/esx_taxijob/locales/hu.lua +++ b/[esx_addons]/esx_taxijob/locales/hu.lua @@ -7,6 +7,7 @@ Locales['hu'] = { -- garage ['spawner_prompt'] = 'nyomd meg a [E] gombot a garázshoz.', + ['vehiclespawner_prompt'] = 'nyomd meg a [E] gombot a garázshoz.', ['store_veh'] = 'nyomd meg a [E] gombot az autó tárolásához', ['spawn_veh'] = 'autó lehívás', ['spawnpoint_blocked'] = 'egy autó blokkolja a lehívási helyet!', @@ -18,6 +19,7 @@ Locales['hu'] = { ['full_service'] = 'teljes szolgálat: ', ['amount_invalid'] = 'érvénytelen összeg', ['press_to_open'] = 'nyomj [E] gombot a menühöz', + ['taxiactions_prompt'] = 'nyomj [E] gombot a menühöz', ['billing'] = 'számlázás', ['billing_sent'] = 'a számlát regisztrálták!', ['invoice_amount'] = 'számla összeg', @@ -33,6 +35,7 @@ Locales['hu'] = { ['return_to_veh'] = 'ülj vissza a kocsiba hogy folytatni tudd a munkát', ['must_in_taxi'] = 'a munka indításához egy taxit kell hogy vezess', ['must_in_vehicle'] = 'a munka indításához egy járművet kell hogy vezess', + ['not_in_taxi'] = 'Elhagytad a taxit küldetés közben!', ['have_earned'] = 'kerestél: $%s', ['comp_earned'] = 'a vállalkozásod keresett: $%s - te kerestél: $%s', ['deposit_stock'] = 'készlet betétele', @@ -42,7 +45,6 @@ Locales['hu'] = { ['quantity'] = 'Mennyiség', ['quantity_invalid'] = 'érvénytelen összeg!', ['inventory'] = 'leltár', - ['taxi_client'] = 'taxi ügyfél', ['have_withdrawn'] = 'kivettél x%s %s', ['have_deposited'] = 'betettél x%s %s', ['player_cannot_hold'] = '~r~nincs elég üres helyed az inventoryban!', diff --git a/[esx_addons]/esx_taxijob/locales/it.lua b/[esx_addons]/esx_taxijob/locales/it.lua index d13d251d..ac3c06c8 100644 --- a/[esx_addons]/esx_taxijob/locales/it.lua +++ b/[esx_addons]/esx_taxijob/locales/it.lua @@ -7,6 +7,7 @@ Locales['it'] = { -- garage ['spawner_prompt'] = 'premi [E] per accedere al garage.', + ['vehiclespawner_prompt'] = 'premi [E] per accedere al garage.', ["vehicle_spawned"] = "generato con successo un ~b~%s!", ['store_veh'] = 'premi [E] per depositare il veicolo', ['spawn_veh'] = 'genera veicolo', @@ -20,6 +21,7 @@ Locales['it'] = { ['full_service'] = 'servizio completo: ', ['amount_invalid'] = 'importo non valido', ['press_to_open'] = 'premi [E] per accedere al menu', + ['taxiactions_prompt'] = 'premi [E] per accedere al menu', ['billing'] = 'fattura', ['billing_sent'] = 'la fattura è stata registrata!', ['invoice_amount'] = 'importo fattura', @@ -47,7 +49,6 @@ Locales['it'] = { ['quantity' ] = 'quantità', ['quantity_invalid'] = 'questa quantità non è valida!', ['inventory'] = 'inventario', - ['taxi_client'] = 'cliente taxi', ['have_withdrawn'] = 'hai prelevato x%s %s', ['have_deposited'] = 'hai depositato x%s %s', ['player_cannot_hold'] = '~r~non hai abbastanza spazio libero nel tuo inventario!', diff --git a/[esx_addons]/esx_taxijob/locales/nl.lua b/[esx_addons]/esx_taxijob/locales/nl.lua index 880f7f32..37de87dc 100644 --- a/[esx_addons]/esx_taxijob/locales/nl.lua +++ b/[esx_addons]/esx_taxijob/locales/nl.lua @@ -7,6 +7,7 @@ Locales['nl'] = { -- garage ['spawner_prompt'] = 'Druk op [E] om de Garage te gebruiken.', + ['vehiclespawner_prompt'] = 'Druk op [E] om de Garage te gebruiken.', ["vehicle_spawned"] = "Successfully Spawned A ~b~%s!", ['store_veh'] = 'Druk op [E] om het voertuig weg te zetten.', ['spawn_veh'] = 'pak voertuig', @@ -19,6 +20,7 @@ Locales['nl'] = { ['full_service'] = 'volledige dienst: ', ['amount_invalid'] = 'ongeldig bedrag', ['press_to_open'] = 'Druk op [E] om het menu te gebruiken.', + ['taxiactions_prompt'] = 'Druk op [E] om het menu te gebruiken.', ['billing'] = 'facturering', ['billing_sent'] = 'de factuur is geregistreerd!', ['invoice_amount'] = 'factuurbedrag', @@ -44,7 +46,6 @@ Locales['nl'] = { ['quantity'] = 'hoeveelheid', ['quantity_invalid'] = 'dat is een ongeldige hoeveelheid !', ['inventory'] = 'inventory', - ['taxi_client'] = 'taxi klant', ['have_withdrawn'] = 'je hebt x%s %s gepakt', ['have_deposited'] = 'je hebt x%s %s weggelegd', ['player_cannot_hold'] = 'Je hebt ~r~niet genoeg vrije ruimte in je inventory!', diff --git a/[esx_addons]/esx_taxijob/locales/pl.lua b/[esx_addons]/esx_taxijob/locales/pl.lua index 877cfab3..d1d8a541 100644 --- a/[esx_addons]/esx_taxijob/locales/pl.lua +++ b/[esx_addons]/esx_taxijob/locales/pl.lua @@ -7,6 +7,7 @@ Locales['pl'] = { -- garage ['spawner_prompt'] = 'naciśnij [E] aby otworzyć garaż.', + ['vehiclespawner_prompt'] = 'naciśnij [E] aby otworzyć garaż.', ['store_veh'] = 'naciśnij [E] aby zdać pojazd', ['spawn_veh'] = 'sprowadź pojazd', ['spawnpoint_blocked'] = 'jakiś pojazd blokuje wyjazd z garażu!', @@ -19,6 +20,7 @@ Locales['pl'] = { ['full_service'] = 'pełny serwis: ', ['amount_invalid'] = 'wartość nieprawidłowa', ['press_to_open'] = 'naciśnij [E] aby wejść do menu', + ['taxiactions_prompt'] = 'naciśnij [E] aby wejść do menu', ['billing'] = 'rachunek', ['billing_sent'] = 'rachunek został wystawiony!', ['invoice_amount'] = 'wartość należności', @@ -44,7 +46,6 @@ Locales['pl'] = { ['quantity'] = 'ilość', ['quantity_invalid'] = 'nieprawidłowa ilość', ['inventory'] = 'ekwipunek', - ['taxi_client'] = 'klient taksówki', ['have_withdrawn'] = 'wyciągasz x%s %s', ['have_deposited'] = 'deponujesz x%s %s', ['player_cannot_hold'] = '~r~Nie masz wystarczająco wolnego miejsca w swoim ekwipunku!', diff --git a/[esx_addons]/esx_taxijob/locales/sr.lua b/[esx_addons]/esx_taxijob/locales/sr.lua index 2ea53cc0..6c2b0d58 100644 --- a/[esx_addons]/esx_taxijob/locales/sr.lua +++ b/[esx_addons]/esx_taxijob/locales/sr.lua @@ -7,6 +7,7 @@ Locales['sr'] = { -- garage ['spawner_prompt'] = 'Pritisni [E] da pristupiš garaži.', + ['vehiclespawner_prompt'] = 'Pritisni [E] da pristupiš garaži.', ["vehicle_spawned"] = "Uspešno uzeto ~b~%s vozilo!", ['store_veh'] = 'Pritisni [E] da parkiraš vozilo', ['spawn_veh'] = 'Uzmi Vozilo', @@ -19,6 +20,7 @@ Locales['sr'] = { ['full_service'] = 'Posao: ', ['amount_invalid'] = 'Nevažeći Iznos', ['press_to_open'] = 'Pritisni [E] da pristupiš meniju', + ['taxiactions_prompt'] = 'Pritisni [E] da pristupiš meniju', ['billing'] = 'Računi', ['billing_sent'] = 'Račun je registrovan!', ['invoice_amount'] = 'Iznos računa', @@ -44,7 +46,6 @@ Locales['sr'] = { ['quantity'] = 'Količina', ['quantity_invalid'] = 'Ta količina je nevažeća!', ['inventory'] = 'Inventar', - ['taxi_client'] = 'Taxi Klijent', ['have_withdrawn'] = 'Podigli ste x%s %s', ['have_deposited'] = 'Ostavili ste x%s %s', ['player_cannot_hold'] = 'Nemate prostora u inventaru!', diff --git a/[esx_addons]/esx_taxijob/locales/zh-cn.lua b/[esx_addons]/esx_taxijob/locales/zh-cn.lua index a789f02a..523818aa 100644 --- a/[esx_addons]/esx_taxijob/locales/zh-cn.lua +++ b/[esx_addons]/esx_taxijob/locales/zh-cn.lua @@ -7,6 +7,7 @@ Locales['zh-cn'] = { -- garage ['spawner_prompt'] = '键下 [E] 访问车库', + ['vehiclespawner_prompt'] = '键下 [E] 访问车库', ["vehicle_spawned"] = "%s 车辆已放行!", ['store_veh'] = '键下 [E] 储存车辆', ['spawn_veh'] = '生成载具', @@ -19,6 +20,7 @@ Locales['zh-cn'] = { ['full_service'] = '公共服务:', ['amount_invalid'] = '无效的金额输入!请重新检查', ['press_to_open'] = '键下 [E] 打开菜单', + ['taxiactions_prompt'] = '键下 [E] 打开菜单', ['billing'] = '开具帐单', ['billing_sent'] = '当前帐单已成功发送至目标市民!', ['invoice_amount'] = '帐单金额', @@ -44,7 +46,6 @@ Locales['zh-cn'] = { ['quantity'] = '数量', ['quantity_invalid'] = '数量无效', ['inventory'] = '存储柜', - ['taxi_client'] = '计程车客户', ['have_withdrawn'] = '你取出了 x%s %s ', ['have_deposited'] = '你存入了 x%s %s ', ['player_cannot_hold'] = '你的物品库没有足够的空间!', diff --git a/[esx_addons]/esx_taxijob/server/main.lua b/[esx_addons]/esx_taxijob/server/main.lua index ad6b1774..951f57aa 100644 --- a/[esx_addons]/esx_taxijob/server/main.lua +++ b/[esx_addons]/esx_taxijob/server/main.lua @@ -4,7 +4,6 @@ if Config.MaxInService ~= -1 then TriggerEvent('esx_service:activateService', 'taxi', Config.MaxInService) end -TriggerEvent('esx_phone:registerNumber', 'taxi', TranslateCap('taxi_client'), true, true) TriggerEvent('esx_society:registerSociety', 'taxi', 'Taxi', 'society_taxi', 'society_taxi', 'society_taxi', { type = 'public' }) From 3798f9005f9eb92e24c28acba248057bc7e0de98 Mon Sep 17 00:00:00 2001 From: Mirow Date: Thu, 4 Sep 2025 20:05:56 +0200 Subject: [PATCH 10/25] refactor(addonaccount): add type annotations Added type annotations and refactored some functions. --- .../server/classes/addonaccount.lua | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua index f5fb4a62..fc6ae8f3 100644 --- a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua +++ b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua @@ -1,35 +1,54 @@ +---@class AddonAccount +---@field name string +---@field owner? string +---@field money number +---@field addMoney fun(amount: number) +---@field removeMoney fun(amount: number) +---@field setMoney fun(amount: number) +---@field save function + +---@param name string +---@param owner? string +---@param money number +---@return AddonAccount function CreateAddonAccount(name, owner, money) - local self = {} + ---@diagnostic disable-next-line: missing-fields + local self = {} --[[@type AddonAccount]] - self.name = name + self.name = name self.owner = owner self.money = money function self.addMoney(amount) - self.money = self.money + amount + self.money += amount self.save() + TriggerEvent('esx_addonaccount:addMoney', self.name, amount) end function self.removeMoney(amount) - self.money = self.money - amount + self.money -= amount self.save() + TriggerEvent('esx_addonaccount:removeMoney', self.name, amount) end function self.setMoney(amount) self.money = amount self.save() + TriggerEvent('esx_addonaccount:setMoney', self.name, amount) end function self.save() - if self.owner == nil then - MySQL.update('UPDATE addon_account_data SET money = ? WHERE account_name = ?', { self.money, self.name }) - else - MySQL.update('UPDATE addon_account_data SET money = ? WHERE account_name = ? AND owner = ?', - { self.money, self.name, self.owner }) + local query, params = 'UPDATE addon_account_data SET money = ? WHERE account_name = ?', { self.money, self.name } + + if self.owner then + query = query .. ' AND owner = ?' + table.insert(params, self.owner) end + + MySQL.update.await(query, params) TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) end From b80a078ff80093f253c34964ad670dc02a08c6b4 Mon Sep 17 00:00:00 2001 From: Mirow Date: Thu, 4 Sep 2025 20:29:10 +0200 Subject: [PATCH 11/25] chore: update manifest --- [esx_addons]/esx_addonaccount/fxmanifest.lua | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/fxmanifest.lua b/[esx_addons]/esx_addonaccount/fxmanifest.lua index dbf78a30..f13679d9 100644 --- a/[esx_addons]/esx_addonaccount/fxmanifest.lua +++ b/[esx_addons]/esx_addonaccount/fxmanifest.lua @@ -1,10 +1,11 @@ -fx_version 'adamant' +fx_version 'cerulean' game 'gta5' +lua54 'yes' +use_fxv2_oal 'yes' author 'ESX-Framework' -description 'Allows resources to store account data, such as society funds' -lua54 'yes' -version '1.1' +description 'Allows resources to store account data, such as society funds.' +version '1.2' legacyversion '1.13.4' server_scripts { @@ -14,10 +15,9 @@ server_scripts { 'server/main.lua' } -server_exports { - 'GetSharedAccount', - 'AddSharedAccount', - 'GetAccount' -} - -dependency 'es_extended' +-- @todo remove, kept just for overview +-- server_exports { +-- 'GetSharedAccount', +-- 'AddSharedAccount', +-- 'GetAccount' +-- } From f0218c0342819d2581c9270f682f8ce75649dbbd Mon Sep 17 00:00:00 2001 From: Mirow Date: Thu, 4 Sep 2025 20:29:22 +0200 Subject: [PATCH 12/25] chore: remove comments --- [esx_addons]/esx_addonaccount/fxmanifest.lua | 7 ------- 1 file changed, 7 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/fxmanifest.lua b/[esx_addons]/esx_addonaccount/fxmanifest.lua index f13679d9..7ac5e30c 100644 --- a/[esx_addons]/esx_addonaccount/fxmanifest.lua +++ b/[esx_addons]/esx_addonaccount/fxmanifest.lua @@ -14,10 +14,3 @@ server_scripts { 'server/classes/addonaccount.lua', 'server/main.lua' } - --- @todo remove, kept just for overview --- server_exports { --- 'GetSharedAccount', --- 'AddSharedAccount', --- 'GetAccount' --- } From 3449ff3b97fc7de566481dc321e4df7e2d52750b Mon Sep 17 00:00:00 2001 From: Mirow Date: Thu, 4 Sep 2025 20:30:00 +0200 Subject: [PATCH 13/25] refactor(server): rewrite Rewrote the functions to load the accounts. Also moved the exports there. --- [esx_addons]/esx_addonaccount/server/main.lua | 189 +++++++++--------- 1 file changed, 92 insertions(+), 97 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index d4ef91d8..d3583805 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -1,101 +1,125 @@ -local AccountsIndex, Accounts, SharedAccounts = {}, {}, {} +local Accounts, SharedAccounts = {}, {} + +local FETCH_ACCOUNTS_QUERY = [[ + SELECT * FROM addon_account + LEFT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name + UNION + SELECT * FROM addon_account + RIGHT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name +]] +local function initializeAccounts() + local accounts = MySQL.query.await(FETCH_ACCOUNTS_QUERY) + local newAccounts = {} + + for _, accountRow in ipairs(accounts) do + local accountName = accountRow.name + if accountRow.shared == 0 then + if not Accounts[accountName] then + Accounts[accountName] = {} + end -AddEventHandler('onResourceStart', function(resourceName) - if resourceName == GetCurrentResourceName() then - local accounts = MySQL.query.await( - 'SELECT * FROM addon_account LEFT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name UNION SELECT * FROM addon_account RIGHT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name') - - local newAccounts = {} - for i = 1, #accounts do - local account = accounts[i] - if account.shared == 0 then - if not Accounts[account.name] then - AccountsIndex[#AccountsIndex + 1] = account.name - Accounts[account.name] = {} - end - Accounts[account.name][#Accounts[account.name] + 1] = CreateAddonAccount(account.name, account.owner, - account.money) + local newIndex = #Accounts[accountName] + 1 + Accounts[accountName][newIndex] = CreateAddonAccount(accountName, accountRow.owner, accountRow.money) + else + if accountRow.money then + SharedAccounts[accountName] = CreateAddonAccount(accountName, nil, accountRow.money) else - if account.money then - SharedAccounts[account.name] = CreateAddonAccount(account.name, nil, account.money) - else - newAccounts[#newAccounts + 1] = { account.name, 0 } - end + newAccounts[#newAccounts + 1] = { accountName, 0 } end end - GlobalState.SharedAccounts = SharedAccounts + end - if next(newAccounts) then - MySQL.prepare('INSERT INTO addon_account_data (account_name, money) VALUES (?, ?)', newAccounts) - for i = 1, #newAccounts do - local newAccount = newAccounts[i] - SharedAccounts[newAccount[1]] = CreateAddonAccount(newAccount[1], nil, 0) - end - GlobalState.SharedAccounts = SharedAccounts + GlobalState.SharedAccounts = SharedAccounts + + if next(newAccounts) then + MySQL.prepare.await('INSERT INTO addon_account_data (account_name, money) VALUES (?, ?)', newAccounts) + + for _, newAccount in ipairs(newAccounts) do + local accountName = newAccount[1] + SharedAccounts[accountName] = CreateAddonAccount(accountName, nil, 0) end + + GlobalState.SharedAccounts = SharedAccounts end -end) +end -function GetAccount(name, owner) - for i = 1, #Accounts[name], 1 do - if Accounts[name][i].owner == owner then - return Accounts[name][i] +---@param name string +---@param owner string +---@return AddonAccount? +local function getAccount(name, owner) + for _, account in ipairs(Accounts[name]) do + if account.owner == owner then + return account end end end -function GetSharedAccount(name) +---@param name string +---@return AddonAccount +local function getSharedAccount(name) return SharedAccounts[name] end -function AddSharedAccount(society, amount) - -- society.name = job_name/society_name - -- society.label = label for the job/account - -- amount = if the shared account should start with x amount - if type(society) ~= 'table' or not society?.name or not society?.label then return end +---@param society { name: string, label: string } +---@param amount? number +---@return AddonAccount? +local function addSharedAccount(society, amount) + local societyName, societyLabel = society?.name, society?.label + if not societyName or not societyLabel then return end - -- check if account already exist? - if SharedAccounts[society.name] ~= nil then return SharedAccounts[society.name] end + local existingSharedAccount = SharedAccounts[societyName] + if existingSharedAccount then return existingSharedAccount end - -- addon account: - local account = MySQL.insert.await('INSERT INTO `addon_account` (name, label, shared) VALUES (?, ?, ?)', { - society.name, society.label, 1 - }) + local account = MySQL.insert.await('INSERT INTO `addon_account` (name, label, shared) VALUES (?, ?, ?)', { societyName, societyLabel, 1 }) if not account then return end - -- if addon account inserted, insert addon account data: - local account_data = MySQL.insert.await('INSERT INTO `addon_account_data` (account_name, money) VALUES (?, ?)', { - society.name, (amount or 0) + amount = amount or 0 + local accountData = MySQL.insert.await('INSERT INTO `addon_account_data` (account_name, money) VALUES (?, ?)', { + societyName, amount }) - if not account_data then return end + if not accountData then return end + + SharedAccounts[societyName] = CreateAddonAccount(societyName, nil, amount) - -- if all data inserted successfully to sql: - SharedAccounts[society.name] = CreateAddonAccount(society.name, nil, (amount or 0)) + GlobalState.SharedAccounts = SharedAccounts - return SharedAccounts[society.name] + return SharedAccounts[societyName] end +AddEventHandler('onResourceStart', function(resourceName) + if resourceName ~= GetCurrentResourceName() then return end + + initializeAccounts() +end) + +---@param name string +---@param owner string +---@param cb function AddEventHandler('esx_addonaccount:getAccount', function(name, owner, cb) - cb(GetAccount(name, owner)) + cb(getAccount(name, owner)) end) +---@param name string +---@param cb function AddEventHandler('esx_addonaccount:getSharedAccount', function(name, cb) - cb(GetSharedAccount(name)) + cb(getSharedAccount(name)) end) -AddEventHandler('esx:playerLoaded', function(playerId, xPlayer) +AddEventHandler('esx:playerLoaded', function(_, xPlayer) local addonAccounts = {} - for i = 1, #AccountsIndex, 1 do - local name = AccountsIndex[i] - local account = GetAccount(name, xPlayer.identifier) + local identifier = xPlayer.getIdentifier() + for _, accountName in pairs(Accounts) do + local account = getAccount(accountName, identifier) - if account == nil then - MySQL.insert('INSERT INTO addon_account_data (account_name, money, owner) VALUES (?, ?, ?)', - { name, 0, xPlayer.identifier }) + if not account then + MySQL.insert.await('INSERT INTO addon_account_data (account_name, money, owner) VALUES (?, ?, ?)', + { accountName, 0, identifier }) - account = CreateAddonAccount(name, xPlayer.identifier, 0) - Accounts[name][#Accounts[name] + 1] = account + account = CreateAddonAccount(accountName, identifier, 0) + + local newIndex = #Accounts[accountName] + 1 + Accounts[accountName][newIndex] = account end addonAccounts[#addonAccounts + 1] = account @@ -104,37 +128,8 @@ AddEventHandler('esx:playerLoaded', function(playerId, xPlayer) xPlayer.set('addonAccounts', addonAccounts) end) -RegisterNetEvent('esx_addonaccount:refreshAccounts') -AddEventHandler('esx_addonaccount:refreshAccounts', function() - local addonAccounts = MySQL.query.await('SELECT * FROM addon_account') - - for i = 1, #addonAccounts, 1 do - local name = addonAccounts[i].name - local shared = addonAccounts[i].shared +RegisterNetEvent('esx_addonaccount:refreshAccounts', initializeAccounts) - local addonAccountData = MySQL.query.await('SELECT * FROM addon_account_data WHERE account_name = ?', { name }) - - if shared == 0 then - table.insert(AccountsIndex, name) - Accounts[name] = {} - - for j = 1, #addonAccountData, 1 do - local addonAccount = CreateAddonAccount(name, addonAccountData[j].owner, addonAccountData[j].money) - table.insert(Accounts[name], addonAccount) - end - else - local money = nil - - if #addonAccountData == 0 then - MySQL.insert('INSERT INTO addon_account_data (account_name, money, owner) VALUES (?, ?, ?)', - { name, 0, nil }) - money = 0 - else - money = addonAccountData[1].money - end - - local addonAccount = CreateAddonAccount(name, nil, money) - SharedAccounts[name] = addonAccount - end - end -end) +exports('GetSharedAccount', getSharedAccount) +exports('AddSharedAccount', addSharedAccount) +exports('GetAccount', getAccount) From c0074eaae31b52039df645847c1e29345146aae4 Mon Sep 17 00:00:00 2001 From: Mirow Date: Fri, 5 Sep 2025 16:08:06 +0200 Subject: [PATCH 14/25] refactor(esx_addonaccount): lazy load accounts --- .../esx_addonaccount/server/database.lua | 35 +++ [esx_addons]/esx_addonaccount/server/main.lua | 227 +++++++++++------- 2 files changed, 169 insertions(+), 93 deletions(-) create mode 100644 [esx_addons]/esx_addonaccount/server/database.lua diff --git a/[esx_addons]/esx_addonaccount/server/database.lua b/[esx_addons]/esx_addonaccount/server/database.lua new file mode 100644 index 00000000..b02b28ba --- /dev/null +++ b/[esx_addons]/esx_addonaccount/server/database.lua @@ -0,0 +1,35 @@ +Database = {} + +---@class DatabaseAccountRow +---@field name string +---@field label string +---@field shared number +---@field id number +---@field account_name? string +---@field money number +---@field owner? string + +---@param name string +---@param owner string +---@return DatabaseAccountRow? +function Database.fetchAccount(name, owner) + local accountData = MySQL.single.await([[ + SELECT * FROM addon_account aa + FULL OUTER JOIN addon_account_data aad ON aa.name = aad.account_name + WHERE aa.shared = 0 AND aa.name = ? AND aad.owner = ? + ]], { name, owner }) + + return accountData +end + +---@param name string +---@return DatabaseAccountRow? +function Database.fetchSharedAccount(name) + local accountData = MySQL.single.await([[ + SELECT * FROM addon_account aa + FULL OUTER JOIN addon_account_data aad ON aa.name = aad.account_name + WHERE aa.shared = 1 AND aa.name = ? + ]], { name }) + + return accountData +end diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index d3583805..ac815ddf 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -1,135 +1,176 @@ -local Accounts, SharedAccounts = {}, {} - -local FETCH_ACCOUNTS_QUERY = [[ - SELECT * FROM addon_account - LEFT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name - UNION - SELECT * FROM addon_account - RIGHT JOIN addon_account_data ON addon_account.name = addon_account_data.account_name -]] -local function initializeAccounts() - local accounts = MySQL.query.await(FETCH_ACCOUNTS_QUERY) - local newAccounts = {} - - for _, accountRow in ipairs(accounts) do - local accountName = accountRow.name - if accountRow.shared == 0 then - if not Accounts[accountName] then - Accounts[accountName] = {} - end - - local newIndex = #Accounts[accountName] + 1 - Accounts[accountName][newIndex] = CreateAddonAccount(accountName, accountRow.owner, accountRow.money) - else - if accountRow.money then - SharedAccounts[accountName] = CreateAddonAccount(accountName, nil, accountRow.money) - else - newAccounts[#newAccounts + 1] = { accountName, 0 } - end - end - end - - GlobalState.SharedAccounts = SharedAccounts - - if next(newAccounts) then - MySQL.prepare.await('INSERT INTO addon_account_data (account_name, money) VALUES (?, ?)', newAccounts) - - for _, newAccount in ipairs(newAccounts) do - local accountName = newAccount[1] - SharedAccounts[accountName] = CreateAddonAccount(accountName, nil, 0) - end - - GlobalState.SharedAccounts = SharedAccounts - end -end +Accounts, SharedAccounts = {}, {} ---@param name string ---@param owner string ---@return AddonAccount? local function getAccount(name, owner) - for _, account in ipairs(Accounts[name]) do - if account.owner == owner then - return account - end - end + local existingAccount = Accounts[name][owner] + if existingAccount then + return existingAccount + end + + local dbAccount = Database.fetchAccount(name, owner) + if not dbAccount then return end + + if not Accounts[name] then + Accounts[name] = {} + end + + Accounts[name][owner] = CreateAddonAccount(name, owner, dbAccount.money) + + return Accounts[name][owner] end ---@param name string ----@return AddonAccount +---@return AddonAccount? local function getSharedAccount(name) - return SharedAccounts[name] + local existingAccount = SharedAccounts[name] + if existingAccount then + return existingAccount + end + + local dbAccount = Database.fetchSharedAccount(name) + if not dbAccount then return end + + local money = dbAccount.money + SharedAccounts[name] = CreateAddonAccount(name, nil, money or 0) + + if not money then + MySQL.prepare.await('INSERT INTO addon_account_data (account_name, money) VALUES (?, ?)', { name, 0 }) + end + + GlobalState.SharedAccounts = SharedAccounts + + return SharedAccounts[name] end ---@param society { name: string, label: string } ---@param amount? number ---@return AddonAccount? local function addSharedAccount(society, amount) - local societyName, societyLabel = society?.name, society?.label - if not societyName or not societyLabel then return end + local societyName, societyLabel = society?.name, society?.label + if not societyName or not societyLabel then return end - local existingSharedAccount = SharedAccounts[societyName] - if existingSharedAccount then return existingSharedAccount end + local existingSharedAccount = getSharedAccount(societyName) + if existingSharedAccount then return existingSharedAccount end - local account = MySQL.insert.await('INSERT INTO `addon_account` (name, label, shared) VALUES (?, ?, ?)', { societyName, societyLabel, 1 }) - if not account then return end + local account = MySQL.insert.await('INSERT INTO `addon_account` (name, label, shared) VALUES (?, ?, ?)', { societyName, societyLabel, 1 }) + if not account then return end - amount = amount or 0 - local accountData = MySQL.insert.await('INSERT INTO `addon_account_data` (account_name, money) VALUES (?, ?)', { - societyName, amount - }) - if not accountData then return end + amount = amount or 0 + local accountData = MySQL.insert.await('INSERT INTO `addon_account_data` (account_name, money) VALUES (?, ?)', { + societyName, amount + }) + if not accountData then return end - SharedAccounts[societyName] = CreateAddonAccount(societyName, nil, amount) + SharedAccounts[societyName] = CreateAddonAccount(societyName, nil, amount) - GlobalState.SharedAccounts = SharedAccounts + GlobalState.SharedAccounts = SharedAccounts - return SharedAccounts[societyName] + return SharedAccounts[societyName] end -AddEventHandler('onResourceStart', function(resourceName) - if resourceName ~= GetCurrentResourceName() then return end +---@param name string +---@param owner string +---@param amount number +local function addAccountMoney(name, owner, amount) + local account = getAccount(name, owner) + if not account then return end - initializeAccounts() -end) + account.addMoney(amount) +end ---@param name string ---@param owner string ----@param cb function -AddEventHandler('esx_addonaccount:getAccount', function(name, owner, cb) - cb(getAccount(name, owner)) -end) +---@param amount number +local function removeAccountMoney(name, owner, amount) + local account = getAccount(name, owner) + if not account then return end + + account.removeMoney(amount) +end ---@param name string ----@param cb function -AddEventHandler('esx_addonaccount:getSharedAccount', function(name, cb) - cb(getSharedAccount(name)) -end) +---@param owner string +---@param amount number +local function setAccountMoney(name, owner, amount) + local account = getAccount(name, owner) + if not account then return end + + account.setMoney(amount) +end + +---@param name string +---@param amount number +local function addSharedAccountMoney(name, amount) + local account = getSharedAccount(name) + if not account then return end + + account.addMoney(amount) +end + +---@param name string +---@param amount number +local function removeSharedAccountMoney(name, amount) + local account = getSharedAccount(name) + if not account then return end + + account.removeMoney(amount) +end + +---@param name string +---@param amount number +local function setSharedAccountMoney(name, amount) + local account = getSharedAccount(name) + if not account then return end + + account.setMoney(amount) +end AddEventHandler('esx:playerLoaded', function(_, xPlayer) - local addonAccounts = {} + local addonAccounts = {} + + local identifier = xPlayer.getIdentifier() + for _, accountName in pairs(Accounts) do + local account = getAccount(accountName, identifier) - local identifier = xPlayer.getIdentifier() - for _, accountName in pairs(Accounts) do - local account = getAccount(accountName, identifier) + if not account then + MySQL.insert.await('INSERT INTO addon_account_data (account_name, money, owner) VALUES (?, ?, ?)', + { accountName, 0, identifier }) - if not account then - MySQL.insert.await('INSERT INTO addon_account_data (account_name, money, owner) VALUES (?, ?, ?)', - { accountName, 0, identifier }) + account = CreateAddonAccount(accountName, identifier, 0) - account = CreateAddonAccount(accountName, identifier, 0) + Accounts[accountName][identifier] = account + end - local newIndex = #Accounts[accountName] + 1 - Accounts[accountName][newIndex] = account - end + addonAccounts[#addonAccounts + 1] = account + end - addonAccounts[#addonAccounts + 1] = account - end + xPlayer.set('addonAccounts', addonAccounts) +end) - xPlayer.set('addonAccounts', addonAccounts) +---@param name string +---@param owner string +---@param cb function +AddEventHandler('esx_addonaccount:getAccount', function(name, owner, cb) + cb(getAccount(name, owner)) end) -RegisterNetEvent('esx_addonaccount:refreshAccounts', initializeAccounts) +---@param name string +---@param cb function +AddEventHandler('esx_addonaccount:getSharedAccount', function(name, cb) + cb(getSharedAccount(name)) +end) exports('GetSharedAccount', getSharedAccount) -exports('AddSharedAccount', addSharedAccount) exports('GetAccount', getAccount) + +exports('AddSharedAccount', addSharedAccount) + +exports('AddAccountMoney', addAccountMoney) +exports('RemoveAccountMoney', removeAccountMoney) +exports('SetAccountMoney', setAccountMoney) + +exports('AddSharedAccountMoney', addSharedAccountMoney) +exports('RemoveSharedAccountMoney', removeSharedAccountMoney) +exports('SetSharedAccountMoney', setSharedAccountMoney) From 142e62da5880d2eb8ac5edf64be58c2d3c1321eb Mon Sep 17 00:00:00 2001 From: Mirow Date: Fri, 5 Sep 2025 16:14:08 +0200 Subject: [PATCH 15/25] feat(esx_addonaccount): add fn to sync accounts with database --- .../server/classes/addonaccount.lua | 15 +++------------ .../esx_addonaccount/server/database.lua | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua index fc6ae8f3..cbfc6cdc 100644 --- a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua +++ b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua @@ -21,35 +21,26 @@ function CreateAddonAccount(name, owner, money) function self.addMoney(amount) self.money += amount - self.save() TriggerEvent('esx_addonaccount:addMoney', self.name, amount) + TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) end function self.removeMoney(amount) self.money -= amount - self.save() TriggerEvent('esx_addonaccount:removeMoney', self.name, amount) + TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) end function self.setMoney(amount) self.money = amount - self.save() TriggerEvent('esx_addonaccount:setMoney', self.name, amount) + TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) end function self.save() - local query, params = 'UPDATE addon_account_data SET money = ? WHERE account_name = ?', { self.money, self.name } - - if self.owner then - query = query .. ' AND owner = ?' - table.insert(params, self.owner) - end - - MySQL.update.await(query, params) - TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) end return self diff --git a/[esx_addons]/esx_addonaccount/server/database.lua b/[esx_addons]/esx_addonaccount/server/database.lua index b02b28ba..1c912a41 100644 --- a/[esx_addons]/esx_addonaccount/server/database.lua +++ b/[esx_addons]/esx_addonaccount/server/database.lua @@ -33,3 +33,22 @@ function Database.fetchSharedAccount(name) return accountData end + +function Database.saveAccounts() + local params, n = {}, 0 + for _, accountData in pairs(Accounts) do + for owner, account in pairs(accountData) do + n += 1 + params[n] = { account.money, account.name, owner } + end + end + + for _, account in pairs(SharedAccounts) do + n += 1 + params[n] = { account.money, account.name } + end + + MySQL.prepare.await([[ + UPDATE addon_account_data SET money = ? WHERE account_name = ? AND owner = ?; + ]], params) +end From 097d539705dd9a58ecee47d449c8d0f76e01b319 Mon Sep 17 00:00:00 2001 From: Mirow Date: Fri, 5 Sep 2025 16:18:28 +0200 Subject: [PATCH 16/25] feat(esx_addonaccount): save accounts on restart --- [esx_addons]/esx_addonaccount/server/main.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index ac815ddf..3571596c 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -162,6 +162,23 @@ AddEventHandler('esx_addonaccount:getSharedAccount', function(name, cb) cb(getSharedAccount(name)) end) +AddEventHandler('txAdmin:events:scheduledRestart', function(eventData) + if eventData.secondsRemaining == 60 then + CreateThread(function() + Wait(50000) + Database.saveAccounts() + end) + end +end) + +AddEventHandler('onResourceStop', function(resource) + if resource == GetCurrentResourceName() then + Database.saveAccounts() + end +end) + +AddEventHandler('txAdmin:events:serverShuttingDown', Database.saveAccounts) + exports('GetSharedAccount', getSharedAccount) exports('GetAccount', getAccount) From f7f9b9595c0871e26eda32f23ec0b82cabf370b3 Mon Sep 17 00:00:00 2001 From: Mirow Date: Fri, 5 Sep 2025 16:19:59 +0200 Subject: [PATCH 17/25] fix(esx_addonaccount): load database module --- [esx_addons]/esx_addonaccount/fxmanifest.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/[esx_addons]/esx_addonaccount/fxmanifest.lua b/[esx_addons]/esx_addonaccount/fxmanifest.lua index 7ac5e30c..af2ca5e2 100644 --- a/[esx_addons]/esx_addonaccount/fxmanifest.lua +++ b/[esx_addons]/esx_addonaccount/fxmanifest.lua @@ -12,5 +12,6 @@ server_scripts { '@es_extended/imports.lua', '@oxmysql/lib/MySQL.lua', 'server/classes/addonaccount.lua', + 'server/database.lua', 'server/main.lua' } From 3016032675448900066af159b65a70a3d9cb33f7 Mon Sep 17 00:00:00 2001 From: Mirow Date: Fri, 5 Sep 2025 16:34:43 +0200 Subject: [PATCH 18/25] fix(esx_addonaccount): properly save accounts --- .../esx_addonaccount/server/database.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/database.lua b/[esx_addons]/esx_addonaccount/server/database.lua index 1c912a41..d4f55999 100644 --- a/[esx_addons]/esx_addonaccount/server/database.lua +++ b/[esx_addons]/esx_addonaccount/server/database.lua @@ -15,8 +15,8 @@ Database = {} function Database.fetchAccount(name, owner) local accountData = MySQL.single.await([[ SELECT * FROM addon_account aa - FULL OUTER JOIN addon_account_data aad ON aa.name = aad.account_name - WHERE aa.shared = 0 AND aa.name = ? AND aad.owner = ? + LEFT JOIN addon_account_data aad ON aa.name = aad.account_name + WHERE aa.shared = 1 AND aa.name = ? AND aad.owner = ? ]], { name, owner }) return accountData @@ -27,7 +27,7 @@ end function Database.fetchSharedAccount(name) local accountData = MySQL.single.await([[ SELECT * FROM addon_account aa - FULL OUTER JOIN addon_account_data aad ON aa.name = aad.account_name + LEFT JOIN addon_account_data aad ON aa.name = aad.account_name WHERE aa.shared = 1 AND aa.name = ? ]], { name }) @@ -35,6 +35,7 @@ function Database.fetchSharedAccount(name) end function Database.saveAccounts() + -- Save accounts that are not shared local params, n = {}, 0 for _, accountData in pairs(Accounts) do for owner, account in pairs(accountData) do @@ -43,12 +44,20 @@ function Database.saveAccounts() end end + if n > 0 then + MySQL.prepare.await([[ + UPDATE addon_account_data SET money = ? WHERE account_name = ? AND owner = ?; + ]], params) + end + + -- Save shared accounts + params, n = {}, 0 for _, account in pairs(SharedAccounts) do n += 1 - params[n] = { account.money, account.name } + params[n] = { account.money, account.name, nil } end MySQL.prepare.await([[ - UPDATE addon_account_data SET money = ? WHERE account_name = ? AND owner = ?; + UPDATE addon_account_data SET money = ? WHERE account_name = ?; ]], params) end From f13e0a26efb69ef98b1844bb3f31245dbe870ec3 Mon Sep 17 00:00:00 2001 From: Mirow Date: Sat, 6 Sep 2025 20:33:02 +0200 Subject: [PATCH 19/25] fix(esx_addonaccount): correct account query --- [esx_addons]/esx_addonaccount/server/database.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[esx_addons]/esx_addonaccount/server/database.lua b/[esx_addons]/esx_addonaccount/server/database.lua index d4f55999..08e6126e 100644 --- a/[esx_addons]/esx_addonaccount/server/database.lua +++ b/[esx_addons]/esx_addonaccount/server/database.lua @@ -16,7 +16,7 @@ function Database.fetchAccount(name, owner) local accountData = MySQL.single.await([[ SELECT * FROM addon_account aa LEFT JOIN addon_account_data aad ON aa.name = aad.account_name - WHERE aa.shared = 1 AND aa.name = ? AND aad.owner = ? + WHERE aa.shared = 0 AND aa.name = ? AND aad.owner = ? ]], { name, owner }) return accountData From ed5322f900c30135ef1c08a13a4cac697ddd3db2 Mon Sep 17 00:00:00 2001 From: Mirow Date: Sat, 6 Sep 2025 20:33:23 +0200 Subject: [PATCH 20/25] fix(esx_addonaccount/server): table indexing error --- [esx_addons]/esx_addonaccount/server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index 3571596c..ee88bc33 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -4,7 +4,7 @@ Accounts, SharedAccounts = {}, {} ---@param owner string ---@return AddonAccount? local function getAccount(name, owner) - local existingAccount = Accounts[name][owner] + local existingAccount = Accounts[name]?[owner] if existingAccount then return existingAccount end From 9cb5e7d7e8320e2f7da224c739ae8d166440e916 Mon Sep 17 00:00:00 2001 From: Mirow Date: Tue, 9 Sep 2025 20:54:41 +0200 Subject: [PATCH 21/25] feat(addonaccount): return success of operations --- .../esx_addonaccount/server/classes/addonaccount.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua index cbfc6cdc..13523781 100644 --- a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua +++ b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua @@ -2,9 +2,9 @@ ---@field name string ---@field owner? string ---@field money number ----@field addMoney fun(amount: number) ----@field removeMoney fun(amount: number) ----@field setMoney fun(amount: number) +---@field addMoney fun(amount: number): boolean +---@field removeMoney fun(amount: number): boolean +---@field setMoney fun(amount: number): boolean ---@field save function ---@param name string @@ -24,13 +24,17 @@ function CreateAddonAccount(name, owner, money) TriggerEvent('esx_addonaccount:addMoney', self.name, amount) TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) + return true end function self.removeMoney(amount) + if amount > self.money then return false end + self.money -= amount TriggerEvent('esx_addonaccount:removeMoney', self.name, amount) TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) + return true end function self.setMoney(amount) @@ -38,6 +42,7 @@ function CreateAddonAccount(name, owner, money) TriggerEvent('esx_addonaccount:setMoney', self.name, amount) TriggerClientEvent('esx_addonaccount:setMoney', -1, self.name, self.money) + return true end function self.save() From 42ffd91fb26e271d810219817634977ff787927a Mon Sep 17 00:00:00 2001 From: Mirow Date: Tue, 9 Sep 2025 20:54:53 +0200 Subject: [PATCH 22/25] feat(esx_addonaccount): introduce `TransferMoney` export. --- [esx_addons]/esx_addonaccount/server/main.lua | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index ee88bc33..c55f4ff2 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -127,6 +127,39 @@ local function setSharedAccountMoney(name, amount) account.setMoney(amount) end +---@alias TransactionAccount { name: string, owner?: string }|string + +---@param accountData TransactionAccount +---@return AddonAccount? +local function getTransactionAccount(accountData) + if type(accountData) == "string" then + return getSharedAccount(accountData) + end + + if accountData.owner then + return getAccount(accountData.name, accountData.owner) + else + return getSharedAccount(accountData.name) + end +end + +---@param sender TransactionAccount +---@param receiver TransactionAccount +---@param amount number +---@return boolean, string +local function transferMoney(sender, receiver, amount) + local senderAccount, receiverAccount = getTransactionAccount(sender), getTransactionAccount(receiver) + if not senderAccount or not receiverAccount then return false, 'invalid_account' end + + if not senderAccount.removeMoney(amount) then + return false, 'insufficient_funds' + end + + receiverAccount.addMoney(amount) + + return true, 'success' +end + AddEventHandler('esx:playerLoaded', function(_, xPlayer) local addonAccounts = {} @@ -191,3 +224,5 @@ exports('SetAccountMoney', setAccountMoney) exports('AddSharedAccountMoney', addSharedAccountMoney) exports('RemoveSharedAccountMoney', removeSharedAccountMoney) exports('SetSharedAccountMoney', setSharedAccountMoney) + +exports('TransferMoney', transferMoney) From fcb83691b46c7b46481d7642468c0ae1181e07d4 Mon Sep 17 00:00:00 2001 From: Mirow Date: Thu, 11 Sep 2025 18:48:19 +0200 Subject: [PATCH 23/25] feat(esx_addonaccount): add `transferMoney` method to class --- .../server/classes/addonaccount.lua | 13 +++++++++++++ [esx_addons]/esx_addonaccount/server/main.lua | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua index 13523781..0920f8ac 100644 --- a/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua +++ b/[esx_addons]/esx_addonaccount/server/classes/addonaccount.lua @@ -5,6 +5,7 @@ ---@field addMoney fun(amount: number): boolean ---@field removeMoney fun(amount: number): boolean ---@field setMoney fun(amount: number): boolean +---@field transferMoney fun(target: TransactionAccount, amount: number): boolean ---@field save function ---@param name string @@ -45,6 +46,18 @@ function CreateAddonAccount(name, owner, money) return true end + function self.transferMoney(target, amount) + local targetAccount = GetTransactionAccount(target) + if not targetAccount then return false end + + if not self.removeMoney(amount) then + return false + end + + targetAccount.addMoney(amount) + return true + end + function self.save() end diff --git a/[esx_addons]/esx_addonaccount/server/main.lua b/[esx_addons]/esx_addonaccount/server/main.lua index c55f4ff2..978fa660 100644 --- a/[esx_addons]/esx_addonaccount/server/main.lua +++ b/[esx_addons]/esx_addonaccount/server/main.lua @@ -131,7 +131,7 @@ end ---@param accountData TransactionAccount ---@return AddonAccount? -local function getTransactionAccount(accountData) +function GetTransactionAccount(accountData) if type(accountData) == "string" then return getSharedAccount(accountData) end @@ -148,7 +148,7 @@ end ---@param amount number ---@return boolean, string local function transferMoney(sender, receiver, amount) - local senderAccount, receiverAccount = getTransactionAccount(sender), getTransactionAccount(receiver) + local senderAccount, receiverAccount = GetTransactionAccount(sender), GetTransactionAccount(receiver) if not senderAccount or not receiverAccount then return false, 'invalid_account' end if not senderAccount.removeMoney(amount) then From e2b39e8253040374e920a81828260c38a5f34694 Mon Sep 17 00:00:00 2001 From: _Not_ <160342111+N0tNvll@users.noreply.github.com> Date: Thu, 2 Oct 2025 19:50:47 -0500 Subject: [PATCH 24/25] Revert "refactor(esx_hud): remove outdated check" --- [esx_addons]/esx_hud/locales/da.lua | 7 +- [esx_addons]/esx_hud/locales/de.lua | 7 +- [esx_addons]/esx_hud/locales/en.lua | 7 +- [esx_addons]/esx_hud/locales/fi.lua | 5 ++ [esx_addons]/esx_hud/locales/fr.lua | 5 ++ [esx_addons]/esx_hud/locales/hu.lua | 27 ++++--- [esx_addons]/esx_hud/locales/it.lua | 5 ++ [esx_addons]/esx_hud/locales/nl.lua | 5 ++ [esx_addons]/esx_hud/locales/pt.lua | 5 ++ [esx_addons]/esx_hud/locales/sr.lua | 5 ++ [esx_addons]/esx_hud/locales/sv.lua | 5 ++ [esx_addons]/esx_hud/locales/tr.lua | 5 ++ [esx_addons]/esx_hud/server/main.lua | 104 +++++++++++++++++++++++++++ 13 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 [esx_addons]/esx_hud/server/main.lua diff --git a/[esx_addons]/esx_hud/locales/da.lua b/[esx_addons]/esx_hud/locales/da.lua index a8e1c1ba..e7ae4dcd 100644 --- a/[esx_addons]/esx_hud/locales/da.lua +++ b/[esx_addons]/esx_hud/locales/da.lua @@ -7,5 +7,10 @@ Locales["da"] = { resource_not_built = "Ressourcen er ikke lavet, download venligst udgivelsesversionen", settingsSaveSuccess = "De nuværende indstillinger er gemt", settingsResetSuccess = "Indstillingerne blev nulstillet", + currentVersion = "Seneste version: ", + yourVersion = "Din version: ", + latestVersion = "Du bruger den seneste version!", + needUpdateResource = "Du skal downloade den nyeste version! Du bruger en gammel version i øjeblikket!", + errorGetCurrentVersion = "Der opstod en fejl under forsøget på at hente den nuværende version!", job_off_duty = " (Ikke på vagt)", -} \ No newline at end of file +} diff --git a/[esx_addons]/esx_hud/locales/de.lua b/[esx_addons]/esx_hud/locales/de.lua index 664a8f57..e6642da5 100644 --- a/[esx_addons]/esx_hud/locales/de.lua +++ b/[esx_addons]/esx_hud/locales/de.lua @@ -7,5 +7,10 @@ Locales["de"] = { resource_not_built = "Resource ist gebuilded! Downloade die neuste version!", settingsSaveSuccess = "Erfolgreich die derzeitigen einstellungen gespeichert!", settingsResetSuccess = "Einstellungen erfolgreich zurückgesetzt", + currentVersion = "Letzte Version: ", + yourVersion = "Deine Version: ", + latestVersion = "Du nutzt die neuste Version von esx_hud!", + needUpdateResource = "Du musst die letze Version downloaden! Installiere die neuste Version!", + errorGetCurrentVersion = "Ein Fehler kam als die Versionsabfrage durchgeführt wurde!", job_off_duty = " (Außer Dienst)", -} \ No newline at end of file +} diff --git a/[esx_addons]/esx_hud/locales/en.lua b/[esx_addons]/esx_hud/locales/en.lua index ee1c3cc5..dbfe0843 100644 --- a/[esx_addons]/esx_hud/locales/en.lua +++ b/[esx_addons]/esx_hud/locales/en.lua @@ -7,5 +7,10 @@ Locales["en"] = { resource_not_built = "Resource are not built, please download the release version", settingsSaveSuccess = "Successfully save current settings", settingsResetSuccess = "Successfully reset settings", + currentVersion = "Latest version: ", + yourVersion = "Your version: ", + latestVersion = "You are using the latest version!", + needUpdateResource = "You need download latest version! You are using an old version at the moment!", + errorGetCurrentVersion = "An error occurred while trying to get the current version!", job_off_duty = " (Off-Duty)", -} \ No newline at end of file +} diff --git a/[esx_addons]/esx_hud/locales/fi.lua b/[esx_addons]/esx_hud/locales/fi.lua index 8bbc617f..45f0ab49 100644 --- a/[esx_addons]/esx_hud/locales/fi.lua +++ b/[esx_addons]/esx_hud/locales/fi.lua @@ -7,5 +7,10 @@ Locales["fi"] = { resource_not_built = "Resursseja ei ole rakennettu, lataa julkaisuversio", settingsSaveSuccess = "Nykyisten asetusten tallentaminen onnistui", settingsResetSuccess = "Asetusten nollaus onnistui", + currentVersion = "Uusin versio: ", + yourVersion = "Sinun versio: ", + latestVersion = "Käytät uusinta versiota!", + needUpdateResource = "Sinun on ladattava uusin versio! Käytät tällä hetkellä vanhaa versiota!", + errorGetCurrentVersion = "Virhe yritettäessä saada nykyinen versio!", job_off_duty = " (Vapaalla)", } diff --git a/[esx_addons]/esx_hud/locales/fr.lua b/[esx_addons]/esx_hud/locales/fr.lua index d7706038..8e0575ff 100644 --- a/[esx_addons]/esx_hud/locales/fr.lua +++ b/[esx_addons]/esx_hud/locales/fr.lua @@ -7,5 +7,10 @@ Locales["fr"] = { resource_not_built = "La ressource n'est pas build, télécharger une version officielle ou compilez la ressource vous même", settingsSaveSuccess = "Les paramètres actuels ont bien été sauvegardés", settingsResetSuccess = "Les paramètres ont bien été réinitialisés", + currentVersion = "Dernière version: ", + yourVersion = "Votre version: ", + latestVersion = "Vous utilisez la dernière version!", + needUpdateResource = "Vous devez télécharger la dernière version! Vous utilisez actuellement une ancienne version!", + errorGetCurrentVersion = "Une erreur s'est produite lors de la tentative d'obtention de la version actuelle!", job_off_duty = " (Hors service)", } diff --git a/[esx_addons]/esx_hud/locales/hu.lua b/[esx_addons]/esx_hud/locales/hu.lua index c6b343f5..70cbe924 100644 --- a/[esx_addons]/esx_hud/locales/hu.lua +++ b/[esx_addons]/esx_hud/locales/hu.lua @@ -1,11 +1,18 @@ Locales["hu"] = { - toggleHud = "HUD be/ki kapcsolása", - indicatorLeft = "Bal irányjelző", - indicatorRight = "Jobb irányjelző", - toggleEngine = "Motor be/ki kapcsolása", - speedChanged = "Sebesség megváltoztatva, új sebesség: ", - resource_not_built = "Az erőforrás nincs lefordítva, töltsd le a kiadott verziót", - settingsSaveSuccess = "A jelenlegi beállítások sikeresen elmentve", - settingsResetSuccess = "A beállítások sikeresen visszaállítva", - job_off_duty = " (Szolgálaton kívül)", -} \ No newline at end of file + toggleHud = "Hud ki / be kapcsolása", + indicatorLeft = "Bal index", + indicatorRight = "Jobb index", + toggleEngine = "Motor ki / be kapcsolása", + increaseSpeed = "(Tempomat) Sebbeség nővelése", + decreaseSpeed = "(Tempomat) Sebbeség csökkenentése", + speedChanged = "Sebesség megváltoztatva, új sebbeség: ", + resource_not_built = "Nincs le buildelve a resource, kérlek töltsd le a release-t", + settingsSaveSuccess = "Sikeresen megtörtént a mentése beállításoknak!", + settingsResetSuccess = "Sikeresen megtörtént a visszaállítása a beállításoknak!", + latestVersion = "Legújabb verziót használod!", + currentVersion = "Legfrissebb verzió: ", + yourVersion = "Jelenlegi verziód: ", + needUpdateResource = "Elavult a verziód töltsd le a legújabbat!", + errorGetCurrentVersion = "Hiba történt a verzió lekérdezés közben!", + job_off_duty = " (Szabadnapos)", +} diff --git a/[esx_addons]/esx_hud/locales/it.lua b/[esx_addons]/esx_hud/locales/it.lua index adef39f3..99fc0516 100644 --- a/[esx_addons]/esx_hud/locales/it.lua +++ b/[esx_addons]/esx_hud/locales/it.lua @@ -7,5 +7,10 @@ Locales["it"] = { resource_not_built = "La risorsa non è stata buildata, scarica la versione release, non il source code!", settingsSaveSuccess = "Salvataggio delle impostazioni correnti riuscito", settingsResetSuccess = "Ripristino impostazioni riuscito", + currentVersion = "Ultima versione ", + yourVersion = "La tua versione:", + latestVersion = "Stai utilizzando l'ultima versione!", + needUpdateResource = "Devi scaricare l'ultima versione! Al momento stai usando una vecchia versione!", + errorGetCurrentVersion = "Si è verificato un errore durante il tentativo di ottenere la versione corrente!", job_off_duty = " (Fuori servizio)", } diff --git a/[esx_addons]/esx_hud/locales/nl.lua b/[esx_addons]/esx_hud/locales/nl.lua index bfa12d6f..31bae3c6 100644 --- a/[esx_addons]/esx_hud/locales/nl.lua +++ b/[esx_addons]/esx_hud/locales/nl.lua @@ -7,5 +7,10 @@ Locales["nl"] = { resource_not_built = "Resource is niet gebouwd, download de releaseversie", settingsSaveSuccess = "De instellingen zijn succesvol opgeslagen", settingsResetSuccess = "De instellingen zijn succesvol gereset", + currentVersion = "Laatste versie: ", + yourVersion = "Jouw versie: ", + latestVersion = "Je gebruikt de laatste versie !", + needUpdateResource = "Je bent een oude versie aan het gebruiken ! download de nieuwste versie !", + errorGetCurrentVersion = "Er is een error ontstaan tijdens het ophalen van de huidige versie !", job_off_duty = " (Niet in dienst)", } diff --git a/[esx_addons]/esx_hud/locales/pt.lua b/[esx_addons]/esx_hud/locales/pt.lua index 27ba7279..afd70543 100644 --- a/[esx_addons]/esx_hud/locales/pt.lua +++ b/[esx_addons]/esx_hud/locales/pt.lua @@ -7,5 +7,10 @@ Locales["pt"] = { resource_not_built = 'O resource não foi construido, por favor faz download da versão "Release"', settingsSaveSuccess = "Salvaste as atuais definições com sucesso", settingsResetSuccess = "Formataste as definições com sucesso", + currentVersion = "Versão mais recente: ", + yourVersion = "A tua versão: ", + latestVersion = "Estás a usar a versão mais recente!", + needUpdateResource = "Precisas de descarregar a versão mais recente! Neste momento, estás a utilizar uma versão antiga!", + errorGetCurrentVersion = "Ocorreu um erro ao tentar obter a versão atual!", job_off_duty = " (Fora de serviço)", } diff --git a/[esx_addons]/esx_hud/locales/sr.lua b/[esx_addons]/esx_hud/locales/sr.lua index 8a8b3148..3927d575 100644 --- a/[esx_addons]/esx_hud/locales/sr.lua +++ b/[esx_addons]/esx_hud/locales/sr.lua @@ -7,5 +7,10 @@ Locales["sr"] = { resource_not_built = "Resurs nije napravljen, preuzmite release verziju resursa!", settingsSaveSuccess = "Trenutna podešavanja uspešno sačuvana", settingsResetSuccess = "Podešavanja uspešno resetovana", + currentVersion = "Poslednja verzija: ", + yourVersion = "Vaša verzija: ", + latestVersion = "Vi koristite poslednju verziju!", + needUpdateResource = "Morate preuzeti najnoviju verziju. Trenutno koristite staru verziju.", + errorGetCurrentVersion = "Došlo je do greške prilikom provere trenutne verzije resursa!", job_off_duty = " (Van dužnosti)", } diff --git a/[esx_addons]/esx_hud/locales/sv.lua b/[esx_addons]/esx_hud/locales/sv.lua index 6a3e19be..21a87bd2 100644 --- a/[esx_addons]/esx_hud/locales/sv.lua +++ b/[esx_addons]/esx_hud/locales/sv.lua @@ -7,5 +7,10 @@ Locales["sv"] = { resource_not_built = "Resource är inte byggd, ladda ner release versionen", settingsSaveSuccess = "Inställningar sparade", settingsResetSuccess = "Inställningar återställda", + currentVersion = "Senaste version: ", + yourVersion = "Din version: ", + latestVersion = "Du använder den senaste versionen!", + needUpdateResource = "Du behöver ladda ner den senaste versionen! Du använder en gammal version just nu!", + errorGetCurrentVersion = "Ett fel inträffade med att ladda ner den senaste versionen!", job_off_duty = " (Ledig)", } diff --git a/[esx_addons]/esx_hud/locales/tr.lua b/[esx_addons]/esx_hud/locales/tr.lua index d371e7e5..b286439f 100644 --- a/[esx_addons]/esx_hud/locales/tr.lua +++ b/[esx_addons]/esx_hud/locales/tr.lua @@ -7,5 +7,10 @@ Locales["tr"] = { resource_not_built = "Kaynak kurulmamış, lütfen son sürümü indirin", settingsSaveSuccess = "Ayarlar başarıyla kaydedildi", settingsResetSuccess = "Ayarlar başarıyla sıfırlandı", + currentVersion = "En son sürüm: ", + yourVersion = "Sizin sürümünüz: ", + latestVersion = "Şu anda en son sürümü kullanıyorsunuz!", + needUpdateResource = "En son sürümü indirmeniz gerekiyor! Şu anda eski bir sürümü kullanıyorsunuz!", + errorGetCurrentVersion = "Geçerli sürümü alırken bir hata oluştu!", job_off_duty = " (Görev dışı)", } diff --git a/[esx_addons]/esx_hud/server/main.lua b/[esx_addons]/esx_hud/server/main.lua new file mode 100644 index 00000000..3fe1fd8c --- /dev/null +++ b/[esx_addons]/esx_hud/server/main.lua @@ -0,0 +1,104 @@ +HUD.VersionCheckURL = "https://api.github.com/repos/esx-framework/esx-hud/releases/latest" + +function HUD:ErrorHandle(msg) + print(("[^1ERROR^7] ^3esx_hud^7: %s"):format(msg)) +end + +function HUD:InfoHandle(msg, color) + if color == "green" then + color = 2 + elseif color == "red" then + color = 1 + elseif color == "blue" then + color = 4 + else + color = 3 + end + print(("[^9INFO^7] ^3esx_hud^7: ^" .. color .. "%s^7"):format(msg)) +end + +VERSION = { + Check = function(err, response, headers) + --Credit: OX_lib version checker by Linden + local currentVersion = GetResourceMetadata(GetCurrentResourceName(), "version", 0) + local latestVersion + if not currentVersion then + return + end + + if err ~= 200 then + HUD:ErrorHandle(Translate("errorGetCurrentVersion")) + return + end + if response then + response = json.decode(response) + if not response.tag_name then + return + end + + latestVersion = response.tag_name:match("%d%.%d+%.%d+") + currentVersion = currentVersion:match("%d%.%d+%.%d+") + + if not latestVersion then + return + end + + if currentVersion == latestVersion then + HUD:InfoHandle(Translate("latestVersion"), "green") + return + end + + local currentVersionSplitted = { string.strsplit(".", currentVersion) } + local latestVersionSplitted = { string.strsplit(".", latestVersion) } + + HUD:InfoHandle(Translate("currentVersion") .. latestVersion, "green") + HUD:InfoHandle(Translate("yourVersion") .. currentVersion, "blue") + + for i = 1, #currentVersionSplitted do + local current, latest = tonumber(currentVersionSplitted[i]), tonumber(latestVersionSplitted[i]) + if current ~= latest then + if not current or not latest then + return + end + if current < latest then + HUD:InfoHandle(Translate("needUpdateResource"), "red") + else + break + end + end + end + end + end, + + RunVersionChecker = function() + CreateThread(function() + PerformHttpRequest(HUD.VersionCheckURL, VERSION.Check, "GET") + end) + end, +} + +RegisterNetEvent("esx_hud:ErrorHandle", function(msg) + HUD:ErrorHandle(msg) +end) + +AddEventHandler("onResourceStart", function(resourceName) + local currentName = GetCurrentResourceName() + if resourceName ~= currentName then + return + end + local built = LoadResourceFile(currentName, "./web/dist/index.html") + + Wait(100) + + --Run version checker + VERSION:RunVersionChecker() + + if not built then + CreateThread(function() + while true do + HUD:ErrorHandle(Translate("resource_not_built")) + Wait(10000) + end + end) + end +end) From 1a4be3aeb946b9b8a5e92fef94b55531b6e853a6 Mon Sep 17 00:00:00 2001 From: _Not_ Date: Sat, 4 Oct 2025 21:06:45 -0500 Subject: [PATCH 25/25] change: ESX Garage web interface to Vue 3 and initialize with Tailwind CSS --- [esx_addons]/esx_garage/client/main.lua | 10 +- [esx_addons]/esx_garage/fxmanifest.lua | 6 +- [esx_addons]/esx_garage/nui/css/app.css | 279 --- [esx_addons]/esx_garage/nui/css/index.css | 1 + .../esx_garage/nui/{ => fonts}/roboto.ttf | Bin [esx_addons]/esx_garage/nui/img/logo.png | Bin 0 -> 13632 bytes [esx_addons]/esx_garage/nui/index.html | 13 + [esx_addons]/esx_garage/nui/js/app.js | 230 -- [esx_addons]/esx_garage/nui/js/index.js | 17 + [esx_addons]/esx_garage/nui/ui.html | 33 - [esx_addons]/esx_garage/web/.gitignore | 25 + [esx_addons]/esx_garage/web/index.html | 13 + [esx_addons]/esx_garage/web/package-lock.json | 1887 +++++++++++++++++ [esx_addons]/esx_garage/web/package.json | 19 + .../esx_garage/web/public/fonts/roboto.ttf | Bin 0 -> 158604 bytes [esx_addons]/esx_garage/web/src/App.vue | 10 + .../esx_garage/web/src/assets/logo.png | Bin 0 -> 13632 bytes .../esx_garage/web/src/components/Main.vue | 83 + .../web/src/components/VehicleCard.vue | 45 + .../web/src/composables/useGarage.js | 147 ++ [esx_addons]/esx_garage/web/src/main.js | 5 + [esx_addons]/esx_garage/web/src/style.css | 82 + [esx_addons]/esx_garage/web/vite.config.js | 32 + 23 files changed, 2386 insertions(+), 551 deletions(-) delete mode 100644 [esx_addons]/esx_garage/nui/css/app.css create mode 100644 [esx_addons]/esx_garage/nui/css/index.css rename [esx_addons]/esx_garage/nui/{ => fonts}/roboto.ttf (100%) create mode 100644 [esx_addons]/esx_garage/nui/img/logo.png create mode 100644 [esx_addons]/esx_garage/nui/index.html delete mode 100644 [esx_addons]/esx_garage/nui/js/app.js create mode 100644 [esx_addons]/esx_garage/nui/js/index.js delete mode 100644 [esx_addons]/esx_garage/nui/ui.html create mode 100644 [esx_addons]/esx_garage/web/.gitignore create mode 100644 [esx_addons]/esx_garage/web/index.html create mode 100644 [esx_addons]/esx_garage/web/package-lock.json create mode 100644 [esx_addons]/esx_garage/web/package.json create mode 100644 [esx_addons]/esx_garage/web/public/fonts/roboto.ttf create mode 100644 [esx_addons]/esx_garage/web/src/App.vue create mode 100644 [esx_addons]/esx_garage/web/src/assets/logo.png create mode 100644 [esx_addons]/esx_garage/web/src/components/Main.vue create mode 100644 [esx_addons]/esx_garage/web/src/components/VehicleCard.vue create mode 100644 [esx_addons]/esx_garage/web/src/composables/useGarage.js create mode 100644 [esx_addons]/esx_garage/web/src/main.js create mode 100644 [esx_addons]/esx_garage/web/src/style.css create mode 100644 [esx_addons]/esx_garage/web/vite.config.js diff --git a/[esx_addons]/esx_garage/client/main.lua b/[esx_addons]/esx_garage/client/main.lua index bdc4d1ec..e5655132 100644 --- a/[esx_addons]/esx_garage/client/main.lua +++ b/[esx_addons]/esx_garage/client/main.lua @@ -242,8 +242,8 @@ CreateThread(function() SendNUIMessage({ showMenu = true, type = 'garage', - vehiclesList = {json.encode(vehiclesList)}, - vehiclesImpoundedList = {json.encode(vehiclesImpoundedList)}, + vehiclesList = json.encode(vehiclesList), + vehiclesImpoundedList = json.encode(vehiclesImpoundedList), poundName = v.ImpoundedName, poundSpawnPoint = poundSpawnPoint, spawnPoint = spawnPoint, @@ -260,7 +260,7 @@ CreateThread(function() SendNUIMessage({ showMenu = true, type = 'garage', - vehiclesList = {json.encode(vehiclesList)}, + vehiclesList = json.encode(vehiclesList), spawnPoint = spawnPoint, locales = { action = TranslateCap('veh_exit'), @@ -301,7 +301,7 @@ CreateThread(function() SendNUIMessage({ showMenu = true, type = 'garage', - vehiclesImpoundedList = {json.encode(vehiclesImpoundedList)}, + vehiclesImpoundedList = json.encode(vehiclesImpoundedList), poundName = v.ImpoundedName, poundSpawnPoint = poundSpawnPoint, locales = { @@ -390,7 +390,7 @@ CreateThread(function() SendNUIMessage({ showMenu = true, type = 'impound', - vehiclesList = {json.encode(vehiclesList)}, + vehiclesList = json.encode(vehiclesList), spawnPoint = spawnPoint, poundCost = v.Cost, locales = { diff --git a/[esx_addons]/esx_garage/fxmanifest.lua b/[esx_addons]/esx_garage/fxmanifest.lua index f9896fbf..82fe687e 100644 --- a/[esx_addons]/esx_garage/fxmanifest.lua +++ b/[esx_addons]/esx_garage/fxmanifest.lua @@ -8,13 +8,11 @@ version '1.0' legacyversion '1.13.4' lua54 'yes' +ui_page 'nui/index.html' +files { 'nui/index.html', 'nui/**/*' } shared_script '@es_extended/imports.lua' server_scripts { '@es_extended/locale.lua', 'locales/*.lua', '@oxmysql/lib/MySQL.lua', 'config.lua', 'server/main.lua' } client_scripts { '@es_extended/locale.lua', 'locales/*.lua', 'config.lua', 'client/main.lua' } - -ui_page 'nui/ui.html' - -files { 'nui/ui.html', 'nui/js/*.js', 'nui/css/*.css', 'nui/roboto.ttf' } diff --git a/[esx_addons]/esx_garage/nui/css/app.css b/[esx_addons]/esx_garage/nui/css/app.css deleted file mode 100644 index 7fa3eca6..00000000 --- a/[esx_addons]/esx_garage/nui/css/app.css +++ /dev/null @@ -1,279 +0,0 @@ -@font-face { - font-family: roboto; - src: url("../roboto.ttf"); -} - -body { - width: 100%; - height: 100%; - overflow: hidden; - font-family: roboto; -} - -#cursor { - position: absolute; - z-index: 999999; - display: none; -} - -#container { - position: absolute; - background: #232934; - border-radius: 10px; - border-top: 20px solid #353e4f; - height: 700px; - width: 1000px; - top: 40%; - left: 40%; - margin: -250px 0 0 -300px; - cursor: default; - display: flex; - flex-direction: unset; -} - -#header { - color: white; - font-size: 44px; - border-radius: 0px 0px 0px 10px; - background: #353e4f; - display: flex; - justify-content: space-between; - flex-direction: column; - align-items: baseline; -} - -#header .title { - padding: 50px; -} - -#header ul { - font-size: 15px; - margin-top: -150px; - padding: 0px; - list-style-type: none; -} - -#header li { - cursor: pointer; - padding: 15px; - width: 296px; -} - -#header li:hover { - font-weight: bold; - background-color: rgba(0, 0, 0, 0.356); - border-right: 3px solid #7186ad; -} -#header li.selected { - font-weight: bold; - background-color: rgba(0, 0, 0, 0.356); - border-right: 3px solid #7186ad; -} - -#header .close { - float: right; - text-align: center; - color: #b90000; - font-size: 20px; - font-weight: bold; - padding: 5px 5px; - background: #00000026; - border: 1px solid #00000026; - border-radius: 3px; - cursor: pointer; - border-radius: 50%; - -moz-border-radius: 50%; - -webkit-border-radius: 50%; - height: 25px; - width: 25px; - margin: 30px 144px; -} - -#header .close:hover { - color: #df3d3d; - background: #00000041; -} - -.clear-both { - clear: both; -} - -#menu { - display: flex; - flex-direction: row; - justify-content: space-between; -} - -.right-side { - width: 50%; -} - -.content { - width: 100%; - margin: 20px; - color: white; - height: 655px; - overflow-y: auto; - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ -} - -.content h2 { - width: 290px; - height: 290px; - position: absolute; - top: 50%; - left: 55%; - margin: -25px 0 0 -25px; - text-align: center; -} - -.content::-webkit-scrollbar { - display: none; -} - -.impounded_content { - display: none; - width: 100%; - margin: 20px; - color: white; - height: 655px; - overflow-y: auto; - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ -} - -.impounded_content h2 { - width: 290px; - height: 290px; - position: absolute; - top: 50%; - left: 55%; - margin: -25px 0 0 -25px; - text-align: center; -} - -.impounded_content::-webkit-scrollbar { - display: none; -} - -.webgl { - position: fixed; - left: 0; - top: 0; - outline: none; -} - -.content .vehicle-header { - display: flex; - justify-content: space-between; - padding: 5px 20px; -} - -.group { - margin: 20px; - color: white; - display: flex; - flex-direction: column; - margin-bottom: 20px; - padding: 10px; - border: solid #353e4f 2px; - border-radius: 10px; -} - -.group > button { - color: white; - width: 50%; - padding: 12px 20px; - margin: 8px 0; - border: 1px solid #353e4f; - border-radius: 4px; - background-color: #353e4f; -} - -.group > input { - color: white; - width: 100%; - padding: 12px 20px; - margin: 8px 0; - background-color: #353e4f; - border: none; - border-radius: 4px; - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; -} - -.group > input::-webkit-outer-spin-button, -input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -.vehicle-listing { - display: inline-block; - flex-direction: row; - border: 1px solid #353e4f; - border-left: 5px solid #353e4f; - border-radius: 3px; - margin: 5px; - padding: 20px 35px; - font-size: 18px; - text-align: center; - width: 229px; -} - -.vehicle-listing div { - display: flow-root; - justify-content: space-between; - align-content: space-between; -} - -.vehicle-listing strong { - display: inline-block; -} - -.vehicle-listing:hover { - background: #353e4f; - border: 1px solid #353e4f; - border-left: 5px solid #353e4f; -} - -.unstyled-button { - padding: 0; - border: none; - background: none; - outline: none; -} - -.vehicle-action { - background: linear-gradient(to bottom, #77b55a 5%, #72b352 100%); - background-color: #77b55a; - border-radius: 3px; - border: 1px solid #4b8f29; - display: inline-block; - cursor: pointer; - color: #ffffff; - font-size: 17px; - font-weight: bold; - padding: 20px 30px; - margin: 15px; - text-shadow: -1px 1px 2px #00000026; -} - -.vehicle-action:hover { - background: linear-gradient(to bottom, #72b352 5%, #77b55a 100%); - background-color: #72b352; -} - -.vehicle-action.red { - border: 1px solid #8f2929; - background: linear-gradient(to bottom, #b55a5a 5%, #b35252 100%); - background-color: #b55a5a; -} - -.vehicle-action.red:hover { - border: 1px solid #8f2c29; - background: linear-gradient(to bottom, #b55a5a 5%, #b35852 100%); - background-color: #b55a5a; -} diff --git a/[esx_addons]/esx_garage/nui/css/index.css b/[esx_addons]/esx_garage/nui/css/index.css new file mode 100644 index 00000000..2ceee44a --- /dev/null +++ b/[esx_addons]/esx_garage/nui/css/index.css @@ -0,0 +1 @@ +/*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}}@font-face{font-family:Roboto;src:url(../fonts/roboto.ttf)format("truetype");font-display:swap}:root{--brand:#fb9b04;--darkest:#161616;--dark:#252525;--mid:#383838;--light:#969696;--lightest:#f2f2f2;--toolbar-h:50px;--radius-lg:16px;--radius-md:12px;--radius-sm:8px;--shadow-1:0 10px 30px #00000059;--shadow-2:0 6px 18px #00000040;--transition-fast:.16s cubic-bezier(.2,.7,.2,1);--transition-med:.26s cubic-bezier(.2,.7,.2,1)}html,body{background:0 0;width:100%;height:100%}body{color:var(--lightest);background:0 0;margin:0;font:500 14px/1.45 Roboto,system-ui,-apple-system,Segoe UI,Arial,sans-serif;overflow:hidden}#container{background:linear-gradient(180deg,var(--dark),var(--darkest));border-radius:var(--radius-lg);width:min(1000px,100vw - 64px);height:min(700px,100vh - 64px);box-shadow:var(--shadow-1);border:1px solid #ffffff0f;grid-template-rows:1fr;grid-template-columns:280px 1fr;display:none;position:absolute;top:50%;left:50%;overflow:hidden;transform:translate(-50%,-50%)}#container[style*="display:grid"]{display:grid!important}#container:before{content:"";z-index:0;background:linear-gradient(90deg,#fb9b043d,#0000 40%),linear-gradient(#ffffff0f,#0000);border-bottom:1px solid #ffffff0f;height:56px;position:absolute;top:0;left:0;right:0}#header{grid-column:1/2;padding-top:56px;position:relative}#header .title{letter-spacing:.2px;color:var(--lightest);z-index:1;padding:18px 20px 10px;font-size:20px;font-weight:700}#header .close{width:36px;height:36px;color:var(--lightest);cursor:pointer;transition:transform var(--transition-fast),background var(--transition-fast),border-color var(--transition-fast);background:#ffffff0f;border:1px solid #ffffff14;border-radius:50%;place-items:center;font-size:18px;display:grid;position:absolute;top:28px;right:14px;transform:translateY(-50%)}#header .close:hover{background:#fb9b0426;border-color:#fb9b0459}#header ul{z-index:1;flex-direction:column;gap:6px;margin:8px 0 0;padding:10px 8px 8px 12px;list-style:none;display:flex}#header li{cursor:pointer;box-sizing:border-box;width:100%;color:var(--lightest);border-radius:var(--radius-md);transition:background var(--transition-fast),border-color var(--transition-fast),color var(--transition-fast);border:1px solid #0000;align-items:center;gap:10px;padding:12px 0 12px 22px;display:flex;position:relative}#header li:before{content:"";background:0 0;border-radius:4px;width:4px;height:60%;position:absolute;top:50%;left:6px;transform:translateY(-50%)}#header li:hover{background:#38383873;border-color:#ffffff14}#header li.selected{color:var(--lightest);background:#38383899;border-color:#fb9b0473}#header li.selected:before{background:var(--brand)}#menu{box-sizing:border-box;flex-direction:column;grid-column:2/-1;height:100%;min-height:0;padding-top:56px;padding-left:8px;display:flex;overflow:hidden}.content,.impounded_content{width:100%;min-height:0;color:var(--lightest);flex-direction:column;flex:auto;display:flex;overflow:hidden}.content .empty,.impounded_content .empty{opacity:.7;text-align:center;margin-top:18vh;font-weight:500}.content .vehicle-list,.impounded_content .vehicle-list{-ms-overflow-style:none;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;min-height:0;height:calc(100% - var(--toolbar-h));box-sizing:border-box;flex:1;grid-template-columns:repeat(2,1fr);grid-auto-rows:auto;align-content:start;place-items:start stretch;gap:36px 12px;width:96%;max-width:96%;margin:0 auto;padding:10px 0 0;display:grid;overflow:hidden scroll}.content .vehicle-list:after,.impounded_content .vehicle-list:after{content:"";display:block}@media (max-width:820px){.content .vehicle-list,.impounded_content .vehicle-list{grid-template-columns:1fr}}.toolbar{box-sizing:border-box;width:96%;height:var(--toolbar-h);flex:none;align-items:center;margin:0 auto;padding:10px 0 0;display:flex;overflow:hidden}.toolbar input[type=search]{border-radius:var(--radius-sm);width:100%;height:100%;color:var(--lightest);background:#3838388c;border:1px solid #ffffff14;outline:none;flex:auto;padding:10px 12px;display:block}.toolbar input[type=search]::placeholder{color:#f2f2f28c}.toolbar input[type=search]:focus{border-color:#fb9b048c;box-shadow:0 0 0 3px #fb9b041f}.vehicle-listing{border-radius:var(--radius-md);box-sizing:border-box;z-index:0;width:100%;min-height:148px;transition:border-color var(--transition-fast),box-shadow var(--transition-fast);background:linear-gradient(#38383873,#252525d9);border:1px solid #ffffff0f;flex-direction:column;gap:10px;padding:16px;display:flex;position:relative}.vehicle-listing:hover{box-shadow:var(--shadow-2);z-index:1;border-color:#fb9b0473}.vehicle-listing div{color:var(--lightest);justify-content:space-between;align-items:center;display:flex}.vehicle-listing strong{color:var(--lightest)}.condition{align-items:center;gap:8px;display:flex}.condition .bar{background:#ffffff14;border-radius:999px;flex:1;height:8px;overflow:hidden}.condition .fill{background:linear-gradient(90deg,#ffad2e,var(--brand));width:0%;height:100%;transition:width var(--transition-med);border-radius:999px}.condition .percent{display:inline-block}.unstyled-button{font:inherit;color:inherit;background:0 0;border:none;padding:0}.vehicle-action{border-radius:var(--radius-sm);color:var(--darkest);background:linear-gradient(180deg,#ffad2e,var(--brand));letter-spacing:.2px;cursor:pointer;transition:transform var(--transition-fast),box-shadow var(--transition-fast),background var(--transition-fast),border-color var(--transition-fast);border:1px solid #ffffff14;justify-content:center;align-self:stretch;align-items:center;gap:8px;padding:12px 14px;font-weight:700;display:inline-flex}.vehicle-action:hover{border-color:#fb9b048c;transform:translateY(-1px);box-shadow:0 6px 18px #fb9b0440}.vehicle-action.red{color:var(--lightest);background:linear-gradient(#d87070,#b35252);border-color:#ffffff14}.vehicle-action.red:hover{border-color:#b352528c;box-shadow:0 6px 18px #b3525240}.logo-left{filter:drop-shadow(0 4px 14px #00000059);-webkit-user-select:none;user-select:none;pointer-events:none;width:auto;height:32px;position:absolute;top:28px;left:16px;transform:translateY(-50%)}.content .vehicle-list,.impounded_content .vehicle-list{scrollbar-width:none}.content .vehicle-list::-webkit-scrollbar{width:0!important;height:0!important}.impounded_content .vehicle-list::-webkit-scrollbar{width:0!important;height:0!important}@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}#header{position:static}#header .close{z-index:10;position:absolute;top:28px;right:14px}::selection{color:inherit;background:0 0}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}.logo[data-v-9a622185]{height:6em;padding:1.5em;will-change:filter;transition:filter .3s}.logo[data-v-9a622185]:hover{filter:drop-shadow(0 0 2em #646cffaa)}.logo.vue[data-v-9a622185]:hover{filter:drop-shadow(0 0 2em #42b883aa)} diff --git a/[esx_addons]/esx_garage/nui/roboto.ttf b/[esx_addons]/esx_garage/nui/fonts/roboto.ttf similarity index 100% rename from [esx_addons]/esx_garage/nui/roboto.ttf rename to [esx_addons]/esx_garage/nui/fonts/roboto.ttf diff --git a/[esx_addons]/esx_garage/nui/img/logo.png b/[esx_addons]/esx_garage/nui/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e08a82bfce6825965bacd70f35f329d4ccc8a125 GIT binary patch literal 13632 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 Vew`HvxU%t)p|0t9(%GxG{~w$1y$t{W literal 0 HcmV?d00001 diff --git a/[esx_addons]/esx_garage/nui/index.html b/[esx_addons]/esx_garage/nui/index.html new file mode 100644 index 00000000..f5230dce --- /dev/null +++ b/[esx_addons]/esx_garage/nui/index.html @@ -0,0 +1,13 @@ + + + + + + ESX + + + + +
+ + diff --git a/[esx_addons]/esx_garage/nui/js/app.js b/[esx_addons]/esx_garage/nui/js/app.js deleted file mode 100644 index 104a5cbe..00000000 --- a/[esx_addons]/esx_garage/nui/js/app.js +++ /dev/null @@ -1,230 +0,0 @@ -$(window).ready(function () { - window.addEventListener("message", function (event) { - let data = event.data; - - if (data.showMenu) { - $("#container").fadeIn(); - $("#menu").fadeIn(); - - if (data.type === "impound") { - $("#header ul").hide(); - } else { - $("#header ul").show(); - } - - if (data.vehiclesList != undefined) { - $("#container").data("spawnpoint", data.spawnPoint); - if (data.poundCost) $("#container").data("poundcost", data.poundCost); - - if (data.poundCost != undefined) { - $(".content .vehicle-list").html( - getVehicles(data.locales, data.vehiclesList, data.poundCost) - ); - } else { - $(".content .vehicle-list").html( - getVehicles(data.locales, data.vehiclesList) - ); - } - - $(".content h2").hide(); - } else { - $(".content h2").show(); - $(".content .vehicle-list").empty(); - } - - if (data.vehiclesImpoundedList != undefined) { - $(".impounded_content").data("poundName", data.poundName); - $(".impounded_content").data("poundSpawnPoint", data.poundSpawnPoint); - - if (data.poundCost) $("#container").data("poundcost", data.poundCost); - - $(".impounded_content .vehicle-list").html( - getImpoundedVehicles(data.locales, data.vehiclesImpoundedList) - ); - $(".impounded_content h2").hide(); - } else { - $(".impounded_content h2").show(); - $(".impounded_content .vehicle-list").empty(); - } - - // Locales - - // needs a rework - // $(".content h2").html(function (i, text) { - // return text.replace("No vehicle in this garage.", data.locales.no_veh_parking); - // }); - - // $(".impounded_content h2").html(function (i, text) { - // return text.replace("No vehicle impounded.", data.locales.no_veh_impounded); - // }); - - $(".vehicle-listing").html(function (i, text) { - return text.replace("Model", data.locales.veh_model); - }); - $(".vehicle-listing").html(function (i, text) { - return text.replace("Plate", data.locales.veh_plate); - }); - $(".vehicle-listing").html(function (i, text) { - return text.replace("Condition", data.locales.veh_condition); - }); - } else if (data.hideAll) { - $("#container").fadeOut(); - } - }); - - $("#container").hide(); - - $(".close").click(function (event) { - $("#container").hide(); - $.post("https://esx_garage/escape", "{}"); - - $(".impounded_content").hide(); - $(".content").show(); - $('li[data-page="garage"]').addClass("selected"); - $('li[data-page="impounded"]').removeClass("selected"); - }); - - document.onkeyup = function (data) { - if (data.which == 27) { - $.post("https://esx_garage/escape", "{}"); - - $(".impounded_content").hide(); - $(".content").show(); - $('li[data-page="garage"]').addClass("selected"); - $('li[data-page="impounded"]').removeClass("selected"); - } - }; - - function getVehicles(locale, vehicle, amount = null) { - let html = ""; - let vehicleData = JSON.parse(vehicle); - let bodyHealth = 1000; - let engineHealth = 1000; - let tankHealth = 1000; - let vehicleDamagePercent = ""; - - for (let i = 0; i < vehicleData.length; i++) { - bodyHealth = (vehicleData[i].props.bodyHealth / 1000) * 100; - engineHealth = (vehicleData[i].props.engineHealth / 1000) * 100; - tankHealth = (vehicleData[i].props.tankHealth / 1000) * 100; - - vehicleDamagePercent = - Math.round(((bodyHealth + engineHealth + tankHealth) / 300) * 100) + - "%"; - - html += "
"; - html += "
Model: " + vehicleData[i].model + "
"; - html += "
Plate: " + vehicleData[i].plate + "
"; - html += - "
Condition: " + vehicleDamagePercent + "
"; - html += - ""; - html += "
"; - } - - return html; - } - - function getImpoundedVehicles(locale, vehicle) { - let html = ""; - let vehicleData = JSON.parse(vehicle); - let bodyHealth = 1000; - let engineHealth = 1000; - let tankHealth = 1000; - let vehicleDamagePercent = ""; - - for (let i = 0; i < vehicleData.length; i++) { - bodyHealth = (vehicleData[i].props.bodyHealth / 1000) * 100; - engineHealth = (vehicleData[i].props.engineHealth / 1000) * 100; - tankHealth = (vehicleData[i].props.tankHealth / 1000) * 100; - - vehicleDamagePercent = - Math.round(((bodyHealth + engineHealth + tankHealth) / 300) * 100) + - "%"; - - html += "
"; - html += "
Model: " + vehicleData[i].model + "
"; - html += "
Plate: " + vehicleData[i].plate + "
"; - html += - "
Condition: " + vehicleDamagePercent + "
"; - html += - ""; - html += "
"; - } - - return html; - } - - $('li[data-page="garage"]').click(function (event) { - $(".impounded_content").hide(); - $(".content").show(); - $('li[data-page="garage"]').addClass("selected"); - $('li[data-page="impounded"]').removeClass("selected"); - }); - - $('li[data-page="impounded"]').click(function (event) { - $(".content").hide(); - $(".impounded_content").show(); - $('li[data-page="impounded"]').addClass("selected"); - $('li[data-page="garage"]').removeClass("selected"); - }); - - $(document).on( - "click", - "button[data-button='spawn'].vehicle-action", - function (event) { - let spawnPoint = $("#container").data("spawnpoint"); - let poundCost = $("#container").data("poundcost"); - let vehicleProps = $(this).data("vehprops"); - - // prevent empty cost - if (poundCost === undefined) poundCost = 0; - - $.post( - "https://esx_garage/spawnVehicle", - JSON.stringify({ - vehicleProps: vehicleProps, - spawnPoint: spawnPoint, - exitVehicleCost: poundCost, - }) - ); - - $(".impounded_content").hide(); - $(".content").show(); - $('li[data-page="garage"]').addClass("selected"); - $('li[data-page="impounded"]').removeClass("selected"); - } - ); - - $(document).on( - "click", - "button[data-button='impounded'].vehicle-action", - function (event) { - let vehicleProps = $(this).data("vehprops"); - let poundName = $(".impounded_content").data("poundName"); - let poundSpawnPoint = $(".impounded_content").data("poundSpawnPoint"); - $.post( - "https://esx_garage/impound", - JSON.stringify({ - vehicleProps: vehicleProps, - poundName: poundName, - poundSpawnPoint: poundSpawnPoint, - }) - ); - - $(".impounded_content").hide(); - $(".content").show(); - $('li[data-page="garage"]').addClass("selected"); - $('li[data-page="impounded"]').removeClass("selected"); - } - ); -}); diff --git a/[esx_addons]/esx_garage/nui/js/index.js b/[esx_addons]/esx_garage/nui/js/index.js new file mode 100644 index 00000000..2e11639d --- /dev/null +++ b/[esx_addons]/esx_garage/nui/js/index.js @@ -0,0 +1,17 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))s(i);new MutationObserver(i=>{for(const r of i)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const r={};return i.integrity&&(r.integrity=i.integrity),i.referrerPolicy&&(r.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?r.credentials="include":i.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(i){if(i.ep)return;i.ep=!0;const r=n(i);fetch(i.href,r)}})();/** +* @vue/shared v3.5.22 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function Kn(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const K={},rt=[],Te=()=>{},Us=()=>!1,rn=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Bn=e=>e.startsWith("onUpdate:"),re=Object.assign,Wn=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},ki=Object.prototype.hasOwnProperty,j=(e,t)=>ki.call(e,t),M=Array.isArray,ot=e=>on(e)==="[object Map]",Ks=e=>on(e)==="[object Set]",R=e=>typeof e=="function",Y=e=>typeof e=="string",Ke=e=>typeof e=="symbol",q=e=>e!==null&&typeof e=="object",Bs=e=>(q(e)||R(e))&&R(e.then)&&R(e.catch),Ws=Object.prototype.toString,on=e=>Ws.call(e),Xi=e=>on(e).slice(8,-1),Gs=e=>on(e)==="[object Object]",Gn=e=>Y(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,xt=Kn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),ln=e=>{const t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},Zi=/-\w/g,Ve=ln(e=>e.replace(Zi,t=>t.slice(1).toUpperCase())),Qi=/\B([A-Z])/g,et=ln(e=>e.replace(Qi,"-$1").toLowerCase()),qs=ln(e=>e.charAt(0).toUpperCase()+e.slice(1)),yn=ln(e=>e?`on${qs(e)}`:""),ke=(e,t)=>!Object.is(e,t),Wt=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:s,value:n})},In=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let fs;const cn=()=>fs||(fs=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function fn(e){if(M(e)){const t={};for(let n=0;n{if(n){const s=n.split(tr);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function ut(e){let t="";if(Y(e))t=e;else if(M(e))for(let n=0;n!!(e&&e.__v_isRef===!0),te=e=>Y(e)?e:e==null?"":M(e)||q(e)&&(e.toString===Ws||!R(e.toString))?zs(e)?te(e.value):JSON.stringify(e,ks,2):String(e),ks=(e,t)=>zs(t)?ks(e,t.value):ot(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,i],r)=>(n[vn(s,r)+" =>"]=i,n),{})}:Ks(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>vn(n))}:Ke(t)?vn(t):q(t)&&!M(t)&&!Gs(t)?String(t):t,vn=(e,t="")=>{var n;return Ke(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** +* @vue/reactivity v3.5.22 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let ce;class or{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=ce,!t&&ce&&(this.index=(ce.scopes||(ce.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0&&--this._on===0&&(ce=this.prevScope,this.prevScope=void 0)}stop(t){if(this._active){this._active=!1;let n,s;for(n=0,s=this.effects.length;n0)return;if(wt){let t=wt;for(wt=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;St;){let t=St;for(St=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(s){e||(e=s)}t=n}}if(e)throw e}function ei(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function ti(e){let t,n=e.depsTail,s=n;for(;s;){const i=s.prevDep;s.version===-1?(s===n&&(n=i),Yn(s),cr(s)):t=s,s.dep.activeLink=s.prevActiveLink,s.prevActiveLink=void 0,s=i}e.deps=t,e.depsTail=n}function Rn(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(ni(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function ni(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===At)||(e.globalVersion=At,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Rn(e))))return;e.flags|=2;const t=e.dep,n=G,s=ge;G=e,ge=!0;try{ei(e);const i=e.fn(e._value);(t.version===0||ke(i,e._value))&&(e.flags|=128,e._value=i,t.version++)}catch(i){throw t.version++,i}finally{G=n,ge=s,ti(e),e.flags&=-3}}function Yn(e,t=!1){const{dep:n,prevSub:s,nextSub:i}=e;if(s&&(s.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=s,e.nextSub=void 0),n.subs===e&&(n.subs=s,!s&&n.computed)){n.computed.flags&=-5;for(let r=n.computed.deps;r;r=r.nextDep)Yn(r,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function cr(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let ge=!0;const si=[];function Re(){si.push(ge),ge=!1}function Fe(){const e=si.pop();ge=e===void 0?!0:e}function us(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=G;G=void 0;try{t()}finally{G=n}}}let At=0;class fr{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class ii{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!G||!ge||G===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==G)n=this.activeLink=new fr(G,this),G.deps?(n.prevDep=G.depsTail,G.depsTail.nextDep=n,G.depsTail=n):G.deps=G.depsTail=n,ri(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const s=n.nextDep;s.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=s),n.prevDep=G.depsTail,n.nextDep=void 0,G.depsTail.nextDep=n,G.depsTail=n,G.deps===n&&(G.deps=s)}return n}trigger(t){this.version++,At++,this.notify(t)}notify(t){qn();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{Jn()}}}function ri(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let s=t.deps;s;s=s.nextDep)ri(s)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const Yt=new WeakMap,Xe=Symbol(""),Fn=Symbol(""),Pt=Symbol("");function Z(e,t,n){if(ge&&G){let s=Yt.get(e);s||Yt.set(e,s=new Map);let i=s.get(n);i||(s.set(n,i=new ii),i.map=s,i.key=n),i.track()}}function Pe(e,t,n,s,i,r){const o=Yt.get(e);if(!o){At++;return}const l=f=>{f&&f.trigger()};if(qn(),t==="clear")o.forEach(l);else{const f=M(e),h=f&&Gn(n);if(f&&n==="length"){const a=Number(s);o.forEach((p,m)=>{(m==="length"||m===Pt||!Ke(m)&&m>=a)&&l(p)})}else switch((n!==void 0||o.has(void 0))&&l(o.get(n)),h&&l(o.get(Pt)),t){case"add":f?h&&l(o.get("length")):(l(o.get(Xe)),ot(e)&&l(o.get(Fn)));break;case"delete":f||(l(o.get(Xe)),ot(e)&&l(o.get(Fn)));break;case"set":ot(e)&&l(o.get(Xe));break}}Jn()}function ur(e,t){const n=Yt.get(e);return n&&n.get(t)}function tt(e){const t=U(e);return t===e?t:(Z(t,"iterate",Pt),me(e)?t:t.map(ne))}function un(e){return Z(e=U(e),"iterate",Pt),e}const ar={__proto__:null,[Symbol.iterator](){return Sn(this,Symbol.iterator,ne)},concat(...e){return tt(this).concat(...e.map(t=>M(t)?tt(t):t))},entries(){return Sn(this,"entries",e=>(e[1]=ne(e[1]),e))},every(e,t){return Oe(this,"every",e,t,void 0,arguments)},filter(e,t){return Oe(this,"filter",e,t,n=>n.map(ne),arguments)},find(e,t){return Oe(this,"find",e,t,ne,arguments)},findIndex(e,t){return Oe(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Oe(this,"findLast",e,t,ne,arguments)},findLastIndex(e,t){return Oe(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Oe(this,"forEach",e,t,void 0,arguments)},includes(...e){return wn(this,"includes",e)},indexOf(...e){return wn(this,"indexOf",e)},join(e){return tt(this).join(e)},lastIndexOf(...e){return wn(this,"lastIndexOf",e)},map(e,t){return Oe(this,"map",e,t,void 0,arguments)},pop(){return mt(this,"pop")},push(...e){return mt(this,"push",e)},reduce(e,...t){return as(this,"reduce",e,t)},reduceRight(e,...t){return as(this,"reduceRight",e,t)},shift(){return mt(this,"shift")},some(e,t){return Oe(this,"some",e,t,void 0,arguments)},splice(...e){return mt(this,"splice",e)},toReversed(){return tt(this).toReversed()},toSorted(e){return tt(this).toSorted(e)},toSpliced(...e){return tt(this).toSpliced(...e)},unshift(...e){return mt(this,"unshift",e)},values(){return Sn(this,"values",ne)}};function Sn(e,t,n){const s=un(e),i=s[t]();return s!==e&&!me(e)&&(i._next=i.next,i.next=()=>{const r=i._next();return r.done||(r.value=n(r.value)),r}),i}const dr=Array.prototype;function Oe(e,t,n,s,i,r){const o=un(e),l=o!==e&&!me(e),f=o[t];if(f!==dr[t]){const p=f.apply(e,r);return l?ne(p):p}let h=n;o!==e&&(l?h=function(p,m){return n.call(this,ne(p),m,e)}:n.length>2&&(h=function(p,m){return n.call(this,p,m,e)}));const a=f.call(o,h,s);return l&&i?i(a):a}function as(e,t,n,s){const i=un(e);let r=n;return i!==e&&(me(e)?n.length>3&&(r=function(o,l,f){return n.call(this,o,l,f,e)}):r=function(o,l,f){return n.call(this,o,ne(l),f,e)}),i[t](r,...s)}function wn(e,t,n){const s=U(e);Z(s,"iterate",Pt);const i=s[t](...n);return(i===-1||i===!1)&&Xn(n[0])?(n[0]=U(n[0]),s[t](...n)):i}function mt(e,t,n=[]){Re(),qn();const s=U(e)[t].apply(e,n);return Jn(),Fe(),s}const hr=Kn("__proto__,__v_isRef,__isVue"),oi=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ke));function pr(e){Ke(e)||(e=String(e));const t=U(this);return Z(t,"has",e),t.hasOwnProperty(e)}class li{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,s){if(n==="__v_skip")return t.__v_skip;const i=this._isReadonly,r=this._isShallow;if(n==="__v_isReactive")return!i;if(n==="__v_isReadonly")return i;if(n==="__v_isShallow")return r;if(n==="__v_raw")return s===(i?r?Cr:ai:r?ui:fi).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(s)?t:void 0;const o=M(t);if(!i){let f;if(o&&(f=ar[n]))return f;if(n==="hasOwnProperty")return pr}const l=Reflect.get(t,n,X(t)?t:s);if((Ke(n)?oi.has(n):hr(n))||(i||Z(t,"get",n),r))return l;if(X(l)){const f=o&&Gn(n)?l:l.value;return i&&q(f)?Nn(f):f}return q(l)?i?Nn(l):an(l):l}}class ci extends li{constructor(t=!1){super(!1,t)}set(t,n,s,i){let r=t[n];if(!this._isShallow){const f=Ze(r);if(!me(s)&&!Ze(s)&&(r=U(r),s=U(s)),!M(t)&&X(r)&&!X(s))return f||(r.value=s),!0}const o=M(t)&&Gn(n)?Number(n)e,Vt=e=>Reflect.getPrototypeOf(e);function yr(e,t,n){return function(...s){const i=this.__v_raw,r=U(i),o=ot(r),l=e==="entries"||e===Symbol.iterator&&o,f=e==="keys"&&o,h=i[e](...s),a=n?Ln:t?zt:ne;return!t&&Z(r,"iterate",f?Fn:Xe),{next(){const{value:p,done:m}=h.next();return m?{value:p,done:m}:{value:l?[a(p[0]),a(p[1])]:a(p),done:m}},[Symbol.iterator](){return this}}}}function Ut(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function vr(e,t){const n={get(i){const r=this.__v_raw,o=U(r),l=U(i);e||(ke(i,l)&&Z(o,"get",i),Z(o,"get",l));const{has:f}=Vt(o),h=t?Ln:e?zt:ne;if(f.call(o,i))return h(r.get(i));if(f.call(o,l))return h(r.get(l));r!==o&&r.get(i)},get size(){const i=this.__v_raw;return!e&&Z(U(i),"iterate",Xe),i.size},has(i){const r=this.__v_raw,o=U(r),l=U(i);return e||(ke(i,l)&&Z(o,"has",i),Z(o,"has",l)),i===l?r.has(i):r.has(i)||r.has(l)},forEach(i,r){const o=this,l=o.__v_raw,f=U(l),h=t?Ln:e?zt:ne;return!e&&Z(f,"iterate",Xe),l.forEach((a,p)=>i.call(r,h(a),h(p),o))}};return re(n,e?{add:Ut("add"),set:Ut("set"),delete:Ut("delete"),clear:Ut("clear")}:{add(i){!t&&!me(i)&&!Ze(i)&&(i=U(i));const r=U(this);return Vt(r).has.call(r,i)||(r.add(i),Pe(r,"add",i,i)),this},set(i,r){!t&&!me(r)&&!Ze(r)&&(r=U(r));const o=U(this),{has:l,get:f}=Vt(o);let h=l.call(o,i);h||(i=U(i),h=l.call(o,i));const a=f.call(o,i);return o.set(i,r),h?ke(r,a)&&Pe(o,"set",i,r):Pe(o,"add",i,r),this},delete(i){const r=U(this),{has:o,get:l}=Vt(r);let f=o.call(r,i);f||(i=U(i),f=o.call(r,i)),l&&l.call(r,i);const h=r.delete(i);return f&&Pe(r,"delete",i,void 0),h},clear(){const i=U(this),r=i.size!==0,o=i.clear();return r&&Pe(i,"clear",void 0,void 0),o}}),["keys","values","entries",Symbol.iterator].forEach(i=>{n[i]=yr(i,e,t)}),n}function zn(e,t){const n=vr(e,t);return(s,i,r)=>i==="__v_isReactive"?!e:i==="__v_isReadonly"?e:i==="__v_raw"?s:Reflect.get(j(n,i)&&i in s?n:s,i,r)}const xr={get:zn(!1,!1)},Sr={get:zn(!1,!0)},wr={get:zn(!0,!1)};const fi=new WeakMap,ui=new WeakMap,ai=new WeakMap,Cr=new WeakMap;function Tr(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Er(e){return e.__v_skip||!Object.isExtensible(e)?0:Tr(Xi(e))}function an(e){return Ze(e)?e:kn(e,!1,mr,xr,fi)}function Or(e){return kn(e,!1,br,Sr,ui)}function Nn(e){return kn(e,!0,_r,wr,ai)}function kn(e,t,n,s,i){if(!q(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const r=Er(e);if(r===0)return e;const o=i.get(e);if(o)return o;const l=new Proxy(e,r===2?s:n);return i.set(e,l),l}function lt(e){return Ze(e)?lt(e.__v_raw):!!(e&&e.__v_isReactive)}function Ze(e){return!!(e&&e.__v_isReadonly)}function me(e){return!!(e&&e.__v_isShallow)}function Xn(e){return e?!!e.__v_raw:!1}function U(e){const t=e&&e.__v_raw;return t?U(t):e}function Ar(e){return!j(e,"__v_skip")&&Object.isExtensible(e)&&Js(e,"__v_skip",!0),e}const ne=e=>q(e)?an(e):e,zt=e=>q(e)?Nn(e):e;function X(e){return e?e.__v_isRef===!0:!1}function H(e){return X(e)?e.value:e}const Pr={get:(e,t,n)=>t==="__v_raw"?e:H(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const i=e[t];return X(i)&&!X(n)?(i.value=n,!0):Reflect.set(e,t,n,s)}};function di(e){return lt(e)?e:new Proxy(e,Pr)}function Mr(e){const t=M(e)?new Array(e.length):{};for(const n in e)t[n]=Rr(e,n);return t}class Ir{constructor(t,n,s){this._object=t,this._key=n,this._defaultValue=s,this.__v_isRef=!0,this._value=void 0}get value(){const t=this._object[this._key];return this._value=t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return ur(U(this._object),this._key)}}function Rr(e,t,n){const s=e[t];return X(s)?s:new Ir(e,t,n)}class Fr{constructor(t,n,s){this.fn=t,this.setter=n,this._value=void 0,this.dep=new ii(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=At-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=s}notify(){if(this.flags|=16,!(this.flags&8)&&G!==this)return Qs(this,!0),!0}get value(){const t=this.dep.track();return ni(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Lr(e,t,n=!1){let s,i;return R(e)?s=e:(s=e.get,i=e.set),new Fr(s,i,n)}const Kt={},kt=new WeakMap;let Ye;function Nr(e,t=!1,n=Ye){if(n){let s=kt.get(n);s||kt.set(n,s=[]),s.push(e)}}function Dr(e,t,n=K){const{immediate:s,deep:i,once:r,scheduler:o,augmentJob:l,call:f}=n,h=A=>i?A:me(A)||i===!1||i===0?Me(A,1):Me(A);let a,p,m,v,I=!1,O=!1;if(X(e)?(p=()=>e.value,I=me(e)):lt(e)?(p=()=>h(e),I=!0):M(e)?(O=!0,I=e.some(A=>lt(A)||me(A)),p=()=>e.map(A=>{if(X(A))return A.value;if(lt(A))return h(A);if(R(A))return f?f(A,2):A()})):R(e)?t?p=f?()=>f(e,2):e:p=()=>{if(m){Re();try{m()}finally{Fe()}}const A=Ye;Ye=a;try{return f?f(e,3,[v]):e(v)}finally{Ye=A}}:p=Te,t&&i){const A=p,k=i===!0?1/0:i;p=()=>Me(A(),k)}const z=lr(),N=()=>{a.stop(),z&&z.active&&Wn(z.effects,a)};if(r&&t){const A=t;t=(...k)=>{A(...k),N()}}let F=O?new Array(e.length).fill(Kt):Kt;const L=A=>{if(!(!(a.flags&1)||!a.dirty&&!A))if(t){const k=a.run();if(i||I||(O?k.some((Ne,_e)=>ke(Ne,F[_e])):ke(k,F))){m&&m();const Ne=Ye;Ye=a;try{const _e=[k,F===Kt?void 0:O&&F[0]===Kt?[]:F,v];F=k,f?f(t,3,_e):t(..._e)}finally{Ye=Ne}}}else a.run()};return l&&l(L),a=new Xs(p),a.scheduler=o?()=>o(L,!1):L,v=A=>Nr(A,!1,a),m=a.onStop=()=>{const A=kt.get(a);if(A){if(f)f(A,4);else for(const k of A)k();kt.delete(a)}},t?s?L(!0):F=a.run():o?o(L.bind(null,!0),!0):a.run(),N.pause=a.pause.bind(a),N.resume=a.resume.bind(a),N.stop=N,N}function Me(e,t=1/0,n){if(t<=0||!q(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,X(e))Me(e.value,t,n);else if(M(e))for(let s=0;s{Me(s,t,n)});else if(Gs(e)){for(const s in e)Me(e[s],t,n);for(const s of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,s)&&Me(e[s],t,n)}return e}/** +* @vue/runtime-core v3.5.22 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function Ft(e,t,n,s){try{return s?e(...s):e()}catch(i){dn(i,t,n)}}function Ee(e,t,n,s){if(R(e)){const i=Ft(e,t,n,s);return i&&Bs(i)&&i.catch(r=>{dn(r,t,n)}),i}if(M(e)){const i=[];for(let r=0;r>>1,i=se[s],r=Mt(i);r=Mt(n)?se.push(e):se.splice(jr(t),0,e),e.flags|=1,pi()}}function pi(){Xt||(Xt=hi.then(mi))}function Vr(e){M(e)?ct.push(...e):$e&&e.id===-1?$e.splice(st+1,0,e):e.flags&1||(ct.push(e),e.flags|=1),pi()}function ds(e,t,n=we+1){for(;nMt(n)-Mt(s));if(ct.length=0,$e){$e.push(...t);return}for($e=t,st=0;st<$e.length;st++){const n=$e[st];n.flags&4&&(n.flags&=-2),n.flags&8||n(),n.flags&=-2}$e=null,st=0}}const Mt=e=>e.id==null?e.flags&2?-1:1/0:e.id;function mi(e){try{for(we=0;we{s._d&&ws(-1);const r=Zt(t);let o;try{o=e(...i)}finally{Zt(r),s._d&&ws(1)}return o};return s._n=!0,s._c=!0,s._d=!0,s}function He(e,t){if(he===null)return e;const n=mn(he),s=e.dirs||(e.dirs=[]);for(let i=0;ie.__isTeleport,Wr=Symbol("_leaveCb");function Qn(e,t){e.shapeFlag&6&&e.component?(e.transition=t,Qn(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function bi(e){e.ids=[e.ids[0]+e.ids[2]+++"-",0,0]}const Qt=new WeakMap;function Ct(e,t,n,s,i=!1){if(M(e)){e.forEach((I,O)=>Ct(I,t&&(M(t)?t[O]:t),n,s,i));return}if(Tt(s)&&!i){s.shapeFlag&512&&s.type.__asyncResolved&&s.component.subTree.component&&Ct(e,t,n,s.component.subTree);return}const r=s.shapeFlag&4?mn(s.component):s.el,o=i?null:r,{i:l,r:f}=e,h=t&&t.r,a=l.refs===K?l.refs={}:l.refs,p=l.setupState,m=U(p),v=p===K?Us:I=>j(m,I);if(h!=null&&h!==f){if(hs(t),Y(h))a[h]=null,v(h)&&(p[h]=null);else if(X(h)){h.value=null;const I=t;I.k&&(a[I.k]=null)}}if(R(f))Ft(f,l,12,[o,a]);else{const I=Y(f),O=X(f);if(I||O){const z=()=>{if(e.f){const N=I?v(f)?p[f]:a[f]:f.value;if(i)M(N)&&Wn(N,r);else if(M(N))N.includes(r)||N.push(r);else if(I)a[f]=[r],v(f)&&(p[f]=a[f]);else{const F=[r];f.value=F,e.k&&(a[e.k]=F)}}else I?(a[f]=o,v(f)&&(p[f]=o)):O&&(f.value=o,e.k&&(a[e.k]=o))};if(o){const N=()=>{z(),Qt.delete(e)};N.id=-1,Qt.set(e,N),ue(N,n)}else hs(e),z()}}}function hs(e){const t=Qt.get(e);t&&(t.flags|=8,Qt.delete(e))}cn().requestIdleCallback;cn().cancelIdleCallback;const Tt=e=>!!e.type.__asyncLoader,yi=e=>e.type.__isKeepAlive;function Gr(e,t){vi(e,"a",t)}function qr(e,t){vi(e,"da",t)}function vi(e,t,n=ie){const s=e.__wdc||(e.__wdc=()=>{let i=n;for(;i;){if(i.isDeactivated)return;i=i.parent}return e()});if(hn(t,s,n),n){let i=n.parent;for(;i&&i.parent;)yi(i.parent.vnode)&&Jr(s,t,n,i),i=i.parent}}function Jr(e,t,n,s){const i=hn(t,e,s,!0);wi(()=>{Wn(s[t],i)},n)}function hn(e,t,n=ie,s=!1){if(n){const i=n[e]||(n[e]=[]),r=t.__weh||(t.__weh=(...o)=>{Re();const l=Lt(n),f=Ee(t,n,e,o);return l(),Fe(),f});return s?i.unshift(r):i.push(r),r}}const Le=e=>(t,n=ie)=>{(!Rt||e==="sp")&&hn(e,(...s)=>t(...s),n)},Yr=Le("bm"),xi=Le("m"),zr=Le("bu"),kr=Le("u"),Si=Le("bum"),wi=Le("um"),Xr=Le("sp"),Zr=Le("rtg"),Qr=Le("rtc");function eo(e,t=ie){hn("ec",e,t)}const to=Symbol.for("v-ndc");function ps(e,t,n,s){let i;const r=n,o=M(e);if(o||Y(e)){const l=o&<(e);let f=!1,h=!1;l&&(f=!me(e),h=Ze(e),e=un(e)),i=new Array(e.length);for(let a=0,p=e.length;at(l,f,void 0,r));else{const l=Object.keys(e);i=new Array(l.length);for(let f=0,h=l.length;fe?Wi(e)?mn(e):Dn(e.parent):null,Et=re(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Dn(e.parent),$root:e=>Dn(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Ti(e),$forceUpdate:e=>e.f||(e.f=()=>{Zn(e.update)}),$nextTick:e=>e.n||(e.n=$r.bind(e.proxy)),$watch:e=>Co.bind(e)}),Cn=(e,t)=>e!==K&&!e.__isScriptSetup&&j(e,t),no={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:s,data:i,props:r,accessCache:o,type:l,appContext:f}=e;let h;if(t[0]!=="$"){const v=o[t];if(v!==void 0)switch(v){case 1:return s[t];case 2:return i[t];case 4:return n[t];case 3:return r[t]}else{if(Cn(s,t))return o[t]=1,s[t];if(i!==K&&j(i,t))return o[t]=2,i[t];if((h=e.propsOptions[0])&&j(h,t))return o[t]=3,r[t];if(n!==K&&j(n,t))return o[t]=4,n[t];Hn&&(o[t]=0)}}const a=Et[t];let p,m;if(a)return t==="$attrs"&&Z(e.attrs,"get",""),a(e);if((p=l.__cssModules)&&(p=p[t]))return p;if(n!==K&&j(n,t))return o[t]=4,n[t];if(m=f.config.globalProperties,j(m,t))return m[t]},set({_:e},t,n){const{data:s,setupState:i,ctx:r}=e;return Cn(i,t)?(i[t]=n,!0):s!==K&&j(s,t)?(s[t]=n,!0):j(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(r[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:s,appContext:i,propsOptions:r,type:o}},l){let f,h;return!!(n[l]||e!==K&&l[0]!=="$"&&j(e,l)||Cn(t,l)||(f=r[0])&&j(f,l)||j(s,l)||j(Et,l)||j(i.config.globalProperties,l)||(h=o.__cssModules)&&h[l])},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:j(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function gs(e){return M(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let Hn=!0;function so(e){const t=Ti(e),n=e.proxy,s=e.ctx;Hn=!1,t.beforeCreate&&ms(t.beforeCreate,e,"bc");const{data:i,computed:r,methods:o,watch:l,provide:f,inject:h,created:a,beforeMount:p,mounted:m,beforeUpdate:v,updated:I,activated:O,deactivated:z,beforeDestroy:N,beforeUnmount:F,destroyed:L,unmounted:A,render:k,renderTracked:Ne,renderTriggered:_e,errorCaptured:De,serverPrefetch:Nt,expose:Be,inheritAttrs:dt,components:Dt,directives:Ht,filters:_n}=t;if(h&&io(h,s,null),o)for(const J in o){const B=o[J];R(B)&&(s[J]=B.bind(n))}if(i){const J=i.call(n,n);q(J)&&(e.data=an(J))}if(Hn=!0,r)for(const J in r){const B=r[J],We=R(B)?B.bind(n,n):R(B.get)?B.get.bind(n,n):Te,$t=!R(B)&&R(B.set)?B.set.bind(n):Te,Ge=Qe({get:We,set:$t});Object.defineProperty(s,J,{enumerable:!0,configurable:!0,get:()=>Ge.value,set:be=>Ge.value=be})}if(l)for(const J in l)Ci(l[J],s,n,J);if(f){const J=R(f)?f.call(n):f;Reflect.ownKeys(J).forEach(B=>{uo(B,J[B])})}a&&ms(a,e,"c");function Q(J,B){M(B)?B.forEach(We=>J(We.bind(n))):B&&J(B.bind(n))}if(Q(Yr,p),Q(xi,m),Q(zr,v),Q(kr,I),Q(Gr,O),Q(qr,z),Q(eo,De),Q(Qr,Ne),Q(Zr,_e),Q(Si,F),Q(wi,A),Q(Xr,Nt),M(Be))if(Be.length){const J=e.exposed||(e.exposed={});Be.forEach(B=>{Object.defineProperty(J,B,{get:()=>n[B],set:We=>n[B]=We,enumerable:!0})})}else e.exposed||(e.exposed={});k&&e.render===Te&&(e.render=k),dt!=null&&(e.inheritAttrs=dt),Dt&&(e.components=Dt),Ht&&(e.directives=Ht),Nt&&bi(e)}function io(e,t,n=Te){M(e)&&(e=$n(e));for(const s in e){const i=e[s];let r;q(i)?"default"in i?r=Gt(i.from||s,i.default,!0):r=Gt(i.from||s):r=Gt(i),X(r)?Object.defineProperty(t,s,{enumerable:!0,configurable:!0,get:()=>r.value,set:o=>r.value=o}):t[s]=r}}function ms(e,t,n){Ee(M(e)?e.map(s=>s.bind(t.proxy)):e.bind(t.proxy),t,n)}function Ci(e,t,n,s){let i=s.includes(".")?$i(n,s):()=>n[s];if(Y(e)){const r=t[e];R(r)&&En(i,r)}else if(R(e))En(i,e.bind(n));else if(q(e))if(M(e))e.forEach(r=>Ci(r,t,n,s));else{const r=R(e.handler)?e.handler.bind(n):t[e.handler];R(r)&&En(i,r,e)}}function Ti(e){const t=e.type,{mixins:n,extends:s}=t,{mixins:i,optionsCache:r,config:{optionMergeStrategies:o}}=e.appContext,l=r.get(t);let f;return l?f=l:!i.length&&!n&&!s?f=t:(f={},i.length&&i.forEach(h=>en(f,h,o,!0)),en(f,t,o)),q(t)&&r.set(t,f),f}function en(e,t,n,s=!1){const{mixins:i,extends:r}=t;r&&en(e,r,n,!0),i&&i.forEach(o=>en(e,o,n,!0));for(const o in t)if(!(s&&o==="expose")){const l=ro[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const ro={data:_s,props:bs,emits:bs,methods:yt,computed:yt,beforeCreate:ee,created:ee,beforeMount:ee,mounted:ee,beforeUpdate:ee,updated:ee,beforeDestroy:ee,beforeUnmount:ee,destroyed:ee,unmounted:ee,activated:ee,deactivated:ee,errorCaptured:ee,serverPrefetch:ee,components:yt,directives:yt,watch:lo,provide:_s,inject:oo};function _s(e,t){return t?e?function(){return re(R(e)?e.call(this,this):e,R(t)?t.call(this,this):t)}:t:e}function oo(e,t){return yt($n(e),$n(t))}function $n(e){if(M(e)){const t={};for(let n=0;n1)return n&&R(t)?t.call(s&&s.proxy):t}}const Oi={},Ai=()=>Object.create(Oi),Pi=e=>Object.getPrototypeOf(e)===Oi;function ao(e,t,n,s=!1){const i={},r=Ai();e.propsDefaults=Object.create(null),Mi(e,t,i,r);for(const o in e.propsOptions[0])o in i||(i[o]=void 0);n?e.props=s?i:Or(i):e.type.props?e.props=i:e.props=r,e.attrs=r}function ho(e,t,n,s){const{props:i,attrs:r,vnode:{patchFlag:o}}=e,l=U(i),[f]=e.propsOptions;let h=!1;if((s||o>0)&&!(o&16)){if(o&8){const a=e.vnode.dynamicProps;for(let p=0;p{f=!0;const[m,v]=Ii(p,t,!0);re(o,m),v&&l.push(...v)};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}if(!r&&!f)return q(e)&&s.set(e,rt),rt;if(M(r))for(let a=0;ae==="_"||e==="_ctx"||e==="$stable",ts=e=>M(e)?e.map(Ce):[Ce(e)],go=(e,t,n)=>{if(t._n)return t;const s=Ur((...i)=>ts(t(...i)),n);return s._c=!1,s},Ri=(e,t,n)=>{const s=e._ctx;for(const i in e){if(es(i))continue;const r=e[i];if(R(r))t[i]=go(i,r,s);else if(r!=null){const o=ts(r);t[i]=()=>o}}},Fi=(e,t)=>{const n=ts(t);e.slots.default=()=>n},Li=(e,t,n)=>{for(const s in t)(n||!es(s))&&(e[s]=t[s])},mo=(e,t,n)=>{const s=e.slots=Ai();if(e.vnode.shapeFlag&32){const i=t._;i?(Li(s,t,n),n&&Js(s,"_",i,!0)):Ri(t,s)}else t&&Fi(e,t)},_o=(e,t,n)=>{const{vnode:s,slots:i}=e;let r=!0,o=K;if(s.shapeFlag&32){const l=t._;l?n&&l===1?r=!1:Li(i,t,n):(r=!t.$stable,Ri(t,i)),o=t}else t&&(Fi(e,t),o={default:1});if(r)for(const l in i)!es(l)&&o[l]==null&&delete i[l]},ue=Ro;function bo(e){return yo(e)}function yo(e,t){const n=cn();n.__VUE__=!0;const{insert:s,remove:i,patchProp:r,createElement:o,createText:l,createComment:f,setText:h,setElementText:a,parentNode:p,nextSibling:m,setScopeId:v=Te,insertStaticContent:I}=e,O=(c,u,d,b=null,g=null,_=null,w=void 0,S=null,x=!!u.dynamicChildren)=>{if(c===u)return;c&&!_t(c,u)&&(b=jt(c),be(c,g,_,!0),c=null),u.patchFlag===-2&&(x=!1,u.dynamicChildren=null);const{type:y,ref:E,shapeFlag:C}=u;switch(y){case gn:z(c,u,d,b);break;case Ue:N(c,u,d,b);break;case On:c==null&&F(u,d,b,w);break;case ae:Dt(c,u,d,b,g,_,w,S,x);break;default:C&1?k(c,u,d,b,g,_,w,S,x):C&6?Ht(c,u,d,b,g,_,w,S,x):(C&64||C&128)&&y.process(c,u,d,b,g,_,w,S,x,pt)}E!=null&&g?Ct(E,c&&c.ref,_,u||c,!u):E==null&&c&&c.ref!=null&&Ct(c.ref,null,_,c,!0)},z=(c,u,d,b)=>{if(c==null)s(u.el=l(u.children),d,b);else{const g=u.el=c.el;u.children!==c.children&&h(g,u.children)}},N=(c,u,d,b)=>{c==null?s(u.el=f(u.children||""),d,b):u.el=c.el},F=(c,u,d,b)=>{[c.el,c.anchor]=I(c.children,u,d,b,c.el,c.anchor)},L=({el:c,anchor:u},d,b)=>{let g;for(;c&&c!==u;)g=m(c),s(c,d,b),c=g;s(u,d,b)},A=({el:c,anchor:u})=>{let d;for(;c&&c!==u;)d=m(c),i(c),c=d;i(u)},k=(c,u,d,b,g,_,w,S,x)=>{u.type==="svg"?w="svg":u.type==="math"&&(w="mathml"),c==null?Ne(u,d,b,g,_,w,S,x):Nt(c,u,g,_,w,S,x)},Ne=(c,u,d,b,g,_,w,S)=>{let x,y;const{props:E,shapeFlag:C,transition:T,dirs:P}=c;if(x=c.el=o(c.type,_,E&&E.is,E),C&8?a(x,c.children):C&16&&De(c.children,x,null,b,g,Tn(c,_),w,S),P&&qe(c,null,b,"created"),_e(x,c,c.scopeId,w,b),E){for(const W in E)W!=="value"&&!xt(W)&&r(x,W,null,E[W],_,b);"value"in E&&r(x,"value",null,E.value,_),(y=E.onVnodeBeforeMount)&&Se(y,b,c)}P&&qe(c,null,b,"beforeMount");const D=vo(g,T);D&&T.beforeEnter(x),s(x,u,d),((y=E&&E.onVnodeMounted)||D||P)&&ue(()=>{y&&Se(y,b,c),D&&T.enter(x),P&&qe(c,null,b,"mounted")},g)},_e=(c,u,d,b,g)=>{if(d&&v(c,d),b)for(let _=0;_{for(let y=x;y{const S=u.el=c.el;let{patchFlag:x,dynamicChildren:y,dirs:E}=u;x|=c.patchFlag&16;const C=c.props||K,T=u.props||K;let P;if(d&&Je(d,!1),(P=T.onVnodeBeforeUpdate)&&Se(P,d,u,c),E&&qe(u,c,d,"beforeUpdate"),d&&Je(d,!0),(C.innerHTML&&T.innerHTML==null||C.textContent&&T.textContent==null)&&a(S,""),y?Be(c.dynamicChildren,y,S,d,b,Tn(u,g),_):w||B(c,u,S,null,d,b,Tn(u,g),_,!1),x>0){if(x&16)dt(S,C,T,d,g);else if(x&2&&C.class!==T.class&&r(S,"class",null,T.class,g),x&4&&r(S,"style",C.style,T.style,g),x&8){const D=u.dynamicProps;for(let W=0;W{P&&Se(P,d,u,c),E&&qe(u,c,d,"updated")},b)},Be=(c,u,d,b,g,_,w)=>{for(let S=0;S{if(u!==d){if(u!==K)for(const _ in u)!xt(_)&&!(_ in d)&&r(c,_,u[_],null,g,b);for(const _ in d){if(xt(_))continue;const w=d[_],S=u[_];w!==S&&_!=="value"&&r(c,_,S,w,g,b)}"value"in d&&r(c,"value",u.value,d.value,g)}},Dt=(c,u,d,b,g,_,w,S,x)=>{const y=u.el=c?c.el:l(""),E=u.anchor=c?c.anchor:l("");let{patchFlag:C,dynamicChildren:T,slotScopeIds:P}=u;P&&(S=S?S.concat(P):P),c==null?(s(y,d,b),s(E,d,b),De(u.children||[],d,E,g,_,w,S,x)):C>0&&C&64&&T&&c.dynamicChildren?(Be(c.dynamicChildren,T,d,g,_,w,S),(u.key!=null||g&&u===g.subTree)&&Ni(c,u,!0)):B(c,u,d,E,g,_,w,S,x)},Ht=(c,u,d,b,g,_,w,S,x)=>{u.slotScopeIds=S,c==null?u.shapeFlag&512?g.ctx.activate(u,d,b,w,x):_n(u,d,b,g,_,w,x):ss(c,u,x)},_n=(c,u,d,b,g,_,w)=>{const S=c.component=Vo(c,b,g);if(yi(c)&&(S.ctx.renderer=pt),Ko(S,!1,w),S.asyncDep){if(g&&g.registerDep(S,Q,w),!c.el){const x=S.subTree=Ie(Ue);N(null,x,u,d),c.placeholder=x.el}}else Q(S,c,u,d,g,_,w)},ss=(c,u,d)=>{const b=u.component=c.component;if(Mo(c,u,d))if(b.asyncDep&&!b.asyncResolved){J(b,u,d);return}else b.next=u,b.update();else u.el=c.el,b.vnode=u},Q=(c,u,d,b,g,_,w)=>{const S=()=>{if(c.isMounted){let{next:C,bu:T,u:P,parent:D,vnode:W}=c;{const ve=Di(c);if(ve){C&&(C.el=W.el,J(c,C,w)),ve.asyncDep.then(()=>{c.isUnmounted||S()});return}}let V=C,oe;Je(c,!1),C?(C.el=W.el,J(c,C,w)):C=W,T&&Wt(T),(oe=C.props&&C.props.onVnodeBeforeUpdate)&&Se(oe,D,C,W),Je(c,!0);const le=xs(c),ye=c.subTree;c.subTree=le,O(ye,le,p(ye.el),jt(ye),c,g,_),C.el=le.el,V===null&&Io(c,le.el),P&&ue(P,g),(oe=C.props&&C.props.onVnodeUpdated)&&ue(()=>Se(oe,D,C,W),g)}else{let C;const{el:T,props:P}=u,{bm:D,m:W,parent:V,root:oe,type:le}=c,ye=Tt(u);Je(c,!1),D&&Wt(D),!ye&&(C=P&&P.onVnodeBeforeMount)&&Se(C,V,u),Je(c,!0);{oe.ce&&oe.ce._def.shadowRoot!==!1&&oe.ce._injectChildStyle(le);const ve=c.subTree=xs(c);O(null,ve,d,b,c,g,_),u.el=ve.el}if(W&&ue(W,g),!ye&&(C=P&&P.onVnodeMounted)){const ve=u;ue(()=>Se(C,V,ve),g)}(u.shapeFlag&256||V&&Tt(V.vnode)&&V.vnode.shapeFlag&256)&&c.a&&ue(c.a,g),c.isMounted=!0,u=d=b=null}};c.scope.on();const x=c.effect=new Xs(S);c.scope.off();const y=c.update=x.run.bind(x),E=c.job=x.runIfDirty.bind(x);E.i=c,E.id=c.uid,x.scheduler=()=>Zn(E),Je(c,!0),y()},J=(c,u,d)=>{u.component=c;const b=c.vnode.props;c.vnode=u,c.next=null,ho(c,u.props,b,d),_o(c,u.children,d),Re(),ds(c),Fe()},B=(c,u,d,b,g,_,w,S,x=!1)=>{const y=c&&c.children,E=c?c.shapeFlag:0,C=u.children,{patchFlag:T,shapeFlag:P}=u;if(T>0){if(T&128){$t(y,C,d,b,g,_,w,S,x);return}else if(T&256){We(y,C,d,b,g,_,w,S,x);return}}P&8?(E&16&&ht(y,g,_),C!==y&&a(d,C)):E&16?P&16?$t(y,C,d,b,g,_,w,S,x):ht(y,g,_,!0):(E&8&&a(d,""),P&16&&De(C,d,b,g,_,w,S,x))},We=(c,u,d,b,g,_,w,S,x)=>{c=c||rt,u=u||rt;const y=c.length,E=u.length,C=Math.min(y,E);let T;for(T=0;TE?ht(c,g,_,!0,!1,C):De(u,d,b,g,_,w,S,x,C)},$t=(c,u,d,b,g,_,w,S,x)=>{let y=0;const E=u.length;let C=c.length-1,T=E-1;for(;y<=C&&y<=T;){const P=c[y],D=u[y]=x?je(u[y]):Ce(u[y]);if(_t(P,D))O(P,D,d,null,g,_,w,S,x);else break;y++}for(;y<=C&&y<=T;){const P=c[C],D=u[T]=x?je(u[T]):Ce(u[T]);if(_t(P,D))O(P,D,d,null,g,_,w,S,x);else break;C--,T--}if(y>C){if(y<=T){const P=T+1,D=PT)for(;y<=C;)be(c[y],g,_,!0),y++;else{const P=y,D=y,W=new Map;for(y=D;y<=T;y++){const fe=u[y]=x?je(u[y]):Ce(u[y]);fe.key!=null&&W.set(fe.key,y)}let V,oe=0;const le=T-D+1;let ye=!1,ve=0;const gt=new Array(le);for(y=0;y=le){be(fe,g,_,!0);continue}let xe;if(fe.key!=null)xe=W.get(fe.key);else for(V=D;V<=T;V++)if(gt[V-D]===0&&_t(fe,u[V])){xe=V;break}xe===void 0?be(fe,g,_,!0):(gt[xe-D]=y+1,xe>=ve?ve=xe:ye=!0,O(fe,u[xe],d,null,g,_,w,S,x),oe++)}const os=ye?xo(gt):rt;for(V=os.length-1,y=le-1;y>=0;y--){const fe=D+y,xe=u[fe],ls=u[fe+1],cs=fe+1{const{el:_,type:w,transition:S,children:x,shapeFlag:y}=c;if(y&6){Ge(c.component.subTree,u,d,b);return}if(y&128){c.suspense.move(u,d,b);return}if(y&64){w.move(c,u,d,pt);return}if(w===ae){s(_,u,d);for(let C=0;CS.enter(_),g);else{const{leave:C,delayLeave:T,afterLeave:P}=S,D=()=>{c.ctx.isUnmounted?i(_):s(_,u,d)},W=()=>{_._isLeaving&&_[Wr](!0),C(_,()=>{D(),P&&P()})};T?T(_,D,W):W()}else s(_,u,d)},be=(c,u,d,b=!1,g=!1)=>{const{type:_,props:w,ref:S,children:x,dynamicChildren:y,shapeFlag:E,patchFlag:C,dirs:T,cacheIndex:P}=c;if(C===-2&&(g=!1),S!=null&&(Re(),Ct(S,null,d,c,!0),Fe()),P!=null&&(u.renderCache[P]=void 0),E&256){u.ctx.deactivate(c);return}const D=E&1&&T,W=!Tt(c);let V;if(W&&(V=w&&w.onVnodeBeforeUnmount)&&Se(V,u,c),E&6)zi(c.component,d,b);else{if(E&128){c.suspense.unmount(d,b);return}D&&qe(c,null,u,"beforeUnmount"),E&64?c.type.remove(c,u,d,pt,b):y&&!y.hasOnce&&(_!==ae||C>0&&C&64)?ht(y,u,d,!1,!0):(_===ae&&C&384||!g&&E&16)&&ht(x,u,d),b&&is(c)}(W&&(V=w&&w.onVnodeUnmounted)||D)&&ue(()=>{V&&Se(V,u,c),D&&qe(c,null,u,"unmounted")},d)},is=c=>{const{type:u,el:d,anchor:b,transition:g}=c;if(u===ae){Yi(d,b);return}if(u===On){A(c);return}const _=()=>{i(d),g&&!g.persisted&&g.afterLeave&&g.afterLeave()};if(c.shapeFlag&1&&g&&!g.persisted){const{leave:w,delayLeave:S}=g,x=()=>w(d,_);S?S(c.el,_,x):x()}else _()},Yi=(c,u)=>{let d;for(;c!==u;)d=m(c),i(c),c=d;i(u)},zi=(c,u,d)=>{const{bum:b,scope:g,job:_,subTree:w,um:S,m:x,a:y}=c;vs(x),vs(y),b&&Wt(b),g.stop(),_&&(_.flags|=8,be(w,c,u,d)),S&&ue(S,u),ue(()=>{c.isUnmounted=!0},u)},ht=(c,u,d,b=!1,g=!1,_=0)=>{for(let w=_;w{if(c.shapeFlag&6)return jt(c.component.subTree);if(c.shapeFlag&128)return c.suspense.next();const u=m(c.anchor||c.el),d=u&&u[Kr];return d?m(d):u};let bn=!1;const rs=(c,u,d)=>{c==null?u._vnode&&be(u._vnode,null,null,!0):O(u._vnode||null,c,u,null,null,null,d),u._vnode=c,bn||(bn=!0,ds(),gi(),bn=!1)},pt={p:O,um:be,m:Ge,r:is,mt:_n,mc:De,pc:B,pbc:Be,n:jt,o:e};return{render:rs,hydrate:void 0,createApp:fo(rs)}}function Tn({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function Je({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function vo(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Ni(e,t,n=!1){const s=e.children,i=t.children;if(M(s)&&M(i))for(let r=0;r>1,e[n[l]]0&&(t[s]=n[r-1]),n[r]=s)}}for(r=n.length,o=n[r-1];r-- >0;)n[r]=o,o=t[o];return n}function Di(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:Di(t)}function vs(e){if(e)for(let t=0;tGt(So);function En(e,t,n){return Hi(e,t,n)}function Hi(e,t,n=K){const{immediate:s,deep:i,flush:r,once:o}=n,l=re({},n),f=t&&s||!t&&r!=="post";let h;if(Rt){if(r==="sync"){const v=wo();h=v.__watcherHandles||(v.__watcherHandles=[])}else if(!f){const v=()=>{};return v.stop=Te,v.resume=Te,v.pause=Te,v}}const a=ie;l.call=(v,I,O)=>Ee(v,a,I,O);let p=!1;r==="post"?l.scheduler=v=>{ue(v,a&&a.suspense)}:r!=="sync"&&(p=!0,l.scheduler=(v,I)=>{I?v():Zn(v)}),l.augmentJob=v=>{t&&(v.flags|=4),p&&(v.flags|=2,a&&(v.id=a.uid,v.i=a))};const m=Dr(e,t,l);return Rt&&(h?h.push(m):f&&m()),m}function Co(e,t,n){const s=this.proxy,i=Y(e)?e.includes(".")?$i(s,e):()=>s[e]:e.bind(s,s);let r;R(t)?r=t:(r=t.handler,n=t);const o=Lt(this),l=Hi(i,r.bind(s),n);return o(),l}function $i(e,t){const n=t.split(".");return()=>{let s=e;for(let i=0;it==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${Ve(t)}Modifiers`]||e[`${et(t)}Modifiers`];function Eo(e,t,...n){if(e.isUnmounted)return;const s=e.vnode.props||K;let i=n;const r=t.startsWith("update:"),o=r&&To(s,t.slice(7));o&&(o.trim&&(i=n.map(a=>Y(a)?a.trim():a)),o.number&&(i=n.map(In)));let l,f=s[l=yn(t)]||s[l=yn(Ve(t))];!f&&r&&(f=s[l=yn(et(t))]),f&&Ee(f,e,6,i);const h=s[l+"Once"];if(h){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ee(h,e,6,i)}}const Oo=new WeakMap;function ji(e,t,n=!1){const s=n?Oo:t.emitsCache,i=s.get(e);if(i!==void 0)return i;const r=e.emits;let o={},l=!1;if(!R(e)){const f=h=>{const a=ji(h,t,!0);a&&(l=!0,re(o,a))};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}return!r&&!l?(q(e)&&s.set(e,null),null):(M(r)?r.forEach(f=>o[f]=null):re(o,r),q(e)&&s.set(e,o),o)}function pn(e,t){return!e||!rn(t)?!1:(t=t.slice(2).replace(/Once$/,""),j(e,t[0].toLowerCase()+t.slice(1))||j(e,et(t))||j(e,t))}function xs(e){const{type:t,vnode:n,proxy:s,withProxy:i,propsOptions:[r],slots:o,attrs:l,emit:f,render:h,renderCache:a,props:p,data:m,setupState:v,ctx:I,inheritAttrs:O}=e,z=Zt(e);let N,F;try{if(n.shapeFlag&4){const A=i||s,k=A;N=Ce(h.call(k,A,a,p,v,m,I)),F=l}else{const A=t;N=Ce(A.length>1?A(p,{attrs:l,slots:o,emit:f}):A(p,null)),F=t.props?l:Ao(l)}}catch(A){Ot.length=0,dn(A,e,1),N=Ie(Ue)}let L=N;if(F&&O!==!1){const A=Object.keys(F),{shapeFlag:k}=L;A.length&&k&7&&(r&&A.some(Bn)&&(F=Po(F,r)),L=at(L,F,!1,!0))}return n.dirs&&(L=at(L,null,!1,!0),L.dirs=L.dirs?L.dirs.concat(n.dirs):n.dirs),n.transition&&Qn(L,n.transition),N=L,Zt(z),N}const Ao=e=>{let t;for(const n in e)(n==="class"||n==="style"||rn(n))&&((t||(t={}))[n]=e[n]);return t},Po=(e,t)=>{const n={};for(const s in e)(!Bn(s)||!(s.slice(9)in t))&&(n[s]=e[s]);return n};function Mo(e,t,n){const{props:s,children:i,component:r}=e,{props:o,children:l,patchFlag:f}=t,h=r.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&f>=0){if(f&1024)return!0;if(f&16)return s?Ss(s,o,h):!!o;if(f&8){const a=t.dynamicProps;for(let p=0;pe.__isSuspense;function Ro(e,t){t&&t.pendingBranch?M(e)?t.effects.push(...e):t.effects.push(e):Vr(e)}const ae=Symbol.for("v-fgt"),gn=Symbol.for("v-txt"),Ue=Symbol.for("v-cmt"),On=Symbol.for("v-stc"),Ot=[];let de=null;function pe(e=!1){Ot.push(de=e?null:[])}function Fo(){Ot.pop(),de=Ot[Ot.length-1]||null}let It=1;function ws(e,t=!1){It+=e,e<0&&de&&t&&(de.hasOnce=!0)}function Ui(e){return e.dynamicChildren=It>0?de||rt:null,Fo(),It>0&&de&&de.push(e),e}function ze(e,t,n,s,i,r){return Ui($(e,t,n,s,i,r,!0))}function tn(e,t,n,s,i){return Ui(Ie(e,t,n,s,i,!0))}function Ki(e){return e?e.__v_isVNode===!0:!1}function _t(e,t){return e.type===t.type&&e.key===t.key}const Bi=({key:e})=>e??null,qt=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?Y(e)||X(e)||R(e)?{i:he,r:e,k:t,f:!!n}:e:null);function $(e,t=null,n=null,s=0,i=null,r=e===ae?0:1,o=!1,l=!1){const f={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Bi(t),ref:t&&qt(t),scopeId:_i,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:s,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:he};return l?(ns(f,n),r&128&&e.normalize(f)):n&&(f.shapeFlag|=Y(n)?8:16),It>0&&!o&&de&&(f.patchFlag>0||r&6)&&f.patchFlag!==32&&de.push(f),f}const Ie=Lo;function Lo(e,t=null,n=null,s=0,i=null,r=!1){if((!e||e===to)&&(e=Ue),Ki(e)){const l=at(e,t,!0);return n&&ns(l,n),It>0&&!r&&de&&(l.shapeFlag&6?de[de.indexOf(e)]=l:de.push(l)),l.patchFlag=-2,l}if(qo(e)&&(e=e.__vccOpts),t){t=No(t);let{class:l,style:f}=t;l&&!Y(l)&&(t.class=ut(l)),q(f)&&(Xn(f)&&!M(f)&&(f=re({},f)),t.style=fn(f))}const o=Y(e)?1:Vi(e)?128:Br(e)?64:q(e)?4:R(e)?2:0;return $(e,t,n,s,i,o,r,!0)}function No(e){return e?Xn(e)||Pi(e)?re({},e):e:null}function at(e,t,n=!1,s=!1){const{props:i,ref:r,patchFlag:o,children:l,transition:f}=e,h=t?Ho(i||{},t):i,a={__v_isVNode:!0,__v_skip:!0,type:e.type,props:h,key:h&&Bi(h),ref:t&&t.ref?n&&r?M(r)?r.concat(qt(t)):[r,qt(t)]:qt(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ae?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:f,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&at(e.ssContent),ssFallback:e.ssFallback&&at(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return f&&s&&Qn(a,f.clone(a)),a}function vt(e=" ",t=0){return Ie(gn,null,e,t)}function Do(e="",t=!1){return t?(pe(),tn(Ue,null,e)):Ie(Ue,null,e)}function Ce(e){return e==null||typeof e=="boolean"?Ie(Ue):M(e)?Ie(ae,null,e.slice()):Ki(e)?je(e):Ie(gn,null,String(e))}function je(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:at(e)}function ns(e,t){let n=0;const{shapeFlag:s}=e;if(t==null)t=null;else if(M(t))n=16;else if(typeof t=="object")if(s&65){const i=t.default;i&&(i._c&&(i._d=!1),ns(e,i()),i._c&&(i._d=!0));return}else{n=32;const i=t._;!i&&!Pi(t)?t._ctx=he:i===3&&he&&(he.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else R(t)?(t={default:t,_ctx:he},n=32):(t=String(t),s&64?(n=16,t=[vt(t)]):n=8);e.children=t,e.shapeFlag|=n}function Ho(...e){const t={};for(let n=0;nie||he;let nn,Vn;{const e=cn(),t=(n,s)=>{let i;return(i=e[n])||(i=e[n]=[]),i.push(s),r=>{i.length>1?i.forEach(o=>o(r)):i[0](r)}};nn=t("__VUE_INSTANCE_SETTERS__",n=>ie=n),Vn=t("__VUE_SSR_SETTERS__",n=>Rt=n)}const Lt=e=>{const t=ie;return nn(e),e.scope.on(),()=>{e.scope.off(),nn(t)}},Cs=()=>{ie&&ie.scope.off(),nn(null)};function Wi(e){return e.vnode.shapeFlag&4}let Rt=!1;function Ko(e,t=!1,n=!1){t&&Vn(t);const{props:s,children:i}=e.vnode,r=Wi(e);ao(e,s,r,t),mo(e,i,n||t);const o=r?Bo(e,t):void 0;return t&&Vn(!1),o}function Bo(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,no);const{setup:s}=n;if(s){Re();const i=e.setupContext=s.length>1?Go(e):null,r=Lt(e),o=Ft(s,e,0,[e.props,i]),l=Bs(o);if(Fe(),r(),(l||e.sp)&&!Tt(e)&&bi(e),l){if(o.then(Cs,Cs),t)return o.then(f=>{Ts(e,f)}).catch(f=>{dn(f,e,0)});e.asyncDep=o}else Ts(e,o)}else Gi(e)}function Ts(e,t,n){R(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:q(t)&&(e.setupState=di(t)),Gi(e)}function Gi(e,t,n){const s=e.type;e.render||(e.render=s.render||Te);{const i=Lt(e);Re();try{so(e)}finally{Fe(),i()}}}const Wo={get(e,t){return Z(e,"get",""),e[t]}};function Go(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,Wo),slots:e.slots,emit:e.emit,expose:t}}function mn(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(di(Ar(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Et)return Et[n](e)},has(t,n){return n in t||n in Et}})):e.proxy}function qo(e){return R(e)&&"__vccOpts"in e}const Qe=(e,t)=>Lr(e,t,Rt),Jo="3.5.22";/** +* @vue/runtime-dom v3.5.22 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Un;const Es=typeof window<"u"&&window.trustedTypes;if(Es)try{Un=Es.createPolicy("vue",{createHTML:e=>e})}catch{}const qi=Un?e=>Un.createHTML(e):e=>e,Yo="http://www.w3.org/2000/svg",zo="http://www.w3.org/1998/Math/MathML",Ae=typeof document<"u"?document:null,Os=Ae&&Ae.createElement("template"),ko={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const i=t==="svg"?Ae.createElementNS(Yo,e):t==="mathml"?Ae.createElementNS(zo,e):n?Ae.createElement(e,{is:n}):Ae.createElement(e);return e==="select"&&s&&s.multiple!=null&&i.setAttribute("multiple",s.multiple),i},createText:e=>Ae.createTextNode(e),createComment:e=>Ae.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ae.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,i,r){const o=n?n.previousSibling:t.lastChild;if(i&&(i===r||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),!(i===r||!(i=i.nextSibling)););else{Os.innerHTML=qi(s==="svg"?`${e}`:s==="mathml"?`${e}`:e);const l=Os.content;if(s==="svg"||s==="mathml"){const f=l.firstChild;for(;f.firstChild;)l.appendChild(f.firstChild);l.removeChild(f)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Xo=Symbol("_vtc");function Zo(e,t,n){const s=e[Xo];s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const sn=Symbol("_vod"),Ji=Symbol("_vsh"),nt={name:"show",beforeMount(e,{value:t},{transition:n}){e[sn]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):bt(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:s}){!t!=!n&&(s?t?(s.beforeEnter(e),bt(e,!0),s.enter(e)):s.leave(e,()=>{bt(e,!1)}):bt(e,t))},beforeUnmount(e,{value:t}){bt(e,t)}};function bt(e,t){e.style.display=t?e[sn]:"none",e[Ji]=!t}const Qo=Symbol(""),el=/(?:^|;)\s*display\s*:/;function tl(e,t,n){const s=e.style,i=Y(n);let r=!1;if(n&&!i){if(t)if(Y(t))for(const o of t.split(";")){const l=o.slice(0,o.indexOf(":")).trim();n[l]==null&&Jt(s,l,"")}else for(const o in t)n[o]==null&&Jt(s,o,"");for(const o in n)o==="display"&&(r=!0),Jt(s,o,n[o])}else if(i){if(t!==n){const o=s[Qo];o&&(n+=";"+o),s.cssText=n,r=el.test(n)}}else t&&e.removeAttribute("style");sn in e&&(e[sn]=r?s.display:"",e[Ji]&&(s.display="none"))}const As=/\s*!important$/;function Jt(e,t,n){if(M(n))n.forEach(s=>Jt(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=nl(e,t);As.test(n)?e.setProperty(et(s),n.replace(As,""),"important"):e[s]=n}}const Ps=["Webkit","Moz","ms"],An={};function nl(e,t){const n=An[t];if(n)return n;let s=Ve(t);if(s!=="filter"&&s in e)return An[t]=s;s=qs(s);for(let i=0;iPn||(ol.then(()=>Pn=0),Pn=Date.now());function cl(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;Ee(fl(s,n.value),t,5,[s])};return n.value=e,n.attached=ll(),n}function fl(e,t){if(M(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>i=>!i._stopped&&s&&s(i))}else return t}const Ns=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ul=(e,t,n,s,i,r)=>{const o=i==="svg";t==="class"?Zo(e,s,o):t==="style"?tl(e,n,s):rn(t)?Bn(t)||il(e,t,n,s,r):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):al(e,t,s,o))?(Rs(e,t,s),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&Is(e,t,s,o,r,t!=="value")):e._isVueCE&&(/[A-Z]/.test(t)||!Y(s))?Rs(e,Ve(t),s,r,t):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),Is(e,t,s,o))};function al(e,t,n,s){if(s)return!!(t==="innerHTML"||t==="textContent"||t in e&&Ns(t)&&R(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const i=e.tagName;if(i==="IMG"||i==="VIDEO"||i==="CANVAS"||i==="SOURCE")return!1}return Ns(t)&&Y(n)?!1:t in e}const Ds=e=>{const t=e.props["onUpdate:modelValue"]||!1;return M(t)?n=>Wt(t,n):t};function dl(e){e.target.composing=!0}function Hs(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Mn=Symbol("_assign"),$s={created(e,{modifiers:{lazy:t,trim:n,number:s}},i){e[Mn]=Ds(i);const r=s||i.props&&i.props.type==="number";it(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),r&&(l=In(l)),e[Mn](l)}),n&&it(e,"change",()=>{e.value=e.value.trim()}),t||(it(e,"compositionstart",dl),it(e,"compositionend",Hs),it(e,"change",Hs))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:s,trim:i,number:r}},o){if(e[Mn]=Ds(o),e.composing)return;const l=(r||e.type==="number")&&!/^0\d/.test(e.value)?In(e.value):e.value,f=t??"";l!==f&&(document.activeElement===e&&e.type!=="range"&&(s&&t===n||i&&e.value.trim()===f)||(e.value=f))}},hl=re({patchProp:ul},ko);let js;function pl(){return js||(js=bo(hl))}const gl=((...e)=>{const t=pl().createApp(...e),{mount:n}=t;return t.mount=s=>{const i=_l(s);if(!i)return;const r=t._component;!R(r)&&!r.render&&!r.template&&(r.template=i.innerHTML),i.nodeType===1&&(i.textContent="");const o=n(i,!1,ml(i));return i instanceof Element&&(i.removeAttribute("v-cloak"),i.setAttribute("data-v-app","")),o},t});function ml(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function _l(e){return Y(e)?document.querySelector(e):e}function Bt(e,t,n){return Math.max(t,Math.min(n,e))}function bl(){const e=an({visible:!1,tab:"garage",vehicles:[],impoundedVehicles:[],searchGarage:"",searchImpounded:"",spawnPoint:null,poundCost:0,poundName:"",poundSpawnPoint:null,impoundOnly:!1,locales:{garage_title:"Garage",garage_tab:"Garage",impounded_tab:"Impounded",veh_model:"Model",veh_plate:"Plate",veh_condition:"Condition",action:"Retrieve",impound_action:"Release",no_veh_parking:"No Vehicles Stored Here.",no_veh_impounded:"No Impounded Vehicles.",search_placeholder:"Search by model or plate…"}}),t=Qe(()=>{const m=e.searchGarage.trim().toLowerCase();return m?e.vehicles.filter(v=>String(v.model||"").toLowerCase().includes(m)||String(v.plate||"").toLowerCase().includes(m)):e.vehicles}),n=Qe(()=>{const m=e.searchImpounded.trim().toLowerCase();return m?e.impoundedVehicles.filter(v=>String(v.model||"").toLowerCase().includes(m)||String(v.plate||"").toLowerCase().includes(m)):e.impoundedVehicles});function s(m){const v=m.props||{},I=Bt((typeof v.bodyHealth=="number"?v.bodyHealth:1e3)/1e3*100,0,100),O=Bt((typeof v.engineHealth=="number"?v.engineHealth:1e3)/1e3*100,0,100),z=Bt((typeof v.tankHealth=="number"?v.tankHealth:1e3)/1e3*100,0,100);return Bt(Math.round((I+O+z)/300*100),0,100)}function i(m,v){fetch(`https://esx_garage/${m}`,{method:"POST",headers:{"Content-Type":"application/json; charset=utf-8"},body:JSON.stringify(v||{})})}function r(m){e.visible=!0,e.impoundOnly=m.type==="impound",e.tab=e.impoundOnly?"impounded":"garage",m.locales&&Object.assign(e.locales,m.locales),e.spawnPoint=m.spawnPoint||null,typeof m.poundCost=="number"&&(e.poundCost=m.poundCost);const v=(I,O)=>O?typeof O=="object"?Array.isArray(O)?O.slice():O:(Array.isArray(O)&&(O=O[0]),typeof O!="string"?[]:JSON.parse(O)):[];e.vehicles=v("vehiclesList",m.vehiclesList),e.impoundedVehicles=v("vehiclesImpoundedList",m.vehiclesImpoundedList),e.poundName=m.poundName||"",e.poundSpawnPoint=m.poundSpawnPoint||null}function o(){e.visible=!1,e.searchGarage="",e.searchImpounded=""}function l(m){i("spawnVehicle",{vehicleProps:m.props,spawnPoint:e.spawnPoint,exitVehicleCost:e.poundCost||0}),o()}function f(m){i("impound",{vehicleProps:m.props,poundName:e.poundName,poundSpawnPoint:e.poundSpawnPoint}),o()}function h(){i("escape",{}),o()}function a(m){const v=m.data||{};!v.showMenu&&!v.hideAll||(v.showMenu?r(v):v.hideAll&&o())}function p(m){m.key==="Escape"&&e.visible&&h()}return xi(()=>{window.addEventListener("message",a),window.addEventListener("keyup",p)}),Si(()=>{window.removeEventListener("message",a),window.removeEventListener("keyup",p)}),{...Mr(e),filteredGarage:t,filteredImpounded:n,damagePercent:s,spawnVehicle:l,impoundVehicle:f,closeUI:h}}const yl=""+new URL("../img/logo.png",import.meta.url).href,vl=["data-model","data-plate"],xl={class:"condition"},Sl={class:"bar"},wl={class:"percent"},Cl={key:0},Vs={__name:"VehicleCard",props:{veh:{type:Object,required:!0},locales:{type:Object,required:!0},damagePercent:{type:Function,required:!0},action:{type:Function,required:!0},actionType:{type:String,default:"spawn"},poundCost:{type:Number,default:0}},emits:["action"],setup(e,{emit:t}){const n=e,s=t;function i(){s("action",n.veh)}const r=Qe(()=>n.actionType==="impound"),o=Qe(()=>n.damagePercent(n.veh));return(l,f)=>(pe(),ze("div",{class:"vehicle-listing","data-model":(e.veh.model||"").toLowerCase(),"data-plate":(e.veh.plate||"").toLowerCase()},[$("div",null,[vt(te(e.locales.veh_model)+": ",1),$("strong",null,te(e.veh.model),1)]),$("div",null,[vt(te(e.locales.veh_plate)+": ",1),$("strong",null,te(e.veh.plate),1)]),$("div",xl,[$("span",null,te(e.locales.veh_condition),1),$("div",Sl,[$("div",{class:"fill",style:fn({width:o.value+"%"})},null,4)]),$("strong",wl,te(o.value)+"%",1)]),$("button",{class:ut(["vehicle-action unstyled-button",{red:r.value}]),onClick:i},[r.value?(pe(),ze(ae,{key:1},[vt(te(e.locales.impound_action),1)],64)):(pe(),ze(ae,{key:0},[vt(te(e.locales.action),1),e.poundCost&&e.poundCost>0?(pe(),ze("span",Cl," ($"+te(e.poundCost)+")",1)):Do("",!0)],64))],2)],8,vl))}},Tl={id:"container",role:"dialog",style:{display:"grid"}},El={id:"header"},Ol={class:"title",id:"garage-title"},Al={role:"tablist"},Pl=["src"],Ml={id:"menu"},Il={class:"content",role:"tabpanel"},Rl={class:"toolbar"},Fl=["placeholder"],Ll=["aria-label"],Nl={class:"impounded_content",role:"tabpanel"},Dl={class:"toolbar"},Hl=["placeholder"],$l=["aria-label"],jl={__name:"Main",setup(e){const{visible:t,tab:n,searchGarage:s,searchImpounded:i,poundCost:r,locales:o,impoundOnly:l,filteredGarage:f,filteredImpounded:h,damagePercent:a,spawnVehicle:p,impoundVehicle:m,closeUI:v}=bl();function I(N){l.value||(n.value=N)}const O=Qe(()=>o.garage_tab+" vehicles list"),z=Qe(()=>o.impounded_tab+" vehicles list");return(N,F)=>He((pe(),ze("div",Tl,[$("div",El,[$("div",Ol,te(H(o).garage_title),1),He($("ul",Al,[$("li",{class:ut({selected:H(n)==="garage"}),role:"tab",onClick:F[0]||(F[0]=L=>I("garage"))},te(H(o).garage_tab),3),$("li",{class:ut({selected:H(n)==="impounded"}),role:"tab",onClick:F[1]||(F[1]=L=>I("impounded"))},te(H(o).impounded_tab),3)],512),[[nt,!H(l)]]),$("img",{class:"logo-left",src:H(yl),alt:"ESX logo"},null,8,Pl),$("button",{class:"close",title:"Close",onClick:F[2]||(F[2]=(...L)=>H(v)&&H(v)(...L))},"×")]),$("div",Ml,[He($("div",Il,[$("div",Rl,[He($("input",{id:"search-garage",type:"search",placeholder:H(o).search_placeholder,"onUpdate:modelValue":F[3]||(F[3]=L=>X(s)?s.value=L:null)},null,8,Fl),[[$s,H(s)]])]),He($("h2",{class:"empty"},te(H(o).no_veh_parking),513),[[nt,!H(f).length]]),$("div",{class:"vehicle-list","aria-label":O.value},[(pe(!0),ze(ae,null,ps(H(f),L=>(pe(),tn(Vs,{key:L.plate,veh:L,locales:H(o),damagePercent:H(a),action:H(p),"action-type":"spawn",poundCost:H(r),onAction:H(p)},null,8,["veh","locales","damagePercent","action","poundCost","onAction"]))),128))],8,Ll)],512),[[nt,H(n)==="garage"]]),He($("div",Nl,[$("div",Dl,[He($("input",{id:"search-impounded",type:"search",placeholder:H(o).search_placeholder,"onUpdate:modelValue":F[4]||(F[4]=L=>X(i)?i.value=L:null)},null,8,Hl),[[$s,H(i)]])]),He($("h2",{class:"empty"},te(H(o).no_veh_impounded),513),[[nt,!H(h).length]]),$("div",{class:"vehicle-list","aria-label":z.value},[(pe(!0),ze(ae,null,ps(H(h),L=>(pe(),tn(Vs,{key:L.plate,veh:L,locales:H(o),damagePercent:H(a),action:H(m),"action-type":"impound",onAction:H(m)},null,8,["veh","locales","damagePercent","action","onAction"]))),128))],8,$l)],512),[[nt,H(n)==="impounded"]])])],512)),[[nt,H(t)]])}},Vl=(e,t)=>{const n=e.__vccOpts||e;for(const[s,i]of t)n[s]=i;return n},Ul={__name:"App",setup(e){return(t,n)=>(pe(),tn(jl))}},Kl=Vl(Ul,[["__scopeId","data-v-9a622185"]]);gl(Kl).mount("#app"); diff --git a/[esx_addons]/esx_garage/nui/ui.html b/[esx_addons]/esx_garage/nui/ui.html deleted file mode 100644 index 3509705b..00000000 --- a/[esx_addons]/esx_garage/nui/ui.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - -
- - - -
- - - - - diff --git a/[esx_addons]/esx_garage/web/.gitignore b/[esx_addons]/esx_garage/web/.gitignore new file mode 100644 index 00000000..ab267f80 --- /dev/null +++ b/[esx_addons]/esx_garage/web/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/ +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +node_modules/ diff --git a/[esx_addons]/esx_garage/web/index.html b/[esx_addons]/esx_garage/web/index.html new file mode 100644 index 00000000..fcbd67f1 --- /dev/null +++ b/[esx_addons]/esx_garage/web/index.html @@ -0,0 +1,13 @@ + + + + + + + ESX + + +
+ + + diff --git a/[esx_addons]/esx_garage/web/package-lock.json b/[esx_addons]/esx_garage/web/package-lock.json new file mode 100644 index 00000000..45198bbe --- /dev/null +++ b/[esx_addons]/esx_garage/web/package-lock.json @@ -0,0 +1,1887 @@ +{ + "name": "web", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web", + "version": "1.0.0", + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "tailwindcss": "^4.1.14", + "vue": "^3.5.22" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.1", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.29", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", + "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", + "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.0", + "lightningcss": "1.30.1", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", + "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.5.1" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-x64": "4.1.14", + "@tailwindcss/oxide-freebsd-x64": "4.1.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-x64-musl": "4.1.14", + "@tailwindcss/oxide-wasm32-wasi": "4.1.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", + "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", + "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", + "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", + "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", + "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", + "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", + "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", + "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", + "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", + "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.5", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", + "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", + "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz", + "integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.14", + "@tailwindcss/oxide": "4.1.14", + "tailwindcss": "4.1.14" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", + "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.29" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz", + "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/shared": "3.5.22", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz", + "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz", + "integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/compiler-core": "3.5.22", + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.19", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz", + "integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz", + "integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.22.tgz", + "integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz", + "integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/runtime-core": "3.5.22", + "@vue/shared": "3.5.22", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.22.tgz", + "integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "vue": "3.5.22" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz", + "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==", + "license": "MIT" + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz", + "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz", + "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-sfc": "3.5.22", + "@vue/runtime-dom": "3.5.22", + "@vue/server-renderer": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + } + } +} diff --git a/[esx_addons]/esx_garage/web/package.json b/[esx_addons]/esx_garage/web/package.json new file mode 100644 index 00000000..4f24410e --- /dev/null +++ b/[esx_addons]/esx_garage/web/package.json @@ -0,0 +1,19 @@ +{ + "name": "web", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "tailwindcss": "^4.1.14", + "vue": "^3.5.22" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.1", + "vite": "^7.1.7" + } +} diff --git a/[esx_addons]/esx_garage/web/public/fonts/roboto.ttf b/[esx_addons]/esx_garage/web/public/fonts/roboto.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d9a6c4c32d7e920b549caf531e390733496b6e0 GIT binary patch literal 158604 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
v%Q*Qgy;tdJj4ZONjTx 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

sDMz7$^SDZV4x`K*fov0l~+M89O^^Om^v{t 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 literal 0 HcmV?d00001 diff --git a/[esx_addons]/esx_garage/web/src/App.vue b/[esx_addons]/esx_garage/web/src/App.vue new file mode 100644 index 00000000..b0942897 --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/App.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/[esx_addons]/esx_garage/web/src/assets/logo.png b/[esx_addons]/esx_garage/web/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e08a82bfce6825965bacd70f35f329d4ccc8a125 GIT binary patch literal 13632 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 Vew`HvxU%t)p|0t9(%GxG{~w$1y$t{W literal 0 HcmV?d00001 diff --git a/[esx_addons]/esx_garage/web/src/components/Main.vue b/[esx_addons]/esx_garage/web/src/components/Main.vue new file mode 100644 index 00000000..39b10542 --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/components/Main.vue @@ -0,0 +1,83 @@ + + + diff --git a/[esx_addons]/esx_garage/web/src/components/VehicleCard.vue b/[esx_addons]/esx_garage/web/src/components/VehicleCard.vue new file mode 100644 index 00000000..4257195a --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/components/VehicleCard.vue @@ -0,0 +1,45 @@ + + + diff --git a/[esx_addons]/esx_garage/web/src/composables/useGarage.js b/[esx_addons]/esx_garage/web/src/composables/useGarage.js new file mode 100644 index 00000000..08ca67c8 --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/composables/useGarage.js @@ -0,0 +1,147 @@ +import { reactive, computed, onMounted, onBeforeUnmount, toRefs } from 'vue'; + +function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); } + +export function useGarage() { + const state = reactive({ + visible: false, + tab: 'garage', + vehicles: [], + impoundedVehicles: [], + searchGarage: '', + searchImpounded: '', + spawnPoint: null, + poundCost: 0, + poundName: '', + poundSpawnPoint: null, + impoundOnly: false, + locales: { + garage_title: 'Garage', + garage_tab: 'Garage', + impounded_tab: 'Impounded', + veh_model: 'Model', + veh_plate: 'Plate', + veh_condition: 'Condition', + action: 'Retrieve', + impound_action: 'Release', + no_veh_parking: 'No Vehicles Stored Here.', + no_veh_impounded: 'No Impounded Vehicles.', + search_placeholder: 'Search by model or plate…' + } + }); + + const filteredGarage = computed(() => { + const q = state.searchGarage.trim().toLowerCase(); + if (!q) return state.vehicles; + return state.vehicles.filter(v => (String(v.model||'').toLowerCase().includes(q) || String(v.plate||'').toLowerCase().includes(q))); + }); + + const filteredImpounded = computed(() => { + const q = state.searchImpounded.trim().toLowerCase(); + if (!q) return state.impoundedVehicles; + return state.impoundedVehicles.filter(v => (String(v.model||'').toLowerCase().includes(q) || String(v.plate||'').toLowerCase().includes(q))); + }); + + function damagePercent(veh) { + const p = veh.props || {}; + const b = clamp(((typeof p.bodyHealth === 'number' ? p.bodyHealth : 1000) / 1000) * 100, 0, 100); + const e = clamp(((typeof p.engineHealth === 'number' ? p.engineHealth : 1000) / 1000) * 100, 0, 100); + const t = clamp(((typeof p.tankHealth === 'number' ? p.tankHealth : 1000) / 1000) * 100, 0, 100); + return clamp(Math.round(((b + e + t) / 300) * 100), 0, 100); + } + + function post(endpoint, payload) { + fetch(`https://esx_garage/${endpoint}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json; charset=utf-8' }, + body: JSON.stringify(payload || {}) + }); + } + + function openMenu(data) { + state.visible = true; + state.impoundOnly = data.type === 'impound'; + state.tab = state.impoundOnly ? 'impounded' : 'garage'; + if (data.locales) Object.assign(state.locales, data.locales); + state.spawnPoint = data.spawnPoint || null; + if (typeof data.poundCost === 'number') state.poundCost = data.poundCost; + const safeParse = (label, raw) => { + if (!raw) return []; + if (typeof raw === 'object') return Array.isArray(raw) ? raw.slice() : raw; + if (Array.isArray(raw)) { + raw = raw[0]; + } + if (typeof raw !== 'string') return []; + return JSON.parse(raw); + }; + + state.vehicles = safeParse('vehiclesList', data.vehiclesList); + state.impoundedVehicles = safeParse('vehiclesImpoundedList', data.vehiclesImpoundedList); + state.poundName = data.poundName || ''; + state.poundSpawnPoint = data.poundSpawnPoint || null; + } + + function hideAll() { + state.visible = false; + state.searchGarage = ''; + state.searchImpounded = ''; + } + + function spawnVehicle(veh) { + post('spawnVehicle', { + vehicleProps: veh.props, + spawnPoint: state.spawnPoint, + exitVehicleCost: state.poundCost || 0 + }); + hideAll(); + } + + function impoundVehicle(veh) { + post('impound', { + vehicleProps: veh.props, + poundName: state.poundName, + poundSpawnPoint: state.poundSpawnPoint + }); + hideAll(); + } + + function closeUI() { + post('escape', {}); + hideAll(); + } + + function onMessage(e) { + const data = e.data || {}; + if (!data.showMenu && !data.hideAll) return; + if (data.showMenu) openMenu(data); + else if (data.hideAll) hideAll(); + } + + function onKey(e) { + if (e.key === 'Escape' && state.visible) { + closeUI(); + } + } + + onMounted(() => { + window.addEventListener('message', onMessage); + window.addEventListener('keyup', onKey); + }); + + onBeforeUnmount(() => { + window.removeEventListener('message', onMessage); + window.removeEventListener('keyup', onKey); + }); + + return { + ...toRefs(state), + filteredGarage, + filteredImpounded, + damagePercent, + spawnVehicle, + impoundVehicle, + closeUI + }; +} + +export default useGarage; diff --git a/[esx_addons]/esx_garage/web/src/main.js b/[esx_addons]/esx_garage/web/src/main.js new file mode 100644 index 00000000..2425c0f7 --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/main.js @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/[esx_addons]/esx_garage/web/src/style.css b/[esx_addons]/esx_garage/web/src/style.css new file mode 100644 index 00000000..65f7abe1 --- /dev/null +++ b/[esx_addons]/esx_garage/web/src/style.css @@ -0,0 +1,82 @@ +@import "tailwindcss"; +@font-face { font-family: 'Roboto'; src: url('/fonts/roboto.ttf') format('truetype'); font-display: swap; } + +:root { + --brand: #FB9B04; + --darkest: #161616; + --dark: #252525; + --mid: #383838; + --light: #969696; + --lightest: #F2F2F2; + --toolbar-h: 50px; + --radius-lg: 16px; + --radius-md: 12px; + --radius-sm: 8px; + --shadow-1: 0 10px 30px rgba(0,0,0,.35); + --shadow-2: 0 6px 18px rgba(0,0,0,.25); + --transition-fast: 160ms cubic-bezier(.2,.7,.2,1); + --transition-med: 260ms cubic-bezier(.2,.7,.2,1); +} + +html, body { width:100%; height:100%; background:transparent; } +body { margin:0; background:transparent; color:var(--lightest); font:500 14px/1.45 'Roboto', system-ui,-apple-system,Segoe UI,Arial,sans-serif; overflow:hidden; } + +#container { position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:min(1000px, calc(100vw - 64px)); height:min(700px, calc(100vh - 64px)); display:none; background:linear-gradient(180deg,var(--dark),var(--darkest)); border:1px solid rgba(255,255,255,.06); border-radius:var(--radius-lg); box-shadow:var(--shadow-1); grid-template-columns:280px 1fr; grid-template-rows:1fr; overflow:hidden; } +#container[style*='display:grid'] { display:grid !important; } + +#container::before { content:''; height:56px; background:linear-gradient(90deg, rgba(251,155,4,.24) 0%, transparent 40%), linear-gradient(180deg, rgba(255,255,255,.06), transparent); border-bottom:1px solid rgba(255,255,255,.06); position:absolute; top:0; left:0; right:0; z-index:0; } + +/* Header / Sidebar */ +#header { grid-column:1 / 2; padding-top:56px; position:relative; } +#header .title { padding:18px 20px 10px 20px; font-size:20px; font-weight:700; letter-spacing:.2px; color:var(--lightest); z-index:1; } +#header .close { position:absolute; top:28px; right:14px; transform:translateY(-50%); width:36px; height:36px; display:grid; place-items:center; color:var(--lightest); background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.08); border-radius:50%; cursor:pointer; font-size:18px; transition:transform var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast); } +#header .close:hover { background:rgba(251,155,4,.15); border-color:rgba(251,155,4,.35); } +#header ul { list-style:none; margin:8px 0 0 0; padding:10px 8px 8px 12px; display:flex; flex-direction:column; gap:6px; z-index:1; } +#header li { cursor:pointer; display:flex; align-items:center; gap:10px; padding:12px 0 12px 22px; width:100%; box-sizing:border-box; color:var(--lightest); border-radius:var(--radius-md); border:1px solid transparent; position:relative; transition:background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); } +#header li::before { content:''; position:absolute; left:6px; top:50%; transform:translateY(-50%); width:4px; height:60%; border-radius:4px; background:transparent; } +#header li:hover { background:rgba(56,56,56,.45); border-color:rgba(255,255,255,.08); } +#header li.selected { background:rgba(56,56,56,.6); border-color:rgba(251,155,4,.45); color:var(--lightest); } +#header li.selected::before { background:var(--brand); } + +/* Main area */ +#menu { grid-column:2 / -1; padding-top:56px; padding-left:8px; height:100%; box-sizing:border-box; min-height:0; display:flex; flex-direction:column; overflow:hidden; } +.content, .impounded_content { width:100%; flex:1 1 auto; min-height:0; color:var(--lightest); overflow:hidden; display:flex; flex-direction:column; } +.content .empty, .impounded_content .empty { opacity:.7; font-weight:500; text-align:center; margin-top:18vh; } + +/* Vehicle lists */ +.content .vehicle-list, .impounded_content .vehicle-list { flex:1 1 0%; min-height:0; overflow-y:scroll; -ms-overflow-style:none; -webkit-overflow-scrolling:touch; overscroll-behavior:contain; overflow-x:hidden; height:calc(100% - var(--toolbar-h)); width:96%; max-width:96%; margin:0 auto; box-sizing:border-box; display:grid; grid-template-columns:repeat(2,1fr); column-gap:12px; padding:10px 0 0 0; row-gap:36px; align-content:start; align-items:start; justify-items:stretch; grid-auto-rows:auto; } +.content .vehicle-list::after, .impounded_content .vehicle-list::after { content:''; display:block; } +@media (max-width: 820px) { .content .vehicle-list, .impounded_content .vehicle-list { grid-template-columns:1fr; } } + +/* Toolbar */ +.toolbar { display:flex; align-items:center; width:96%; padding:10px 0 0 0; margin:0 auto; box-sizing:border-box; overflow:hidden; flex:0 0 auto; height:var(--toolbar-h); } +.toolbar input[type="search"] { flex:1 1 auto; width:100%; height:100%; display:block; padding:10px 12px; border-radius:var(--radius-sm); border:1px solid rgba(255,255,255,.08); background:rgba(56,56,56,.55); color:var(--lightest); outline:none; } +.toolbar input[type="search"]::placeholder { color:rgba(242,242,242,.55); } +.toolbar input[type="search"]:focus { border-color:rgba(251,155,4,.55); box-shadow:0 0 0 3px rgba(251,155,4,.12); } + +/* Cards */ +.vehicle-listing { display:flex; flex-direction:column; gap:10px; background:linear-gradient(180deg, rgba(56,56,56,.45), rgba(37,37,37,.85)); border:1px solid rgba(255,255,255,.06); border-radius:var(--radius-md); padding:16px; min-height:148px; width:100%; box-sizing:border-box; position:relative; z-index:0; transition:border-color var(--transition-fast), box-shadow var(--transition-fast); } +.vehicle-listing:hover { border-color:rgba(251,155,4,.45); box-shadow:var(--shadow-2); z-index:1; } +.vehicle-listing div { display:flex; align-items:center; justify-content:space-between; color:var(--lightest); } +.vehicle-listing strong { color:var(--lightest); } + +/* Condition bar */ +.condition { display:flex; align-items:center; gap:8px; } +.condition .bar { flex:1; height:8px; background:rgba(255,255,255,.08); border-radius:999px; overflow:hidden; } +.condition .fill { height:100%; width:0%; background:linear-gradient(90deg, #ffad2e, var(--brand)); border-radius:999px; transition:width var(--transition-med); } +.condition .percent { display:inline-block; } + +/* Buttons */ +.unstyled-button { background:none; border:none; padding:0; font:inherit; color:inherit; } +.vehicle-action { align-self:stretch; display:inline-flex; justify-content:center; align-items:center; gap:8px; padding:12px 14px; border-radius:var(--radius-sm); border:1px solid rgba(255,255,255,.08); color:var(--darkest); background:linear-gradient(180deg, #ffad2e, var(--brand)); font-weight:700; letter-spacing:.2px; cursor:pointer; transition:transform var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast); } +.vehicle-action:hover { transform:translateY(-1px); box-shadow:0 6px 18px rgba(251,155,4,.25); border-color:rgba(251,155,4,.55); } +.vehicle-action.red { color:var(--lightest); background:linear-gradient(180deg, #d87070, #b35252); border-color:rgba(255,255,255,.08); } +.vehicle-action.red:hover { box-shadow:0 6px 18px rgba(179,82,82,.25); border-color:rgba(179,82,82,.55); } +.logo-left { position:absolute; left:16px; top:28px; transform:translateY(-50%); height:32px; width:auto; filter:drop-shadow(0 4px 14px rgba(0,0,0,.35)); user-select:none; pointer-events:none; } +.content .vehicle-list, .impounded_content .vehicle-list { scrollbar-width:none; } +.content .vehicle-list::-webkit-scrollbar, .impounded_content .vehicle-list::-webkit-scrollbar { width:0 !important; height:0 !important; } +@media (prefers-reduced-motion: reduce) { * { transition:none !important; animation:none !important; } } +#header { position:static; } +#header .close { position:absolute; top:28px; right:14px; z-index:10; } +::selection { background:transparent; color:inherit; } +::-moz-selection { background:transparent; color:inherit; } diff --git a/[esx_addons]/esx_garage/web/vite.config.js b/[esx_addons]/esx_garage/web/vite.config.js new file mode 100644 index 00000000..e33525d4 --- /dev/null +++ b/[esx_addons]/esx_garage/web/vite.config.js @@ -0,0 +1,32 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [vue(), tailwindcss()], + base: './', + build: { + outDir: '../nui', + emptyOutDir: true, + assetsDir: 'assets', + rollupOptions: { + output: { + entryFileNames: 'js/[name].js', + chunkFileNames: 'js/[name].js', + assetFileNames: (assetInfo) => { + const ext = assetInfo.name ? assetInfo.name.split('.').pop() : '' + if (/ttf|otf|woff2?|eot/i.test(ext)) return 'fonts/[name][extname]' + if (/png|jpe?g|gif|svg|webp|ico/i.test(ext)) return 'img/[name][extname]' + if (/css/i.test(ext)) return 'css/[name][extname]' + return 'assets/[name][extname]' + } + } + } + }, + resolve: { + alias: { + '@': resolve(__dirname, 'src') + } + } +})