From ba9a679f6458ef2e7ca717338f6560030e28adf9 Mon Sep 17 00:00:00 2001 From: "ANTOND." <71350868+antond15@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:18:16 +0100 Subject: [PATCH] feat!: V2 Rewrite (#22) --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 +- .github/workflows/release.yml | 36 +- LICENSE | 23 +- README.md | 52 +- config.lua | 122 +- docs/common_issues.md | 22 - docs/config.md | 108 - fxmanifest.lua | 34 +- locales/bg.lua | 12 - locales/cs.json | 11 + locales/cs.lua | 12 - locales/en.json | 11 + locales/en.lua | 12 - locales/et.lua | 12 - locales/sk.json | 11 + modules/client/main.lua | 102 + modules/client/setup.lua | 46 + modules/server/main.lua | 72 + modules/server/sections/groups/esx.lua | 136 + modules/server/sections/groups/ox.lua | 26 + modules/server/sections/groups/qb.lua | 123 + modules/server/sections/groups/qbx.lua | 140 + modules/server/sections/indicators.lua | 32 + modules/server/sections/players.lua | 48 + resource/client.lua | 2 + resource/client/client.lua | 115 - resource/client/locales.lua | 22 - resource/server.lua | 7 + resource/server/framework.lua | 127 - resource/server/server.lua | 39 - resource/server/version.lua | 34 - web/.gitattributes | 1 + web/.gitignore | 24 +- web/.prettierrc | 10 + web/bun.lockb | Bin 0 -> 95256 bytes web/index.html | 10 +- web/package.json | 48 +- web/pnpm-lock.yaml | 2500 ----------------- web/postcss.config.cjs | 6 + web/public/logo.svg | 19 + web/src/App.svelte | 92 + web/src/App.tsx | 7 - web/src/components/Footer.tsx | 46 - web/src/components/Scoreboard.tsx | 168 -- web/src/components/body/GroupList.tsx | 48 - web/src/components/body/PlayerList.tsx | 36 - web/src/components/body/SectionHeader.tsx | 26 - web/src/components/footer.svelte | 47 + web/src/components/groups.svelte | 31 + web/src/components/lib/sheet/index.ts | 57 + .../components/lib/sheet/sheet-content.svelte | 37 + .../components/lib/sheet/sheet-overlay.svelte | 21 + .../components/lib/sheet/sheet-portal.svelte | 13 + web/src/components/lib/tooltip/animation.ts | 50 + web/src/components/lib/tooltip/index.ts | 7 + .../lib/tooltip/tooltip-content.svelte | 26 + .../lib/tooltip/tooltip-trigger.svelte | 14 + web/src/components/players.svelte | 29 + web/src/components/status-indicators.svelte | 21 + web/src/components/title.svelte | 22 + web/src/hooks/useNuiEvent.ts | 49 - web/src/index.css | 19 - web/src/index.pcss | 84 + web/src/interfaces/group.ts | 5 - web/src/interfaces/locale.ts | 3 - web/src/interfaces/player.ts | 3 - web/src/main.ts | 19 + web/src/main.tsx | 28 - web/src/providers/VisibilityProvider.svelte | 14 + web/src/providers/VisibilityProvider.tsx | 38 - web/src/store/config.ts | 19 + web/src/store/data.ts | 28 + web/src/store/locales.ts | 10 + web/src/store/visibility.ts | 3 + web/src/theme/index.ts | 10 - web/src/types/config.ts | 20 + web/src/types/data.ts | 30 + web/src/types/locales.ts | 9 + web/src/utils/debugData.ts | 6 +- web/src/utils/fetchNui.ts | 19 +- web/src/utils/misc.ts | 9 +- web/src/utils/useNuiEvent.ts | 48 + web/src/vite-env.d.ts | 1 + web/svelte.config.js | 7 + web/tailwind.config.ts | 35 + web/tsconfig.json | 28 +- web/tsconfig.node.json | 4 +- web/vite.config.ts | 22 +- 88 files changed, 1847 insertions(+), 3695 deletions(-) delete mode 100644 docs/common_issues.md delete mode 100644 docs/config.md delete mode 100644 locales/bg.lua create mode 100644 locales/cs.json delete mode 100644 locales/cs.lua create mode 100644 locales/en.json delete mode 100644 locales/en.lua delete mode 100644 locales/et.lua create mode 100644 locales/sk.json create mode 100644 modules/client/main.lua create mode 100644 modules/client/setup.lua create mode 100644 modules/server/main.lua create mode 100644 modules/server/sections/groups/esx.lua create mode 100644 modules/server/sections/groups/ox.lua create mode 100644 modules/server/sections/groups/qb.lua create mode 100644 modules/server/sections/groups/qbx.lua create mode 100644 modules/server/sections/indicators.lua create mode 100644 modules/server/sections/players.lua create mode 100644 resource/client.lua delete mode 100644 resource/client/client.lua delete mode 100644 resource/client/locales.lua create mode 100644 resource/server.lua delete mode 100644 resource/server/framework.lua delete mode 100644 resource/server/server.lua delete mode 100644 resource/server/version.lua create mode 100644 web/.gitattributes create mode 100644 web/.prettierrc create mode 100644 web/bun.lockb delete mode 100644 web/pnpm-lock.yaml create mode 100644 web/postcss.config.cjs create mode 100644 web/public/logo.svg create mode 100644 web/src/App.svelte delete mode 100644 web/src/App.tsx delete mode 100644 web/src/components/Footer.tsx delete mode 100644 web/src/components/Scoreboard.tsx delete mode 100644 web/src/components/body/GroupList.tsx delete mode 100644 web/src/components/body/PlayerList.tsx delete mode 100644 web/src/components/body/SectionHeader.tsx create mode 100644 web/src/components/footer.svelte create mode 100644 web/src/components/groups.svelte create mode 100644 web/src/components/lib/sheet/index.ts create mode 100644 web/src/components/lib/sheet/sheet-content.svelte create mode 100644 web/src/components/lib/sheet/sheet-overlay.svelte create mode 100644 web/src/components/lib/sheet/sheet-portal.svelte create mode 100644 web/src/components/lib/tooltip/animation.ts create mode 100644 web/src/components/lib/tooltip/index.ts create mode 100644 web/src/components/lib/tooltip/tooltip-content.svelte create mode 100644 web/src/components/lib/tooltip/tooltip-trigger.svelte create mode 100644 web/src/components/players.svelte create mode 100644 web/src/components/status-indicators.svelte create mode 100644 web/src/components/title.svelte delete mode 100644 web/src/hooks/useNuiEvent.ts delete mode 100644 web/src/index.css create mode 100644 web/src/index.pcss delete mode 100644 web/src/interfaces/group.ts delete mode 100644 web/src/interfaces/locale.ts delete mode 100644 web/src/interfaces/player.ts create mode 100644 web/src/main.ts delete mode 100644 web/src/main.tsx create mode 100644 web/src/providers/VisibilityProvider.svelte delete mode 100644 web/src/providers/VisibilityProvider.tsx create mode 100644 web/src/store/config.ts create mode 100644 web/src/store/data.ts create mode 100644 web/src/store/locales.ts create mode 100644 web/src/store/visibility.ts delete mode 100644 web/src/theme/index.ts create mode 100644 web/src/types/config.ts create mode 100644 web/src/types/data.ts create mode 100644 web/src/types/locales.ts create mode 100644 web/src/utils/useNuiEvent.ts create mode 100644 web/svelte.config.js create mode 100644 web/tailwind.config.ts diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 91b9421..79d5a38 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -17,7 +17,7 @@ body: description: | What release version was this issue encountered on? Use the version number, not `latest` or similar useless stuff. - placeholder: v1.0.2 + placeholder: v2.0.0 validations: required: true @@ -28,8 +28,9 @@ body: description: What framework are you getting this error on? options: - ox_core - - es_extended + - qbx_core - qb-core + - es_extended multiple: true validations: required: true @@ -68,3 +69,5 @@ body: required: true - label: "I have provided a **detailed** issue description and **detailed** reproduction steps." required: true + - label: "I have read the documentation." + required: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c1ab27..7622675 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,59 +1,51 @@ name: Create new release on: + workflow_dispatch: push: tags: - 'v*.*.*' jobs: - new-release: - name: Build and create new release + release: runs-on: ubuntu-latest - steps: - name: Get latest code - uses: actions/checkout@v3 - - - name: Setup pnpm - uses: pnpm/action-setup@v2.2.4 - with: - version: latest + uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v3 + - name: Setup Bun + uses: oven-sh/setup-bun@v2 with: - node-version: 16.x - cache: 'pnpm' - cache-dependency-path: 'web/pnpm-lock.yaml' + bun-version: latest - name: Install dependencies - run: pnpm install + run: bun install working-directory: web - name: Run build script - run: pnpm build + run: bun run build working-directory: web - name: Update tag - uses: EndBug/latest-tag@v1.5.0 + uses: EndBug/latest-tag@v1 with: ref: ${{ github.ref_name }} - name: Install zip run: sudo apt install zip - - name: Bundle built files + - name: Bundle files run: | mkdir -p ./temp/ac_scoreboard + mkdir -p ./temp/ac_scoreboard/web/ cp ./{LICENSE,README.md,fxmanifest.lua,config.lua} ./temp/ac_scoreboard - cp -r ./{resource,locales} ./temp/ac_scoreboard - mkdir ./temp/ac_scoreboard/web/ + cp -r ./{locales,modules,resource} ./temp/ac_scoreboard cp -r ./web/build ./temp/ac_scoreboard/web/ cd ./temp && zip -r ../ac_scoreboard.zip ./ac_scoreboard - name: Create release - uses: marvinpinto/action-automatic-releases@v1.2.1 + uses: softprops/action-gh-release@v2 with: - repo_token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ github.token }} prerelease: false files: ac_scoreboard.zip diff --git a/LICENSE b/LICENSE index f288702..0d75779 100644 --- a/LICENSE +++ b/LICENSE @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + AC Scoreboard + Copyright © 2024 AC Scripts () This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -647,25 +647,6 @@ the "copyright" line and a pointer to where the full notice is found. You should have received a copy of the GNU General Public License along with this program. If not, see . -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with diff --git a/README.md b/README.md index 7d04020..f2dc6bc 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,48 @@ -### Introduction -ac_scoreboard is the ultimate standalone scoreboard solution for your server. +![](https://img.shields.io/github/downloads/acscripts/ac_scoreboard/total?logo=github) +![](https://img.shields.io/github/v/release/acscripts/ac_scoreboard?logo=github) -You can use any supported framework to enable additional features such as group (job) list. -Supported frameworks are [ox_core](https://github.com/overextended/ox_core), [es_extended](https://github.com/esx-framework/esx-legacy) and [qb-core](https://github.com/qbcore-framework/qb-core). +## Introduction +**AC Scoreboard** is the ultimate standalone scoreboard solution for your server. -Report bugs using [GitHub issues](https://github.com/antond15/ac_scoreboard/issues). Use the official [Discord server](https://discord.gg/2ZezMw2xvR) for support. +You can use any supported framework to enable additional features such as group list. +Supported frameworks are [ox_core](https://github.com/overextended/ox_core), [qbx_core](https://github.com/Qbox-project/qbx_core), [qb-core](https://github.com/qbcore-framework/qb-core) and [es_extended](https://github.com/esx-framework/esx_core). -### Features -- Customizable server name +Report bugs using [GitHub issues](https://github.com/acscripts/ac_scoreboard/issues). Use the official [Discord server](https://discord.acscripts.dev) for support. + +## Features +- Customizable title (server name and logo) - Group list with each group's player count - Player list with their server ID +- Status indicators that can be used for anything (e.g. if players can rob stores) - Select on which side of the screen is the scoreboard +- Customizable UI settings (background blur, close behavior) - Choose what parts should be visible -- Detailed config explanation - Total player count and copyable server ID -- Configurable key mapping and command name -- Support for custom locales -### Common issues -Possible solutions can be found [here](./docs/common_issues.md). +## Documentation +➡️ [docs.acscripts.dev/scoreboard](https://docs.acscripts.dev/scoreboard) ⬅️ + +## Showcase + + YouTube Showcase + + +[youtu.be/D_S4OmYOKJA](https://youtu.be/D_S4OmYOKJA) + +--- + +## Copyright +Copyright © 2024 AC Scripts () + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. -### Preview -https://youtu.be/M7YQ5vicwKo +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. -scoreboard preview +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/config.lua b/config.lua index 2d392a0..28e078d 100644 --- a/config.lua +++ b/config.lua @@ -1,47 +1,77 @@ ---------------------------------------------------------------------------------------------- --- More detailed description of each config option can be found in 'docs/config.md' file. ---------------------------------------------------------------------------------------------- - -ac = { - -- Language for the UI - locale = 'en', - - -- Whether to check for newer resource version and notify in server console. - versionCheck = true, - - -- Server name shown in the scoreboard header. - serverName = 'AC Scoreboard', - - -- Command name to open the scoreboard UI. - commandName = 'scoreboard', - - -- Default keybind for the '/scoreboard' command. - commandKey = 'DELETE', - - -- Which parts of the scoreboard should be visible (both, groups, players). - visibleParts = 'both', - - -- On which side of the screen the scoreboard should be (left, right). - drawerSide = 'right', - - -- Group list shown in the scoreboard. - groupList = { - { - label = 'Police', - groups = {'police', 'sheriff'} - }, - { - label = 'EMS', - groups = {'ambulance'}, - separator = true - }, - { - label = 'Taxi', - groups = {'taxi'} - }, - { - label = 'Mechanic', - groups = {'mechanic', 'lsc', 'bennys'} - } - } +----------------------------------------------------------------- +-- Visit https://docs.acscripts.dev/scoreboard for documentation +----------------------------------------------------------------- + +return { + settings = { + title = { + text = 'AC Scoreboard', + logo = 'https://cfx-nui-ac_scoreboard/web/build/logo.svg', + }, + + side = 'right', + + showOverlay = false, + + closeOnEscape = true, + + closeOnOutsideClick = true, + + uppercaseNames = false, + + highlightEmptyGroups = true, + + compactPlayers = false, + + compactGroups = false, + + playerColumns = 1, + + groupColumns = 1, + }, + + visibleSections = { + groups = true, + players = true, + playerNames = true, + playerIds = true, + statusIndicators = true, + footer = true, + }, + + -- Command name for opening the scoreboard + commandName = 'scoreboard', + + -- Default keybind for the '/scoreboard' command + commandKey = 'DELETE', + + -- Whether to include off-duty players in group count + includeOffDuty = false, + + -- Group list shown in the scoreboard + groups = { + { + label = 'Police', + groups = {'police', 'sheriff'}, + }, + { + label = 'EMS', + groups = {'ambulance'}, + }, + { + label = 'Mechanics', + groups = {'lsc', 'bennys', 'hayes'}, + }, + { + label = 'Taxi', + groups = {'taxi'}, + }, + }, + + -- Status indicators shown in the scoreboard + statusIndicators = { + { id = 'house_robbery', label = 'House robbery', icon = 'mdi:house', defaultState = true }, + { id = 'store_robbery', label = 'Store robbery', icon = 'mdi:store', defaultState = false }, + { id = 'bank_robbery', label = 'Bank robbery', icon = 'mdi:bank' }, + }, } diff --git a/docs/common_issues.md b/docs/common_issues.md deleted file mode 100644 index b08f81e..0000000 --- a/docs/common_issues.md +++ /dev/null @@ -1,22 +0,0 @@ -# Something doesn't work -Didn't find your answer here? Visit the [Discord server](https://discord.gg/2ZezMw2xvR) for support. - -## Unbuilt UI -This resource uses React for the UI part which must be built before using on your server. -You can build it yourself (if you know how) or download the [> **RELEASE** <](https://github.com/antond15/ac_scoreboard/releases/latest) from GitHub. -If you use the green button to download it from GitHub, it won't work straight away. - -## Latest version -Make sure you have the latest version of all required resources. - -**Downloads** -• [Latest version of ac_scoreboard](https://github.com/antond15/ac_scoreboard/releases/latest) -• Latest version of your chosen framework - -## Start order -ac_scoreboard must be started **AFTER** your framework. - -```cfg -ensure -ensure ac_scoreboard -``` diff --git a/docs/config.md b/docs/config.md deleted file mode 100644 index 3825ffe..0000000 --- a/docs/config.md +++ /dev/null @@ -1,108 +0,0 @@ -# Config explanation -In this file you can find more detailed description of each config option. - -
-Quick navigation - -- [locale](#locale) -- [versionCheck](#versioncheck) -- [serverName](#servername) -- [commandName](#commandname) -- [commandKey](#commandkey) -- [visibleParts](#visibleparts) -- [drawerSide](#drawerside) -- [groupList](#grouplist) -
- -
- -## locale -What supported language to use for the UI. -Locale name is the same as the file name in [locales](../locales) folder without the `.lua` extension (eg. **en**, **cs**). -Feel free to submit a PR with more languages! - -**Accepted values** -`'en'` = Or any other locale. - - - -## versionCheck -Whether to check for newer resource version and notify in server console. - -**Accepted values** -`true` = You will be notified in server console when a newer version of **ac_scoreboard** is available. -`false` = You will need to manually check for a newer version on GitHub 👎🏽 - - - -## serverName -Server name shown in the header of the scoreboard. - -**Accepted values** -`'My cool RP server'` = Or any other string value - - - -## commandName -Command name for opening the scoreboard. - -**Accepted values** -`'scoreboard'` = Or any other string value - - - -## commandKey -Default keybind for the scoreboard command. - -**Accepted values** -`false` = The keybind will not be created at all. -`''` = Empty quotes for creating the keybind, but not setting a default key. -`'DELETE'` = Or any other [valid key](https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard) to create a keybind with **this** default key. - - - -## visibleParts -Which parts of the scoreboard should be visible. - -**Accepted values** -`'both'` = Both groups and players will be visible. -`'groups'` = Only groups will be visible. -`'players'` = Only players will be visible. - - - -## drawerSide -On which side of the screen the scoreboard should be. - -**Accepted values** -`'left'` = Left. -`'right'` = Right. - - - -## groupList -List of groups which will be visible in the scoreboard UI with their total count. -Order in the UI is the same as in the config! - -**Accepted values** -```lua -{ - label = 'Label for the groups below', - groups = {'any valid', 'groups'}, - separator = true -- optional, will add a separator line under this group -} -``` - -**Example config data** -```lua -groupList = { - { -- Number of players in 'police' and/or 'sheriff' group will be shown under the 'Police' label. - label = 'Police', - groups = {'police', 'sheriff'} - }, - { -- Number of players in 'ambulance' group will be shown under the 'EMS' label. - label = 'EMS', - groups = {'ambulance'} - }, -} -``` \ No newline at end of file diff --git a/fxmanifest.lua b/fxmanifest.lua index bf268b0..ffe4ee0 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,31 +1,35 @@ fx_version 'cerulean' game 'gta5' lua54 'yes' +use_experimental_fxv2_oal 'yes' name 'ac_scoreboard' -author 'ANTOND.#8507' -version '1.0.4' +author 'AC Scripts' +version '2.0.0' description 'A framework-standalone scoreboard UI for FiveM.' -repository 'https://github.com/antond15/ac_scoreboard' +repository 'https://github.com/acscripts/ac_scoreboard' -shared_script 'config.lua' +shared_script '@ox_lib/init.lua' +server_script 'resource/server.lua' +client_script 'resource/client.lua' -server_scripts { - 'resource/server/server.lua', - 'resource/server/framework.lua', - 'resource/server/version.lua' -} - -client_scripts { - 'resource/client/locales.lua', - 'resource/client/client.lua' -} ui_page 'web/build/index.html' files { 'web/build/index.html', 'web/build/**/*', - 'locales/*.lua' + 'config.lua', + 'modules/client/*.lua', + 'locales/*.json', +} + + +ox_libs { + 'locale', +} + +dependencies { + 'ox_lib', } diff --git a/locales/bg.lua b/locales/bg.lua deleted file mode 100644 index 75b8228..0000000 --- a/locales/bg.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - ['ui_group'] = "Група", - ['ui_count'] = "Брой", - ['ui_name'] = "Име", - ['ui_id'] = "ЕГН", - ['ui_player_count'] = "Брой на играчите", - ['ui_your_id'] = "Твоето ЕГН", - ['ui_copied'] = "Копирано!", - - ['command_open'] = "Отваря скорборда", - ['keymap_open'] = "Oтвори скорборда", -} diff --git a/locales/cs.json b/locales/cs.json new file mode 100644 index 0000000..f5edab0 --- /dev/null +++ b/locales/cs.json @@ -0,0 +1,11 @@ +{ + "ui": { + "groups": "Skupiny", + "players": "Hráči", + "copy_server_id": "Zkopírovat své server ID", + "server_id_copied": "Server ID zkopírováno", + "anonymous_player": "Anonymní hráč" + }, + "command_open": "Otevře rozhraní scoreboardu", + "keymap_open": "Otevřít scoreboard" +} diff --git a/locales/cs.lua b/locales/cs.lua deleted file mode 100644 index a07a0bd..0000000 --- a/locales/cs.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - ['ui_group'] = "Zaměstnání", - ['ui_count'] = "Počet", - ['ui_name'] = "Jméno", - ['ui_id'] = "ID", - ['ui_player_count'] = "Počet hráčů", - ['ui_your_id'] = "Tvé ID", - ['ui_copied'] = "Zkopírováno do schránky!", - - ['command_open'] = "Otevře scoreboard", - ['keymap_open'] = "Otevřít scoreboard", -} diff --git a/locales/en.json b/locales/en.json new file mode 100644 index 0000000..256dafd --- /dev/null +++ b/locales/en.json @@ -0,0 +1,11 @@ +{ + "ui": { + "groups": "Groups", + "players": "Players", + "copy_server_id": "Copy your server ID", + "server_id_copied": "Server ID copied", + "anonymous_player": "Anonymous player" + }, + "command_open": "Opens the scoreboard UI", + "keymap_open": "Open scoreboard UI" +} diff --git a/locales/en.lua b/locales/en.lua deleted file mode 100644 index 2d71c3f..0000000 --- a/locales/en.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - ['ui_group'] = "Group", - ['ui_count'] = "Count", - ['ui_name'] = "Name", - ['ui_id'] = "ID", - ['ui_player_count'] = "Player count", - ['ui_your_id'] = "Your server ID", - ['ui_copied'] = "Copied to clipboard!", - - ['command_open'] = "Opens the scoreboard UI", - ['keymap_open'] = "Open scoreboard UI", -} diff --git a/locales/et.lua b/locales/et.lua deleted file mode 100644 index ec4a532..0000000 --- a/locales/et.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - ['ui_group'] = "Töökoht", - ['ui_count'] = "Tööl", - ['ui_name'] = "Nimi", - ['ui_id'] = "ID", - ['ui_player_count'] = "Mängijate arv", - ['ui_your_id'] = "Sinu ID", - ['ui_copied'] = "Kopeeritud!", - - ['command_open'] = "Avad listi!", - ['keymap_open'] = "Ava list", -} diff --git a/locales/sk.json b/locales/sk.json new file mode 100644 index 0000000..f8d0cfa --- /dev/null +++ b/locales/sk.json @@ -0,0 +1,11 @@ +{ + "ui": { + "groups": "Skupiny", + "players": "Hráči", + "copy_server_id": "Skopírovať svoje server ID", + "server_id_copied": "Server ID skopírované", + "anonymous_player": "Anonymný hráč" + }, + "command_open": "Otvorí rozhranie scoreboardu", + "keymap_open": "Otvoriť scoreboard" +} diff --git a/modules/client/main.lua b/modules/client/main.lua new file mode 100644 index 0000000..3e494b4 --- /dev/null +++ b/modules/client/main.lua @@ -0,0 +1,102 @@ +local Config = require 'config' +local isOpened = false + + +local function openScoreboard() + if isOpened then + isOpened = false + return SendNUIMessage({ + action = 'setVisible', + data = false, + }) + end + + isOpened = true + + local data = lib.callback.await('ac_scoreboard:getServerData', false) + + if data.groups then + local groups = {} + + for index, group in ipairs(Config.groups) do + groups[index] = { + label = group.label, + count = data.groups[index], + } + end + + data.groups = groups + end + + if data.statusIndicators then + local indicators = {} + + for index, indicator in ipairs(Config.statusIndicators) do + indicators[index] = { + label = indicator.label, + icon = indicator.icon, + state = data.statusIndicators[index], + } + end + + data.statusIndicators = indicators + end + + if data.footer then + data.footer.serverId = cache.serverId + end + + SendNUIMessage({ + action = 'setData', + data = data, + }) + + SetNuiFocus(true, true) + SetNuiFocusKeepInput(true) + SetCursorLocation(Config.settings.side == 'right' and 0.8 or 0.2, 0.5) + + SendNUIMessage({ + action = 'setVisible', + data = true, + }) + + while isOpened do + HudWeaponWheelIgnoreSelection() + DisablePlayerFiring(cache.playerId, true) + DisableControlAction(0, 1, true) -- INPUT_LOOK_LR + DisableControlAction(0, 2, true) -- INPUT_LOOK_UD + DisableControlAction(0, 200, true) -- INPUT_FRONTEND_PAUSE_ALTERNATE + Wait(0) + end + + while IsDisabledControlPressed(0, 200) do + DisableControlAction(0, 200, true) + Wait(0) + end + + SetNuiFocus(false, false) + SetNuiFocusKeepInput(false) +end + +RegisterNUICallback('close', function(_, cb) + cb(1) + isOpened = false +end) + + +TriggerEvent('chat:addSuggestion', ('/%s'):format(Config.commandName), locale('command_open')) +RegisterCommand(Config.commandName, openScoreboard, false) + +if Config.commandKey then + RegisterKeyMapping(Config.commandName, locale('keymap_open'), 'keyboard', Config.commandKey) +end + + +AddEventHandler('onResourceStop', function(resource) + if resource == cache.resource then + if isOpened then + SetNuiFocus(false, false) + SetNuiFocusKeepInput(false) + end + end +end) diff --git a/modules/client/setup.lua b/modules/client/setup.lua new file mode 100644 index 0000000..afcbc27 --- /dev/null +++ b/modules/client/setup.lua @@ -0,0 +1,46 @@ +local Config = require 'config' + + +---@return table +local function getUiLocales() + local locales = lib.getLocales() + local uiLocales = {} + + for key, locale in pairs(locales) do + local uiKey = key:match('^ui%.(.+)') + + if uiKey then + uiLocales[uiKey] = locale + end + end + + return uiLocales +end + + +RegisterNUICallback('ready', function(_, cb) + cb(1) + + SendNUIMessage({ + action = 'setConfig', + data = Config.settings, + }) + + SendNUIMessage({ + action = 'setLocales', + data = getUiLocales(), + }) +end) + +AddEventHandler('ox_lib:setLocale', function() + SendNUIMessage({ + action = 'setLocales', + data = getUiLocales(), + }) +end) + + +RegisterNUICallback('copyServerId', function(_, cb) + cb(1) + lib.setClipboard(tostring(cache.serverId)) +end) diff --git a/modules/server/main.lua b/modules/server/main.lua new file mode 100644 index 0000000..69a38e7 --- /dev/null +++ b/modules/server/main.lua @@ -0,0 +1,72 @@ +local Config = require 'config' + +lib.versionCheck('acscripts/ac_scoreboard') + + +local visibleSections = Config.visibleSections +local Players = nil +local Groups = nil +local Indicators = nil + +SetTimeout(0, function() + if visibleSections.players then + Players = require 'modules.server.sections.players' + end + + if visibleSections.groups then + if GetResourceState('ox_core') == 'started' then + Groups = require 'modules.server.sections.groups.ox' + elseif GetResourceState('es_extended') == 'started' then + Groups = require 'modules.server.sections.groups.esx' + elseif GetResourceState('qbx_core') == 'started' then + Groups = require 'modules.server.sections.groups.qbx' + elseif GetResourceState('qb-core') == 'started' then + Groups = require 'modules.server.sections.groups.qb' + else + lib.print.warn('No compatible framework found. Group section was automatically disabled.') + end + end + + if visibleSections.statusIndicators then + Indicators = require 'modules.server.sections.indicators' + end +end) + + +---@param playerId number +---@param section string +---@return boolean +local function canShowSection(playerId, section) + local state = visibleSections[section] + return state == true or state == 'limited' and IsPlayerAceAllowed(tostring(playerId), ('scoreboard.show.%s'):format(section)) +end + + +---@param playerId number +---@return table +lib.callback.register('ac_scoreboard:getServerData', function(playerId) + local payload = {} + + if Players and canShowSection(playerId, 'players') then + local showPlayerNames = canShowSection(playerId, 'playerNames') + local showPlayerIds = canShowSection(playerId, 'playerIds') + payload.players = Players.getPlayers(showPlayerNames, showPlayerIds) + end + + if Groups and canShowSection(playerId, 'groups') then + payload.groups = Groups.getCounts() + end + + if Indicators and canShowSection(playerId, 'statusIndicators') then + payload.statusIndicators = Indicators.getStates() + end + + if canShowSection(playerId, 'footer') then + payload.footer = { + maxPlayers = GetConvarInt('sv_maxclients', 0), -- still waiting for the day when we can subscribe to convar changes + playerCount = GetNumPlayerIndices(), + } + end + + return payload +end) diff --git a/modules/server/sections/groups/esx.lua b/modules/server/sections/groups/esx.lua new file mode 100644 index 0000000..b6abb4e --- /dev/null +++ b/modules/server/sections/groups/esx.lua @@ -0,0 +1,136 @@ +local Config = require 'config' +local Players = {} +local Groups = {} + +local hasDutySystem = lib.checkDependency('es_extended', '1.11.0', false) + + +---@param groupName string +local function addMember(groupName) + Groups[groupName] = (Groups[groupName] or 0) + 1 +end + +---@param groupName string +local function removeMember(groupName) + Groups[groupName] = (Groups[groupName] or 1) - 1 +end + +---@param group table +---@return string, boolean +local function getGroupData(group) + if hasDutySystem then + return group.name, group.onDuty + end + + local groupName = group.name + local onDuty = true + + if groupName:sub(1, 4) == 'off_' then + groupName = groupName:sub(5) + onDuty = false + end + + return groupName, onDuty +end + + +CreateThread(function() + local ESX = exports.es_extended:getSharedObject() + + for _, player in ipairs(ESX.GetExtendedPlayers()) do + local groupName, onDuty = getGroupData(player.job) + + Players[player.source] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end + end +end) + + +---@param player table +AddEventHandler('esx:playerLoaded', function(_, player) + local groupName, onDuty = getGroupData(player.job) + + Players[player.source] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end +end) + +---@param playerId number +---@param group table +AddEventHandler('esx:setJob', function(playerId, group) + local oldGroup = Players[playerId] + if not oldGroup then return end + + local groupName, onDuty = getGroupData(group) + + Players[playerId] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty then + removeMember(oldGroup.name) + addMember(groupName) + else + if oldGroup.onDuty then + removeMember(oldGroup.name) + end + + if onDuty then + addMember(groupName) + end + end +end) + + +---@param playerId number +local function removePlayer(playerId) + local group = Players[playerId] + if not group then return end + + local groupName, onDuty = getGroupData(group) + + if Config.includeOffDuty or onDuty then + removeMember(groupName) + end + + Players[playerId] = nil +end + +AddEventHandler('esx:playerLogout', removePlayer) +AddEventHandler('playerDropped', function() + removePlayer(source) +end) + + +local function getCounts() + local counts = {} + + for index, group in ipairs(Config.groups) do + local totalCount = 0 + + for _, groupName in ipairs(group.groups) do + totalCount += Groups[groupName] or 0 + end + + counts[index] = totalCount + end + + return counts +end + + +return { + getCounts = getCounts, +} diff --git a/modules/server/sections/groups/ox.lua b/modules/server/sections/groups/ox.lua new file mode 100644 index 0000000..cb1d0cf --- /dev/null +++ b/modules/server/sections/groups/ox.lua @@ -0,0 +1,26 @@ +if not lib.checkDependency('ox_core', '1.1.3', true) then return end + +local Config = require 'config' +local COUNT_TYPE = Config.includeOffDuty and 'count' or 'activeCount' + + +local function getCounts() + local counts = {} + + for index, group in ipairs(Config.groups) do + local totalCount = 0 + + for _, groupName in ipairs(group.groups) do + totalCount += GlobalState[('%s:%s'):format(groupName, COUNT_TYPE)] or 0 + end + + counts[index] = totalCount + end + + return counts +end + + +return { + getCounts = getCounts, +} diff --git a/modules/server/sections/groups/qb.lua b/modules/server/sections/groups/qb.lua new file mode 100644 index 0000000..2cd79f4 --- /dev/null +++ b/modules/server/sections/groups/qb.lua @@ -0,0 +1,123 @@ +local Config = require 'config' +local Players = {} +local Groups = {} + + +---@param groupName string +local function addMember(groupName) + Groups[groupName] = (Groups[groupName] or 0) + 1 +end + +---@param groupName string +local function removeMember(groupName) + Groups[groupName] = (Groups[groupName] or 1) - 1 +end + +--- To eliminate confusion between `onDuty` and `onduty` +---@param job table +---@return string, boolean +local function getGroupData(job) + return job.name, job.onduty +end + + +CreateThread(function() + local QB = exports['qb-core']:GetCoreObject() + + for _, player in ipairs(QB.Functions.GetQBPlayers()) do + player = player.PlayerData + local groupName, onDuty = getGroupData(player.job) + + Players[player.source] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end + end +end) + + +---@param player table +AddEventHandler('QBCore:Server:PlayerLoaded', function(player) + player = player.PlayerData + local groupName, onDuty = getGroupData(player.job) + + Players[player.source] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end +end) + +---@param playerId number +---@param group table +AddEventHandler('QBCore:Server:OnJobUpdate', function(playerId, group) + local oldGroup = Players[playerId] + if not oldGroup then return end + + local groupName, onDuty = getGroupData(group) + + Players[playerId] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty then + removeMember(oldGroup.name) + addMember(groupName) + else + if oldGroup.onDuty then + removeMember(oldGroup.name) + end + + if onDuty then + addMember(groupName) + end + end +end) + + +---@param playerId number +local function removePlayer(playerId) + local group = Players[playerId] + if not group then return end + + if Config.includeOffDuty or group.onDuty then + removeMember(group.name) + end + + Players[playerId] = nil +end + +AddEventHandler('QBCore:Server:OnPlayerUnload', removePlayer) +AddEventHandler('playerDropped', function() + removePlayer(source) +end) + + +local function getCounts() + local counts = {} + + for index, group in ipairs(Config.groups) do + local totalCount = 0 + + for _, groupName in ipairs(group.groups) do + totalCount += Groups[groupName] or 0 + end + + counts[index] = totalCount + end + + return counts +end + + +return { + getCounts = getCounts, +} diff --git a/modules/server/sections/groups/qbx.lua b/modules/server/sections/groups/qbx.lua new file mode 100644 index 0000000..a5956a0 --- /dev/null +++ b/modules/server/sections/groups/qbx.lua @@ -0,0 +1,140 @@ +local Config = require 'config' +local Players = {} +local Groups = {} + + +---@param groupName string +local function addMember(groupName) + Groups[groupName] = (Groups[groupName] or 0) + 1 +end + +---@param groupName string +local function removeMember(groupName) + Groups[groupName] = (Groups[groupName] or 1) - 1 +end + +--- To eliminate confusion between `onDuty` and `onduty` +---@param job table +---@return string, boolean +local function getGroupData(job) + return job.name, job.onduty +end + + +CreateThread(function() + for playerId, player in pairs(exports.qbx_core:GetQBPlayers()) do + player = player.PlayerData + local groupName, onDuty = getGroupData(player.job) + + Players[playerId] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end + end +end) + + +---@param player table +AddEventHandler('QBCore:Server:PlayerLoaded', function(player) + player = player.PlayerData + local groupName, onDuty = getGroupData(player.job) + + Players[player.source] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty or onDuty then + addMember(groupName) + end +end) + +---@param playerId number +---@param group table +AddEventHandler('QBCore:Server:OnJobUpdate', function(playerId, group) + local oldGroup = Players[playerId] + if not oldGroup then return end + + local groupName, onDuty = getGroupData(group) + + Players[playerId] = { + name = groupName, + onDuty = onDuty, + } + + if Config.includeOffDuty then + removeMember(oldGroup.name) + addMember(groupName) + else + if oldGroup.onDuty then + removeMember(oldGroup.name) + end + + if onDuty then + addMember(groupName) + end + end +end) + +---@param playerId number +---@param onDuty boolean +AddEventHandler('QBCore:Server:SetDuty', function(playerId, onDuty) + local oldGroup = Players[playerId] + if not oldGroup then return end + + if not Config.includeOffDuty then + if not onDuty and oldGroup.onDuty then + removeMember(oldGroup.name) + end + + if onDuty and not oldGroup.onDuty then + addMember(oldGroup.name) + end + end + + Players[playerId].onDuty = onDuty +end) + + +---@param playerId number +local function removePlayer(playerId) + local group = Players[playerId] + if not group then return end + + if Config.includeOffDuty or group.onDuty then + removeMember(group.name) + end + + Players[playerId] = nil +end + +AddEventHandler('QBCore:Server:OnPlayerUnload', removePlayer) +AddEventHandler('playerDropped', function() + removePlayer(source) +end) + + +local function getCounts() + local counts = {} + + for index, group in ipairs(Config.groups) do + local totalCount = 0 + + for _, groupName in ipairs(group.groups) do + totalCount += Groups[groupName] or 0 + end + + counts[index] = totalCount + end + + return counts +end + + +return { + getCounts = getCounts, +} diff --git a/modules/server/sections/indicators.lua b/modules/server/sections/indicators.lua new file mode 100644 index 0000000..4d06b16 --- /dev/null +++ b/modules/server/sections/indicators.lua @@ -0,0 +1,32 @@ +local Config = require 'config' +local IndicatorMap = {} +local Indicators = {} + +CreateThread(function() + for index, data in ipairs(Config.statusIndicators) do + IndicatorMap[data.id] = index + Indicators[index] = data.defaultState or false + end +end) + + +---@param id string +---@param state boolean +local function setIndicatorState(id, state) + if not IndicatorMap[id] then return end + local index = IndicatorMap[id] + Indicators[index] = state or false +end + +---@return boolean[] +local function getStates() + return Indicators +end + + +AddEventHandler('ac_scoreboard:setIndicatorState', setIndicatorState) +exports('setIndicatorState', setIndicatorState) + +return { + getStates = getStates, +} diff --git a/modules/server/sections/players.lua b/modules/server/sections/players.lua new file mode 100644 index 0000000..d872c4b --- /dev/null +++ b/modules/server/sections/players.lua @@ -0,0 +1,48 @@ +local Players = {} + +CreateThread(function() + for _, playerId in ipairs(GetPlayers()) do + Players[playerId] = GetPlayerName(playerId) + end +end) + + +AddEventHandler('playerJoining', function() + local playerId = tostring(source) + Players[playerId] = GetPlayerName(playerId) +end) + +AddEventHandler('playerDropped', function() + Players[tostring(source)] = nil +end) + + +---@param playerNames boolean +---@param playerIds boolean +---@return table[] +local function getPlayers(playerNames, playerIds) + local players = {} + local index = 1 + + for id, name in pairs(Players) do + local data = {} + + if playerNames then + data.name = name + end + + if playerIds then + data.id = id + end + + players[index] = data + index += 1 + end + + return players +end + + +return { + getPlayers = getPlayers, +} diff --git a/resource/client.lua b/resource/client.lua new file mode 100644 index 0000000..a2d88e4 --- /dev/null +++ b/resource/client.lua @@ -0,0 +1,2 @@ +require 'modules.client.main' +require 'modules.client.setup' diff --git a/resource/client/client.lua b/resource/client/client.lua deleted file mode 100644 index 4ae2e3b..0000000 --- a/resource/client/client.lua +++ /dev/null @@ -1,115 +0,0 @@ -local opened = false -local playerId = PlayerId() - -local dataPromise = nil -RegisterNetEvent('ac_scoreboard:receiveData', function(data) - if dataPromise then - dataPromise:resolve(data) - dataPromise = nil - end -end) - ----@param action string ----@param data table | boolean -local function sendNuiMessage(action, data) - SendNUIMessage({ - action = action, - data = data - }) -end - -local function handleClose() - SetNuiFocus(false, false) - SetNuiFocusKeepInput(false) - opened = false -end - -local function getGroups() - local groupData = {} - for i=1, #ac.groupList do - local group = ac.groupList[i] - local count = 0 - for j=1, #group.groups do - count += GlobalState[('%s:count'):format(group.groups[j])] or 0 - end - - groupData[#groupData + 1] = { - label = group.label, - count = count, - separator = group.separator or nil - } - end - - return groupData -end - -local function getUiLocales() - local uiLocales = {} - for k,v in pairs(locales) do - if k:find('ui_') then - uiLocales[k] = v - end - end - - return uiLocales -end - -local initialDataSet = false -local function setData() - dataPromise = promise.new() - TriggerServerEvent('ac_scoreboard:requestData') - local data = Citizen.Await(dataPromise) - - if not initialDataSet then - initialDataSet = true - data.serverName = ac.serverName - data.visibleParts = ac.visibleParts - data.drawerSide = ac.drawerSide - data.serverId = GetPlayerServerId(playerId) - data.locales = getUiLocales() - end - - data.groups = getGroups() - - sendNuiMessage('setData', data) -end - -if ac.commandKey then - RegisterKeyMapping(ac.commandName, locale('keymap_open'), 'keyboard', ac.commandKey) -end - -TriggerEvent('chat:addSuggestion', ('/%s'):format(ac.commandName), locale('command_open')) -RegisterCommand(ac.commandName, function() - if opened then - handleClose() - sendNuiMessage('setVisible', false) - return - end - - opened = true - - CreateThread(function() - while opened do - DisablePlayerFiring(playerId, true) - HudWeaponWheelIgnoreSelection() - DisableControlAction(0, 1, true) - DisableControlAction(0, 2, true) - DisableControlAction(0, 140, true) - DisableControlAction(0, 200, true) - - Wait(0) - end - end) - - setData() - - SetNuiFocus(true, true) - SetNuiFocusKeepInput(true) - - sendNuiMessage('setVisible', true) -end, false) - -RegisterNUICallback('close', function(_, cb) - cb(1) - handleClose() -end) diff --git a/resource/client/locales.lua b/resource/client/locales.lua deleted file mode 100644 index 261ffa3..0000000 --- a/resource/client/locales.lua +++ /dev/null @@ -1,22 +0,0 @@ -local file = LoadResourceFile('ac_scoreboard', ('locales/%s.lua'):format(ac.locale)) -if not file then - file = LoadResourceFile('ac_scoreboard', 'locales/en.lua') - CreateThread(function() - error(('Locale file "%s" not found, fallbacking to default "en".'):format(ac.locale), 0) - end) -end - -local data, err = load(file) -if err then error(err) end - ----@diagnostic disable-next-line: need-check-nil -locales = data() - ----@param key string ----@return string -function locale(key, ...) - if locales[key] then - return locales[key]:format(...) - end - return key -end diff --git a/resource/server.lua b/resource/server.lua new file mode 100644 index 0000000..45d27ca --- /dev/null +++ b/resource/server.lua @@ -0,0 +1,7 @@ +if not LoadResourceFile(cache.resource, 'web/build/index.html') then + error('\n^1Unable to load UI. Build ac_scoreboard yourself or download the latest prebuilt release:\n^4https://github.com/acscripts/ac_scoreboard/releases/latest/download/ac_scoreboard.zip^0\n', 0) +end + +if not lib.checkDependency('ox_lib', '3.27.0', true) then return end + +require 'modules.server.main' diff --git a/resource/server/framework.lua b/resource/server/framework.lua deleted file mode 100644 index 09fca50..0000000 --- a/resource/server/framework.lua +++ /dev/null @@ -1,127 +0,0 @@ ----@param name string ----@return boolean -local function hasResource(name) - return GetResourceState(name):find('start') ~= nil -end - -local core = (hasResource('es_extended') and 'esx') or (hasResource('qb-core') and 'qb') or (hasResource('ox_core') and 'ox') or '' -if core ~= 'esx' and core ~= 'qb' then return end - - -local count = {} -local players = {} - ----@class JobData ----@field name string Job name ----@field onDuty boolean? ----@field source number - -local jobs = { - ---@param job string Job name - add = function(job) - count[job] = (count[job] or 0) + 1 - GlobalState[('%s:count'):format(job)] = count[job] - end, - - ---@param job string Job name - remove = function(job) - count[job] = (count[job] or 1) - 1 - GlobalState[('%s:count'):format(job)] = count[job] - end, - - ---@param data JobData - loaded = function(self, data) - local onDuty = data.onDuty == nil or data.onDuty - - players[data.source] = { - name = data.name, - onDuty = onDuty, - } - - if onDuty then self.add(data.name) end - end, - - ---@param data JobData - update = function(self, data) - local lastJob = players[data.source] - if not lastJob then return end - - local onDuty = data.onDuty == nil or data.onDuty - if data.name == lastJob.name and onDuty == lastJob.onDuty then return end - - players[data.source] = { - name = data.name, - onDuty = onDuty, - } - - if onDuty then self.add(data.name) end - if lastJob.onDuty then self.remove(lastJob.name) end - end -} - -AddEventHandler('playerDropped', function() - local lastJob = players[source] - players[source] = nil - - if lastJob?.onDuty then jobs.remove(lastJob.name) end -end) - - -if core == 'esx' then - -- Credits to Linden (https://gist.github.com/thelindat/93311a4fd6ea6c1d4427438a533e228c) - local ESX = exports.es_extended:getSharedObject() - - for _, player in pairs(ESX.GetExtendedPlayers()) do - jobs:loaded({ - name = player.job.name, - onDuty = player.job.onDuty, - source = player.source - }) - end - - AddEventHandler('esx:playerLoaded', function(_, player) - jobs:loaded({ - name = player.job.name, - onDuty = player.job.onDuty, - source = player.source - }) - end) - - AddEventHandler('esx:setJob', function(playerId, job) - jobs:update({ - name = job.name, - onDuty = job.onDuty, - source = playerId - }) - end) - -elseif core == 'qb' then - local QB = exports['qb-core']:GetCoreObject() - - for _, player in pairs(QB.Functions.GetQBPlayers()) do - player = player.PlayerData - jobs:loaded({ - name = player.job.name, - onDuty = player.job.onduty, - source = player.source - }) - end - - AddEventHandler('QBCore:Server:PlayerLoaded', function(player) - player = player.PlayerData - jobs:loaded({ - name = player.job.name, - onDuty = player.job.onduty, - source = player.source - }) - end) - - AddEventHandler('QBCore:Player:SetPlayerData', function(player) - jobs:update({ - name = player.job.name, - onDuty = player.job.onduty, - source = player.source - }) - end) - -end diff --git a/resource/server/server.lua b/resource/server/server.lua deleted file mode 100644 index b19a127..0000000 --- a/resource/server/server.lua +++ /dev/null @@ -1,39 +0,0 @@ -local players = {} -local maxPlayers = GetConvarInt('sv_maxclients', 32) -local lastMaxPlayers = os.time() - ----@param playerId string -local function addPlayer(playerId) - if not players[playerId] then - players[playerId] = GetPlayerName(playerId) - end -end - -AddEventHandler('playerJoining', function() - addPlayer(tostring(source)) -end) - -AddEventHandler('playerDropped', function() - players[tostring(source)] = nil -end) - -CreateThread(function() - for _, playerId in pairs(GetPlayers()) do - addPlayer(playerId) - end -end) - -RegisterNetEvent('ac_scoreboard:requestData', function() - -- Convar change handlers are "not really important or worth the risk of badly designing stuff", - -- so we update 'maxPlayers' every 5 minutes if called, like a dicks. - if os.time() - lastMaxPlayers > 300 then - maxPlayers = GetConvarInt('sv_maxclients', 32) - lastMaxPlayers = os.time() - end - - TriggerClientEvent('ac_scoreboard:receiveData', source, { - players = players, - playerCount = GetNumPlayerIndices(), - maxPlayers = maxPlayers - }) -end) diff --git a/resource/server/version.lua b/resource/server/version.lua deleted file mode 100644 index b0f9dad..0000000 --- a/resource/server/version.lua +++ /dev/null @@ -1,34 +0,0 @@ --- Yoinked from https://github.com/overextended/ox_lib/blob/master/resource/version/server.lua -if ac.versionCheck then - local currentVersion = GetResourceMetadata('ac_scoreboard', 'version', 0) - - if currentVersion then - currentVersion = currentVersion:match('%d%.%d+%.%d+') - end - - SetTimeout(1000, function() - PerformHttpRequest('https://api.github.com/repos/acscripts/ac_scoreboard/releases/latest', function(status, response) - if status ~= 200 then return end - - response = json.decode(response) - if response.prerelease then return end - - local latestVersion = response.tag_name:match('%d%.%d+%.%d+') - if not latestVersion or latestVersion == currentVersion then return end - - local cv = { string.strsplit('.', currentVersion) } - local lv = { string.strsplit('.', latestVersion) } - - for i = 1, #cv do - local current, minimum = tonumber(cv[i]), tonumber(lv[i]) - - if current ~= minimum then - if current < minimum then - return print(('^3An update is available for ac_scoreboard (current version: %s)\r\n%s^0'):format(currentVersion, response.html_url)) - else break end - end - end - - end, 'GET') - end) -end diff --git a/web/.gitattributes b/web/.gitattributes new file mode 100644 index 0000000..cc672fe --- /dev/null +++ b/web/.gitattributes @@ -0,0 +1 @@ +*.lockb binary diff=lockb \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore index acc0d09..a62e535 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -1,10 +1,24 @@ -node_modules +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* pnpm-debug.log* +lerna-debug.log* +node_modules build +dist +dist-ssr +*.local -.env -.env.development - -.vscode +# Editor directories and files +.vscode/* .idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web/.prettierrc b/web/.prettierrc new file mode 100644 index 0000000..9d5e825 --- /dev/null +++ b/web/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 120, + "singleQuote": true, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "bracketSpacing": true, + "trailingComma": "es5", + "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"] +} diff --git a/web/bun.lockb b/web/bun.lockb new file mode 100644 index 0000000000000000000000000000000000000000..ee514b561c771375f9763728c4d9b38af647753d GIT binary patch literal 95256 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

#w>yIfT&7Q&SBDC%aq)EzRe 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 literal 0 HcmV?d00001 diff --git a/web/index.html b/web/index.html index 4bbf4c7..18ea430 100644 --- a/web/index.html +++ b/web/index.html @@ -1,12 +1,14 @@ - + - ac_scoreboard + AC Scoreboard + + -

- +
+ diff --git a/web/package.json b/web/package.json index e3d2e52..6dcad0b 100644 --- a/web/package.json +++ b/web/package.json @@ -1,32 +1,34 @@ { - "name": "ac_scoreboard", "private": true, - "version": "0.0.0", + "type": "module", "scripts": { - "start": "vite", - "start:game": "vite build --watch", - "build": "tsc && vite build", + "dev": "vite", + "dev:game": "vite build --watch", + "build": "vite build", "preview": "vite preview", - "format": "prettier --write \"./src/**/*.{ts,tsx,css}\"" + "check": "svelte-check --tsconfig ./tsconfig.json", + "format": "prettier . --write" }, "dependencies": { - "@chakra-ui/react": "^2.4.9", - "@chakra-ui/styled-system": "^2.5.1", - "@emotion/react": "^11.10.5", - "@emotion/styled": "^11.10.5", - "framer-motion": "^9.0.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-icons": "^4.7.1" + "bits-ui": "^0.21.16", + "tailwind-variants": "^0.2.1" }, "devDependencies": { - "@babel/core": "^7.20.12", - "@types/node": "^18.13.0", - "@types/react": "^18.0.27", - "@types/react-dom": "^18.0.10", - "@vitejs/plugin-react": "^3.1.0", - "prettier": "^2.8.3", - "typescript": "^4.9.5", - "vite": "^4.1.1" + "@iconify/svelte": "^4.1.0", + "@sveltejs/vite-plugin-svelte": "^4.0.2", + "@tsconfig/svelte": "^5.0.4", + "autoprefixer": "^10.4.20", + "clsx": "^2.1.1", + "postcss": "^8.4.49", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.2", + "prettier-plugin-tailwindcss": "^0.6.9", + "svelte": "^5.9.0", + "svelte-check": "^4.1.1", + "tailwind-merge": "^2.5.5", + "tailwindcss": "^3.4.16", + "tslib": "^2.8.1", + "typescript": "^5.7.2", + "vite": "^5.4.11" } -} \ No newline at end of file +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml deleted file mode 100644 index e63841c..0000000 --- a/web/pnpm-lock.yaml +++ /dev/null @@ -1,2500 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@chakra-ui/react': - specifier: ^2.4.9 - version: 2.4.9(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(@types/react@18.0.27)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/styled-system': - specifier: ^2.5.1 - version: 2.5.1 - '@emotion/react': - specifier: ^11.10.5 - version: 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - '@emotion/styled': - specifier: ^11.10.5 - version: 11.10.5(@babel/core@7.20.12)(@emotion/react@11.10.5)(@types/react@18.0.27)(react@18.2.0) - framer-motion: - specifier: ^9.0.2 - version: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-icons: - specifier: ^4.7.1 - version: 4.7.1(react@18.2.0) - -devDependencies: - '@babel/core': - specifier: ^7.20.12 - version: 7.20.12 - '@types/node': - specifier: ^18.13.0 - version: 18.13.0 - '@types/react': - specifier: ^18.0.27 - version: 18.0.27 - '@types/react-dom': - specifier: ^18.0.10 - version: 18.0.10 - '@vitejs/plugin-react': - specifier: ^3.1.0 - version: 3.1.0(vite@4.1.1) - prettier: - specifier: ^2.8.3 - version: 2.8.3 - typescript: - specifier: ^4.9.5 - version: 4.9.5 - vite: - specifier: ^4.1.1 - version: 4.1.1(@types/node@18.13.0) - -packages: - - /@ampproject/remapping@2.2.0: - resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.17 - - /@babel/code-frame@7.18.6: - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.18.6 - - /@babel/compat-data@7.20.14: - resolution: {integrity: sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==} - engines: {node: '>=6.9.0'} - - /@babel/core@7.20.12: - resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.14 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.20.12) - '@babel/helper-module-transforms': 7.20.11 - '@babel/helpers': 7.20.13 - '@babel/parser': 7.20.15 - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 - convert-source-map: 1.9.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - /@babel/generator@7.20.14: - resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - '@jridgewell/gen-mapping': 0.3.2 - jsesc: 2.5.2 - - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.20.12): - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.20.14 - '@babel/core': 7.20.12 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.5 - lru-cache: 5.1.1 - semver: 6.3.1 - - /@babel/helper-environment-visitor@7.18.9: - resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} - engines: {node: '>=6.9.0'} - - /@babel/helper-function-name@7.19.0: - resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.20.7 - - /@babel/helper-hoist-variables@7.18.6: - resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - - /@babel/helper-module-imports@7.18.6: - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - - /@babel/helper-module-transforms@7.20.11: - resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.20.2 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 - transitivePeerDependencies: - - supports-color - - /@babel/helper-plugin-utils@7.20.2: - resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} - engines: {node: '>=6.9.0'} - - /@babel/helper-simple-access@7.20.2: - resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - - /@babel/helper-split-export-declaration@7.18.6: - resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - - /@babel/helper-string-parser@7.19.4: - resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-identifier@7.19.1: - resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.18.6: - resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} - engines: {node: '>=6.9.0'} - - /@babel/helpers@7.20.13: - resolution: {integrity: sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 - transitivePeerDependencies: - - supports-color - - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.19.1 - chalk: 2.4.2 - js-tokens: 4.0.0 - - /@babel/parser@7.20.15: - resolution: {integrity: sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.20.7 - - /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.20.12): - resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.20.2 - dev: false - - /@babel/plugin-transform-react-jsx-self@7.18.6(@babel/core@7.20.12): - resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.20.12): - resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/runtime@7.20.13: - resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.11 - dev: false - - /@babel/template@7.20.7: - resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.15 - '@babel/types': 7.20.7 - - /@babel/traverse@7.20.13: - resolution: {integrity: sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.14 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.15 - '@babel/types': 7.20.7 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - - /@babel/types@7.20.7: - resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - - /@chakra-ui/accordion@2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0): - resolution: {integrity: sha512-RTXYhL85dUSVUEurDicxS76JaCXa/L4FYWPAxPSisbZtFvL+/gvoFMcGtT8ZRsJwFWaevmkD+57EmOYCWlLL1A==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/descendant': 3.0.13(react@18.2.0) - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/transition': 2.0.15(framer-motion@9.0.2)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/alert@2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-0Y5vw+HkeXpwbL1roVpSSNM6luMRmUbwduUSHEA4OnX1ismvsDb1ZBfpi4Vxp6w8euJ2Uj6df3krbd5tbCP6tg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/spinner': 2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/anatomy@2.1.2: - resolution: {integrity: sha512-pKfOS/mztc4sUXHNc8ypJ1gPWSolWT770jrgVRfolVbYlki8y5Y+As996zMF6k5lewTu6j9DQequ7Cc9a69IVQ==} - dev: false - - /@chakra-ui/avatar@2.2.4(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-OUuZAhabW0FgmFVt0djH3cVR8p9bKC3vYT3Ol2lrUz3hbf4LrjU5EzmMHmQvcbSs6bNDxS3k9hnswLebOFctJQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/image': 2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/breadcrumb@2.1.4(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-vyBx5TAxPnHhb0b8nyRGfqyjleD//9mySFhk96c9GL+T6YDO4swHw5y/kvDv3Ngc/iRwJ9hdI49PZKwPxLqsEg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/breakpoint-utils@2.0.7: - resolution: {integrity: sha512-YBwsDPMlaMRZ4fKc2WyIIaUmByzkiP4ozxMJIjJRPhedzSho7FOZuE8532q+97f2SyY8z/yZPJ41q4GdwHI/HQ==} - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - dev: false - - /@chakra-ui/button@2.0.16(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-NjuTKa7gNhnGSUutKuTc8HoAOe9WWIigpciBG7yj3ok67kg8bXtSzPyQFZlgTY6XGdAckWTT+Do4tvhwa5LA+g==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/spinner': 2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/card@2.1.6(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-fFd/WAdRNVY/WOSQv4skpy0WeVhhI0f7dTY1Sm0jVl0KLmuP/GnpsWtKtqWjNcV00K963EXDyhlk6+9oxbP4gw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/checkbox@2.2.10(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-vzxEjw99qj7loxAdP1WuHNt4EAvj/t6cc8oxyOB2mEvkAzhxI34rLR+3zWDuHWsmhyUO+XEDh4FiWdR+DK5Siw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/visually-hidden': 2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0) - '@zag-js/focus-visible': 0.2.1 - react: 18.2.0 - dev: false - - /@chakra-ui/clickable@2.0.14(react@18.2.0): - resolution: {integrity: sha512-jfsM1qaD74ZykLHmvmsKRhDyokLUxEfL8Il1VoZMNX5RBI0xW/56vKpLTFF/v/+vLPLS+Te2cZdD4+2O+G6ulA==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - react: 18.2.0 - dev: false - - /@chakra-ui/close-button@2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-05YPXk456t1Xa3KpqTrvm+7smx+95dmaPiwjiBN3p7LHUQVHJd8ZXSDB0V+WKi419k3cVQeJUdU/azDO2f40sw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/color-mode@2.1.12(react@18.2.0): - resolution: {integrity: sha512-sYyfJGDoJSLYO+V2hxV9r033qhte5Nw/wAn5yRGGZnEEN1dKPEdWQ3XZvglWSDTNd0w9zkoH2w6vP4FBBYb/iw==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/control-box@2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-FEyrU4crxati80KUF/+1Z1CU3eZK6Sa0Yv7Z/ydtz9/tvGblXW9NFanoomXAOvcIFLbaLQPPATm9Gmpr7VG05A==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/counter@2.0.14(react@18.2.0): - resolution: {integrity: sha512-KxcSRfUbb94dP77xTip2myoE7P2HQQN4V5fRJmNAGbzcyLciJ+aDylUU/UxgNcEjawUp6Q242NbWb1TSbKoqog==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/number-utils': 2.0.7 - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - react: 18.2.0 - dev: false - - /@chakra-ui/css-reset@2.0.12(@emotion/react@11.10.5)(react@18.2.0): - resolution: {integrity: sha512-Q5OYIMvqTl2vZ947kIYxcS5DhQXeStB84BzzBd6C10wOx1gFUu9pL+jLpOnHR3hhpWRMdX5o7eT+gMJWIYUZ0Q==} - peerDependencies: - '@emotion/react': '>=10.0.35' - react: '>=18' - dependencies: - '@emotion/react': 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/descendant@3.0.13(react@18.2.0): - resolution: {integrity: sha512-9nzxZVxUSMc4xPL5fSaRkEOQjDQWUGjGvrZI7VzWk9eq63cojOtIxtWMSW383G9148PzWJjJYt30Eud5tdZzlg==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/dom-utils@2.0.6: - resolution: {integrity: sha512-PVtDkPrDD5b8aoL6Atg7SLjkwhWb7BwMcLOF1L449L3nZN+DAO3nyAh6iUhZVJyunELj9d0r65CDlnMREyJZmA==} - dev: false - - /@chakra-ui/editable@2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-YxRJsJ2JQd42zfPBgTKzIhg1HugT+gfQz1ZosmUN+IZT9YZXL2yodHTUz6Lee04Vc/CdEqgBFLuREXEUNBfGtA==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-focus-on-pointer-down': 2.0.6(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/event-utils@2.0.8: - resolution: {integrity: sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw==} - dev: false - - /@chakra-ui/focus-lock@2.0.16(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-UuAdGCPVrCa1lecoAvpOQD7JFT7a9RdmhKWhFt5ioIcekSLJcerdLHuuL3w0qz//8kd1/SOt7oP0aJqdAJQrCw==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/dom-utils': 2.0.6 - react: 18.2.0 - react-focus-lock: 2.9.3(@types/react@18.0.27)(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - dev: false - - /@chakra-ui/form-control@2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-34ptCaJ2LNvQNOlB6MAKsmH1AkT1xo7E+3Vw10Urr81yTOjDTM/iU6vG3JKPfRDMyXeowPjXmutlnuk72SSjRg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/hooks@2.1.5(react@18.2.0): - resolution: {integrity: sha512-E3bGwxjXvMUc9ev3egctrRi5fnER5xXbWUsivA3iFRdUrkfX+19JLUfP1TURzv7UQG8X1AxKSwfqIsYyeHrdmQ==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-utils': 2.0.12(react@18.2.0) - '@chakra-ui/utils': 2.0.15 - compute-scroll-into-view: 1.0.14 - copy-to-clipboard: 3.3.1 - react: 18.2.0 - dev: false - - /@chakra-ui/icon@3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-RpA1X5Ptz8Mt39HSyEIW1wxAz2AXyf9H0JJ5HVx/dBdMZaGMDJ0HyyPBVci0m4RCoJuyG1HHG/DXJaVfUTVAeg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/image@2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-w2rElXtI3FHXuGpMCsSklus+pO1Pl2LWDwsCGdpBQUvGFbnHfl7MftQgTlaGHeD5OS95Pxva39hKrA2VklKHiQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/input@2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-wV+EG6+F9GngMPpLHBCuxXTNttHihFTT3DpbJnmID9LuAPg7YkWcTNTvpAzC0/Sz9KrcTR9RhSu9a5cvxkkXpw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/object-utils': 2.0.8 - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/layout@2.1.15(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-dJYzBm2ywRYNmtadot/5ii+Gztsx8a9Jd+gFXiSLcfQs/QRdboqMyr/0O+6RY2sI7Mwvyo6uo9AvGJBU1djrNQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/breakpoint-utils': 2.0.7 - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/object-utils': 2.0.8 - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/lazy-utils@2.0.5: - resolution: {integrity: sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg==} - dev: false - - /@chakra-ui/live-region@2.0.13(react@18.2.0): - resolution: {integrity: sha512-Ja+Slk6ZkxSA5oJzU2VuGU7TpZpbMb/4P4OUhIf2D30ctmIeXkxTWw1Bs1nGJAVtAPcGS5sKA+zb89i8g+0cTQ==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/media-query@3.2.11(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-AylT/qIpbCOvcjvURMdItLvAnaEYZynatvVJUQ8TYcQO2KHBt8BBhQ9umrmNAZFr8y7CRcg7PdvK+g+yOkq22g==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/breakpoint-utils': 2.0.7 - '@chakra-ui/react-env': 3.0.0(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/menu@2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0): - resolution: {integrity: sha512-3Ysk1HwJTv6mzkT1dgsNObZnuZiySPJwLdmmCdv8+rpto8u0oCN+etenN0s7HQlAddvHxZ2Sm+1yKZOu6Wimrg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/clickable': 2.0.14(react@18.2.0) - '@chakra-ui/descendant': 3.0.13(react@18.2.0) - '@chakra-ui/lazy-utils': 2.0.5 - '@chakra-ui/popper': 3.0.13(react@18.2.0) - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-animation-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-disclosure': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-focus-effect': 2.0.9(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-outside-click': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/transition': 2.0.15(framer-motion@9.0.2)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/modal@2.2.9(@chakra-ui/system@2.4.0)(@types/react@18.0.27)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-nTfNp7XsVwn5+xJOtstoFA8j0kq/9sJj7KesyYzjEDaMKvCZvIOntRYowoydho43jb4+YC7ebKhp0KOIINS0gg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/close-button': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/focus-lock': 2.0.16(@types/react@18.0.27)(react@18.2.0) - '@chakra-ui/portal': 2.0.15(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/transition': 2.0.15(framer-motion@9.0.2)(react@18.2.0) - aria-hidden: 1.2.2(@types/react@18.0.27)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.0.27)(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - dev: false - - /@chakra-ui/number-input@2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-cPkyAFFHHzeFBselrT1BtjlzMkJ6TKrTDUnHFlzqXy6aqeXuhrjFhMfXucjedSpOqedsP9ZbKFTdIAhu9DdL/A==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/counter': 2.0.14(react@18.2.0) - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-event-listener': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-interval': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/number-utils@2.0.7: - resolution: {integrity: sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg==} - dev: false - - /@chakra-ui/object-utils@2.0.8: - resolution: {integrity: sha512-2upjT2JgRuiupdrtBWklKBS6tqeGMA77Nh6Q0JaoQuH/8yq+15CGckqn3IUWkWoGI0Fg3bK9LDlbbD+9DLw95Q==} - dev: false - - /@chakra-ui/pin-input@2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-6O7s4vWz4cqQ6zvMov9sYj6ZqWAsTxR/MNGe3DNgu1zWQg8veNCYtj1rNGhNS3eZNUMAa8uM2dXIphGTP53Xow==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/descendant': 3.0.13(react@18.2.0) - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/popover@2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0): - resolution: {integrity: sha512-ob7fAz+WWmXIq7iGHVB3wDKzZTj+T+noYBT/U1Q+jIf+jMr2WOpJLTfb0HTZcfhvn4EBFlfBg7Wk5qbXNaOn7g==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/close-button': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/lazy-utils': 2.0.5 - '@chakra-ui/popper': 3.0.13(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-animation-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-disclosure': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-focus-effect': 2.0.9(react@18.2.0) - '@chakra-ui/react-use-focus-on-pointer-down': 2.0.6(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/popper@3.0.13(react@18.2.0): - resolution: {integrity: sha512-FwtmYz80Ju8oK3Z1HQfisUE7JIMmDsCQsRBu6XuJ3TFQnBHit73yjZmxKjuRJ4JgyT4WBnZoTF3ATbRKSagBeg==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@popperjs/core': 2.11.6 - react: 18.2.0 - dev: false - - /@chakra-ui/portal@2.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-z8v7K3j1/nMuBzp2+wRIIw7s/eipVtnXLdjK5yqbMxMRa44E8Mu5VNJLz3aQFLHXEUST+ifqrjImQeli9do6LQ==} - peerDependencies: - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/progress@2.1.5(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-jj5Vp4lxUchuwp4RPCepM0yAyKi344bgsOd3Apd+ldxclDcewPc82fbwDu7g/Xv27LqJkT+7E/SlQy04wGrk0g==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/provider@2.1.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-+NUBHOkqWFpi/unwqhUQh1t/S1+TMZBTz+FiTeWycSUicdFsGCcTe6eQNLu6X5C8gYx9FGXG4ESx7HCTNXQj7w==} - peerDependencies: - '@emotion/react': ^11.0.0 - '@emotion/styled': ^11.0.0 - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/css-reset': 2.0.12(@emotion/react@11.10.5)(react@18.2.0) - '@chakra-ui/portal': 2.0.15(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-env': 3.0.0(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/utils': 2.0.15 - '@emotion/react': 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - '@emotion/styled': 11.10.5(@babel/core@7.20.12)(@emotion/react@11.10.5)(@types/react@18.0.27)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/radio@2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-PlJiV59eGSmeKP4v/4+ccQUWGRd0cjPKkj/p3L+UbOf8pl9dWm8y9kIeL5TYbghQSDv0nzkrH4+yMnnDTZjdMQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@zag-js/focus-visible': 0.2.1 - react: 18.2.0 - dev: false - - /@chakra-ui/react-children-utils@2.0.6(react@18.2.0): - resolution: {integrity: sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-context@2.0.7(react@18.2.0): - resolution: {integrity: sha512-i7EGmSU+h2GB30cwrKB4t1R5BMHyGoJM5L2Zz7b+ZUX4aAqyPcfe97wPiQB6Rgr1ImGXrUeov4CDVrRZ2FPgLQ==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-env@3.0.0(react@18.2.0): - resolution: {integrity: sha512-tfMRO2v508HQWAqSADFrwZgR9oU10qC97oV6zGbjHh9ALP0/IcFR+Bi71KRTveDTm85fMeAzZYGj57P3Dsipkw==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-types@2.0.7(react@18.2.0): - resolution: {integrity: sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-animation-state@2.0.8(react@18.2.0): - resolution: {integrity: sha512-xv9zSF2Rd1mHWQ+m5DLBWeh4atF8qrNvsOs3MNrvxKYBS3f79N3pqcQGrWAEvirXWXfiCeje2VAkEggqFRIo+Q==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/dom-utils': 2.0.6 - '@chakra-ui/react-use-event-listener': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-callback-ref@2.0.7(react@18.2.0): - resolution: {integrity: sha512-YjT76nTpfHAK5NxplAlZsQwNju5KmQExnqsWNPFeOR6vvbC34+iPSTr+r91i1Hdy7gBSbevsOsd5Wm6RN3GuMw==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-controllable-state@2.0.8(react@18.2.0): - resolution: {integrity: sha512-F7rdCbLEmRjwwODqWZ3y+mKgSSHPcLQxeUygwk1BkZPXbKkJJKymOIjIynil2cbH7ku3hcSIWRvuhpCcfQWJ7Q==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-disclosure@2.0.8(react@18.2.0): - resolution: {integrity: sha512-2ir/mHe1YND40e+FyLHnDsnDsBQPwzKDLzfe9GZri7y31oU83JSbHdlAXAhp3bpjohslwavtRCp+S/zRxfO9aQ==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-event-listener@2.0.7(react@18.2.0): - resolution: {integrity: sha512-4wvpx4yudIO3B31pOrXuTHDErawmwiXnvAN7gLEOVREi16+YGNcFnRJ5X5nRrmB7j2MDUtsEDpRBFfw5Z9xQ5g==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-focus-effect@2.0.9(react@18.2.0): - resolution: {integrity: sha512-20nfNkpbVwyb41q9wxp8c4jmVp6TUGAPE3uFTDpiGcIOyPW5aecQtPmTXPMJH+2aa8Nu1wyoT1btxO+UYiQM3g==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/dom-utils': 2.0.6 - '@chakra-ui/react-use-event-listener': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-focus-on-pointer-down@2.0.6(react@18.2.0): - resolution: {integrity: sha512-OigXiLRVySn3tyVqJ/rn57WGuukW8TQe8fJYiLwXbcNyAMuYYounvRxvCy2b53sQ7QIZamza0N0jhirbH5FNoQ==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-event-listener': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-interval@2.0.5(react@18.2.0): - resolution: {integrity: sha512-1nbdwMi2K87V6p5f5AseOKif2CkldLaJlq1TOqaPRwb7v3aU9rltBtYdf+fIyuHSToNJUV6wd9budCFdLCl3Fg==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-latest-ref@2.0.5(react@18.2.0): - resolution: {integrity: sha512-3mIuFzMyIo3Ok/D8uhV9voVg7KkrYVO/pwVvNPJOHsDQqCA6DpYE4WDsrIx+fVcwad3Ta7SupexR5PoI+kq6QQ==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-merge-refs@2.0.7(react@18.2.0): - resolution: {integrity: sha512-zds4Uhsc+AMzdH8JDDkLVet9baUBgtOjPbhC5r3A0ZXjZvGhCztFAVE3aExYiVoMPoHLKbLcqvCWE6ioFKz1lw==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-outside-click@2.0.7(react@18.2.0): - resolution: {integrity: sha512-MsAuGLkwYNxNJ5rb8lYNvXApXxYMnJ3MzqBpQj1kh5qP/+JSla9XMjE/P94ub4fSEttmNSqs43SmPPrmPuihsQ==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-pan-event@2.0.9(react@18.2.0): - resolution: {integrity: sha512-xu35QXkiyrgsHUOnctl+SwNcwf9Rl62uYE5y8soKOZdBm8E+FvZIt2hxUzK1EoekbJCMzEZ0Yv1ZQCssVkSLaQ==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/event-utils': 2.0.8 - '@chakra-ui/react-use-latest-ref': 2.0.5(react@18.2.0) - framesync: 6.1.2 - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-previous@2.0.5(react@18.2.0): - resolution: {integrity: sha512-BIZgjycPE4Xr+MkhKe0h67uHXzQQkBX/u5rYPd65iMGdX1bCkbE0oorZNfOHLKdTmnEb4oVsNvfN6Rfr+Mnbxw==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-safe-layout-effect@2.0.5(react@18.2.0): - resolution: {integrity: sha512-MwAQBz3VxoeFLaesaSEN87reVNVbjcQBDex2WGexAg6hUB6n4gc1OWYH/iXp4tzp4kuggBNhEHkk9BMYXWfhJQ==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-size@2.0.8(react@18.2.0): - resolution: {integrity: sha512-OdCxVPm8ekPVn9R6S1OtfLVNRVZ0G1tcfA2/oY1c55aXbm/R0TFZ+twSoy+X+aRFhqydmE7DRsKyW2ysXuuVBw==} - peerDependencies: - react: '>=18' - dependencies: - '@zag-js/element-size': 0.3.0 - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-timeout@2.0.5(react@18.2.0): - resolution: {integrity: sha512-QqmB+jVphh3h/CS60PieorpY7UqSPkrQCB7f7F+i9vwwIjtP8fxVHMmkb64K7VlzQiMPzv12nlID5dqkzlv0mw==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/react-use-update-effect@2.0.7(react@18.2.0): - resolution: {integrity: sha512-vBM2bmmM83ZdDtasWv3PXPznpTUd+FvqBC8J8rxoRmvdMEfrxTiQRBJhiGHLpS9BPLLPQlosN6KdFU97csB6zg==} - peerDependencies: - react: '>=18' - dependencies: - react: 18.2.0 - dev: false - - /@chakra-ui/react-utils@2.0.12(react@18.2.0): - resolution: {integrity: sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==} - peerDependencies: - react: '>=18' - dependencies: - '@chakra-ui/utils': 2.0.15 - react: 18.2.0 - dev: false - - /@chakra-ui/react@2.4.9(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(@types/react@18.0.27)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-lY++xW+zhLp0zQr2Sf5phjYMIphOmjGV/o5A1oDQPrqwLJFm4mL2+eXvpAFrLnZoh00qa4iBqarxJCW7qpHeiA==} - peerDependencies: - '@emotion/react': ^11.0.0 - '@emotion/styled': ^11.0.0 - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/accordion': 2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0) - '@chakra-ui/alert': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/avatar': 2.2.4(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/breadcrumb': 2.1.4(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/button': 2.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/card': 2.1.6(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/checkbox': 2.2.10(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/close-button': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/control-box': 2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/counter': 2.0.14(react@18.2.0) - '@chakra-ui/css-reset': 2.0.12(@emotion/react@11.10.5)(react@18.2.0) - '@chakra-ui/editable': 2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/hooks': 2.1.5(react@18.2.0) - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/image': 2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/input': 2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/layout': 2.1.15(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/live-region': 2.0.13(react@18.2.0) - '@chakra-ui/media-query': 3.2.11(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/menu': 2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0) - '@chakra-ui/modal': 2.2.9(@chakra-ui/system@2.4.0)(@types/react@18.0.27)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/number-input': 2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/pin-input': 2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/popover': 2.1.8(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0) - '@chakra-ui/popper': 3.0.13(react@18.2.0) - '@chakra-ui/portal': 2.0.15(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/progress': 2.1.5(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/provider': 2.1.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/radio': 2.0.19(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-env': 3.0.0(react@18.2.0) - '@chakra-ui/select': 2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/skeleton': 2.0.23(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/slider': 2.0.20(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/spinner': 2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/stat': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/styled-system': 2.5.2 - '@chakra-ui/switch': 2.0.22(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/table': 2.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/tabs': 2.1.8(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/tag': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/textarea': 2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/theme': 2.2.5(@chakra-ui/styled-system@2.5.2) - '@chakra-ui/theme-utils': 2.0.9 - '@chakra-ui/toast': 5.0.1(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/tooltip': 2.2.6(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/transition': 2.0.15(framer-motion@9.0.2)(react@18.2.0) - '@chakra-ui/utils': 2.0.15 - '@chakra-ui/visually-hidden': 2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0) - '@emotion/react': 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - '@emotion/styled': 11.10.5(@babel/core@7.20.12)(@emotion/react@11.10.5)(@types/react@18.0.27)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - dev: false - - /@chakra-ui/select@2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-1d2lUT5LM6oOs5x4lzBh4GFDuXX62+lr+sgV7099g951/5UNbb0CS2hSZHsO7yZThLNbr7QTWZvAOAayVcGzdw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/shared-utils@2.0.4: - resolution: {integrity: sha512-JGWr+BBj3PXGZQ2gxbKSD1wYjESbYsZjkCeE2nevyVk4rN3amV1wQzCnBAhsuJktMaZD6KC/lteo9ou9QUDzpA==} - dev: false - - /@chakra-ui/shared-utils@2.0.5: - resolution: {integrity: sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q==} - dev: false - - /@chakra-ui/skeleton@2.0.23(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-iMK50PlC9kR52v8tZWSKnZTJsOpZrqXOXaR9r/0Ry3xhdMq5hGkcigA+zKy/ZEglbMZ2CG9Fdtvi2vQurE1VZw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/media-query': 3.2.11(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-use-previous': 2.0.5(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/slider@2.0.20(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-5Q+9s6bIjI8GIp7YRHqt5hT678p7lCIdA/zB6c/fCp+MvOInxx4LiJZvNuaw0HX6z6bC7R/skIhmIjsgSI3MNw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/number-utils': 2.0.7 - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-callback-ref': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-latest-ref': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-pan-event': 2.0.9(react@18.2.0) - '@chakra-ui/react-use-size': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/spinner@2.0.13(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-T1/aSkVpUIuiYyrjfn1+LsQEG7Onbi1UE9ccS/evgf61Dzy4GgTXQUnDuWFSgpV58owqirqOu6jn/9eCwDlzlg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/stat@2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-PhD+5oVLWjQmGLfeZSmexp3AtLcaggWBwoMZ4z8QMZIQzf/fJJWMk0bMqxlpTv8ORDkfY/4ImuFB/RJHvcqlcA==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/styled-system@2.5.1: - resolution: {integrity: sha512-HhaXR/r5eGlC7vkoOWQ31yZEj+Aq+kFee7ZZb0fBRGKQichn06S9Ugr8CsFyzb+jNexHdtBlIcTBm0ufJ8HsFA==} - dependencies: - '@chakra-ui/shared-utils': 2.0.4 - csstype: 3.1.1 - lodash.mergewith: 4.6.2 - dev: false - - /@chakra-ui/styled-system@2.5.2: - resolution: {integrity: sha512-FVnSWcj28F2t0R6slslYnhdWL8L3+elzoNt9oXBosS9PS6u6Yh56Dqq2GH2yasOWSmuuXGCPbzOYuc0U+MlCqg==} - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - csstype: 3.1.1 - lodash.mergewith: 4.6.2 - dev: false - - /@chakra-ui/switch@2.0.22(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react@18.2.0): - resolution: {integrity: sha512-+/Yy6y7VFD91uSPruF8ZvePi3tl5D8UNVATtWEQ+QBI92DLSM+PtgJ2F0Y9GMZ9NzMxpZ80DqwY7/kqcPCfLvw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/checkbox': 2.2.10(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/system@2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0): - resolution: {integrity: sha512-gUX6OZVvFDMV92NtKLuawIWqvjhYc0u1LCAMeb1k3ktVBjWEYjIM4DBIirEhHjcADa8ownrTEHeW0aGxN7uxjQ==} - peerDependencies: - '@emotion/react': ^11.0.0 - '@emotion/styled': ^11.0.0 - react: '>=18' - dependencies: - '@chakra-ui/color-mode': 2.1.12(react@18.2.0) - '@chakra-ui/object-utils': 2.0.8 - '@chakra-ui/react-utils': 2.0.12(react@18.2.0) - '@chakra-ui/styled-system': 2.5.2 - '@chakra-ui/theme-utils': 2.0.9 - '@chakra-ui/utils': 2.0.15 - '@emotion/react': 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - '@emotion/styled': 11.10.5(@babel/core@7.20.12)(@emotion/react@11.10.5)(@types/react@18.0.27)(react@18.2.0) - react: 18.2.0 - react-fast-compare: 3.2.0 - dev: false - - /@chakra-ui/table@2.0.16(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-vWDXZ6Ad3Aj66curp1tZBHvCfQHX2FJ4ijLiqGgQszWFIchfhJ5vMgEBJaFMZ+BN1draAjuRTZqaQefOApzvRg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/tabs@2.1.8(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-B7LeFN04Ny2jsSy5TFOQxnbZ6ITxGxLxsB2PE0vvQjMSblBrUryOxdjw80HZhfiw6od0ikK9CeKQOIt9QCguSw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/clickable': 2.0.14(react@18.2.0) - '@chakra-ui/descendant': 3.0.13(react@18.2.0) - '@chakra-ui/lazy-utils': 2.0.5 - '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-controllable-state': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-safe-layout-effect': 2.0.5(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/tag@2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-A47zE9Ft9qxOJ+5r1cUseKRCoEdqCRzFm0pOtZgRcckqavglk75Xjgz8HbBpUO2zqqd49MlqdOwR8o87fXS1vg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.16(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/textarea@2.0.18(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-aGHHb29vVifO0OtcK/k8cMykzjOKo/coDTU0NJqz7OOLAWIMNV2eGenvmO1n9tTZbmbqHiX+Sa1nPRX+pd14lg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/theme-tools@2.0.17(@chakra-ui/styled-system@2.5.2): - resolution: {integrity: sha512-Auu38hnihlJZQcPok6itRDBbwof3TpXGYtDPnOvrq4Xp7jnab36HLt7KEXSDPXbtOk3ZqU99pvI1en5LbDrdjg==} - peerDependencies: - '@chakra-ui/styled-system': '>=2.0.0' - dependencies: - '@chakra-ui/anatomy': 2.1.2 - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/styled-system': 2.5.2 - color2k: 2.0.2 - dev: false - - /@chakra-ui/theme-utils@2.0.9: - resolution: {integrity: sha512-+Nn1NooFeAr4d/OVU1NjXEMKCKCIfesYw27BoYzFYCWt/+cS/qcVdPJj+uXgK8L8xExhkREipt2r9kGlE+WpTw==} - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/styled-system': 2.5.2 - '@chakra-ui/theme': 2.2.5(@chakra-ui/styled-system@2.5.2) - lodash.mergewith: 4.6.2 - dev: false - - /@chakra-ui/theme@2.2.5(@chakra-ui/styled-system@2.5.2): - resolution: {integrity: sha512-hYASZMwu0NqEv6PPydu+F3I+kMNd44yR4TwjR/lXBz/LEh64L6UPY6kQjebCfgdVtsGdl3HKg+eLlfa7SvfRgw==} - peerDependencies: - '@chakra-ui/styled-system': '>=2.0.0' - dependencies: - '@chakra-ui/anatomy': 2.1.2 - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/styled-system': 2.5.2 - '@chakra-ui/theme-tools': 2.0.17(@chakra-ui/styled-system@2.5.2) - dev: false - - /@chakra-ui/toast@5.0.1(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-R66broJXhe4cd+o5/r7raF4Jg4J3W3QBHrykV7AV/W0Wiav8tL8jwSq8pMmXVnO3oGwKWZ+VHuSWmjcL65BHmg==} - peerDependencies: - '@chakra-ui/system': 2.4.0 - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/alert': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/close-button': 2.0.17(@chakra-ui/system@2.4.0)(react@18.2.0) - '@chakra-ui/portal': 2.0.15(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-context': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-timeout': 2.0.5(react@18.2.0) - '@chakra-ui/react-use-update-effect': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/styled-system': 2.5.2 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - '@chakra-ui/theme': 2.2.5(@chakra-ui/styled-system@2.5.2) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/tooltip@2.2.6(@chakra-ui/system@2.4.0)(framer-motion@9.0.2)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-4cbneidZ5+HCWge3OZzewRQieIvhDjSsl+scrl4Scx7E0z3OmqlTIESU5nGIZDBLYqKn/UirEZhqaQ33FOS2fw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/popper': 3.0.13(react@18.2.0) - '@chakra-ui/portal': 2.0.15(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-types': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-disclosure': 2.0.8(react@18.2.0) - '@chakra-ui/react-use-event-listener': 2.0.7(react@18.2.0) - '@chakra-ui/react-use-merge-refs': 2.0.7(react@18.2.0) - '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/transition@2.0.15(framer-motion@9.0.2)(react@18.2.0): - resolution: {integrity: sha512-o9LBK/llQfUDHF/Ty3cQ6nShpekKTqHUoJlUOzNKhoTsNpoRerr9v0jwojrX1YI02KtVjfhFU6PiqXlDfREoNw==} - peerDependencies: - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/shared-utils': 2.0.5 - framer-motion: 9.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/utils@2.0.15: - resolution: {integrity: sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==} - dependencies: - '@types/lodash.mergewith': 4.6.7 - css-box-model: 1.2.1 - framesync: 6.1.2 - lodash.mergewith: 4.6.2 - dev: false - - /@chakra-ui/visually-hidden@2.0.15(@chakra-ui/system@2.4.0)(react@18.2.0): - resolution: {integrity: sha512-WWULIiucYRBIewHKFA7BssQ2ABLHLVd9lrUo3N3SZgR0u4ZRDDVEUNOy+r+9ruDze8+36dGbN9wsN1IdELtdOw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0' - react: '>=18' - dependencies: - '@chakra-ui/system': 2.4.0(@emotion/react@11.10.5)(@emotion/styled@11.10.5)(react@18.2.0) - react: 18.2.0 - dev: false - - /@emotion/babel-plugin@11.10.5(@babel/core@7.20.12): - resolution: {integrity: sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.20.12) - '@babel/runtime': 7.20.13 - '@emotion/hash': 0.9.0 - '@emotion/memoize': 0.8.0 - '@emotion/serialize': 1.1.1 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.1.3 - dev: false - - /@emotion/cache@11.10.5: - resolution: {integrity: sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==} - dependencies: - '@emotion/memoize': 0.8.0 - '@emotion/sheet': 1.2.1 - '@emotion/utils': 1.2.0 - '@emotion/weak-memoize': 0.3.0 - stylis: 4.1.3 - dev: false - - /@emotion/hash@0.9.0: - resolution: {integrity: sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==} - dev: false - - /@emotion/is-prop-valid@0.8.8: - resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} - requiresBuild: true - dependencies: - '@emotion/memoize': 0.7.4 - dev: false - optional: true - - /@emotion/is-prop-valid@1.2.0: - resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==} - dependencies: - '@emotion/memoize': 0.8.0 - dev: false - - /@emotion/memoize@0.7.4: - resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} - dev: false - optional: true - - /@emotion/memoize@0.8.0: - resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==} - dev: false - - /@emotion/react@11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==} - peerDependencies: - '@babel/core': ^7.0.0 - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@babel/core': - optional: true - '@types/react': - optional: true - dependencies: - '@babel/core': 7.20.12 - '@babel/runtime': 7.20.13 - '@emotion/babel-plugin': 11.10.5(@babel/core@7.20.12) - '@emotion/cache': 11.10.5 - '@emotion/serialize': 1.1.1 - '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@emotion/utils': 1.2.0 - '@emotion/weak-memoize': 0.3.0 - '@types/react': 18.0.27 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - dev: false - - /@emotion/serialize@1.1.1: - resolution: {integrity: sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==} - dependencies: - '@emotion/hash': 0.9.0 - '@emotion/memoize': 0.8.0 - '@emotion/unitless': 0.8.0 - '@emotion/utils': 1.2.0 - csstype: 3.1.1 - dev: false - - /@emotion/sheet@1.2.1: - resolution: {integrity: sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==} - dev: false - - /@emotion/styled@11.10.5(@babel/core@7.20.12)(@emotion/react@11.10.5)(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==} - peerDependencies: - '@babel/core': ^7.0.0 - '@emotion/react': ^11.0.0-rc.0 - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@babel/core': - optional: true - '@types/react': - optional: true - dependencies: - '@babel/core': 7.20.12 - '@babel/runtime': 7.20.13 - '@emotion/babel-plugin': 11.10.5(@babel/core@7.20.12) - '@emotion/is-prop-valid': 1.2.0 - '@emotion/react': 11.10.5(@babel/core@7.20.12)(@types/react@18.0.27)(react@18.2.0) - '@emotion/serialize': 1.1.1 - '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@emotion/utils': 1.2.0 - '@types/react': 18.0.27 - react: 18.2.0 - dev: false - - /@emotion/unitless@0.8.0: - resolution: {integrity: sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==} - dev: false - - /@emotion/use-insertion-effect-with-fallbacks@1.0.0(react@18.2.0): - resolution: {integrity: sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==} - peerDependencies: - react: '>=16.8.0' - dependencies: - react: 18.2.0 - dev: false - - /@emotion/utils@1.2.0: - resolution: {integrity: sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==} - dev: false - - /@emotion/weak-memoize@0.3.0: - resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==} - dev: false - - /@esbuild/android-arm64@0.16.17: - resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.16.17: - resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.16.17: - resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.16.17: - resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.16.17: - resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.16.17: - resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.16.17: - resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.16.17: - resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.16.17: - resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.16.17: - resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.16.17: - resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.16.17: - resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.16.17: - resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.16.17: - resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.16.17: - resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.16.17: - resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.16.17: - resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.16.17: - resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.16.17: - resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.16.17: - resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.16.17: - resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.16.17: - resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@jridgewell/gen-mapping@0.1.1: - resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - - /@jridgewell/gen-mapping@0.3.2: - resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.17 - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - - /@jridgewell/trace-mapping@0.3.17: - resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - - /@motionone/animation@10.15.1: - resolution: {integrity: sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==} - dependencies: - '@motionone/easing': 10.15.1 - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - tslib: 2.5.0 - dev: false - - /@motionone/dom@10.15.5: - resolution: {integrity: sha512-Xc5avlgyh3xukU9tydh9+8mB8+2zAq+WlLsC3eEIp7Ax7DnXgY7Bj/iv0a4X2R9z9ZFZiaXK3BO0xMYHKbAAdA==} - dependencies: - '@motionone/animation': 10.15.1 - '@motionone/generators': 10.15.1 - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - hey-listen: 1.0.8 - tslib: 2.5.0 - dev: false - - /@motionone/easing@10.15.1: - resolution: {integrity: sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==} - dependencies: - '@motionone/utils': 10.15.1 - tslib: 2.5.0 - dev: false - - /@motionone/generators@10.15.1: - resolution: {integrity: sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==} - dependencies: - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - tslib: 2.5.0 - dev: false - - /@motionone/types@10.15.1: - resolution: {integrity: sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA==} - dev: false - - /@motionone/utils@10.15.1: - resolution: {integrity: sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==} - dependencies: - '@motionone/types': 10.15.1 - hey-listen: 1.0.8 - tslib: 2.5.0 - dev: false - - /@popperjs/core@2.11.6: - resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} - dev: false - - /@types/lodash.mergewith@4.6.7: - resolution: {integrity: sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==} - dependencies: - '@types/lodash': 4.14.191 - dev: false - - /@types/lodash@4.14.191: - resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==} - dev: false - - /@types/node@18.13.0: - resolution: {integrity: sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==} - dev: true - - /@types/parse-json@4.0.0: - resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} - dev: false - - /@types/prop-types@15.7.5: - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - - /@types/react-dom@18.0.10: - resolution: {integrity: sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==} - dependencies: - '@types/react': 18.0.27 - dev: true - - /@types/react@18.0.27: - resolution: {integrity: sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.2 - csstype: 3.1.1 - - /@types/scheduler@0.16.2: - resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - - /@vitejs/plugin-react@3.1.0(vite@4.1.1): - resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.1.0-beta.0 - dependencies: - '@babel/core': 7.20.12 - '@babel/plugin-transform-react-jsx-self': 7.18.6(@babel/core@7.20.12) - '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.20.12) - magic-string: 0.27.0 - react-refresh: 0.14.0 - vite: 4.1.1(@types/node@18.13.0) - transitivePeerDependencies: - - supports-color - dev: true - - /@zag-js/element-size@0.3.0: - resolution: {integrity: sha512-5/hEI+0c6ZNCx6KHlOS5/WeHsd6+I7gk7Y/b/zATp4Rp3tHirs/tu1frq+iy5BmfaG9hbQtfHfUJTjOcI5jnoQ==} - dev: false - - /@zag-js/focus-visible@0.2.1: - resolution: {integrity: sha512-19uTjoZGP4/Ax7kSNhhay9JA83BirKzpqLkeEAilrpdI1hE5xuq6q+tzJOsrMOOqJrm7LkmZp5lbsTQzvK2pYg==} - dev: false - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - - /aria-hidden@1.2.2(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 - react: ^16.9.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - react: 18.2.0 - tslib: 2.5.0 - dev: false - - /babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} - dependencies: - '@babel/runtime': 7.20.13 - cosmiconfig: 7.1.0 - resolve: 1.22.1 - dev: false - - /browserslist@4.21.5: - resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001450 - electron-to-chromium: 1.4.288 - node-releases: 2.0.10 - update-browserslist-db: 1.0.10(browserslist@4.21.5) - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: false - - /caniuse-lite@1.0.30001450: - resolution: {integrity: sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==} - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - /color2k@2.0.2: - resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} - dev: false - - /compute-scroll-into-view@1.0.14: - resolution: {integrity: sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==} - dev: false - - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - - /copy-to-clipboard@3.3.1: - resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==} - dependencies: - toggle-selection: 1.0.6 - dev: false - - /cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - dependencies: - '@types/parse-json': 4.0.0 - import-fresh: 3.3.0 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.2 - dev: false - - /css-box-model@1.2.1: - resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==} - dependencies: - tiny-invariant: 1.3.1 - dev: false - - /csstype@3.1.1: - resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - - /detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dev: false - - /electron-to-chromium@1.4.288: - resolution: {integrity: sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==} - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: false - - /esbuild@0.16.17: - resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.16.17 - '@esbuild/android-arm64': 0.16.17 - '@esbuild/android-x64': 0.16.17 - '@esbuild/darwin-arm64': 0.16.17 - '@esbuild/darwin-x64': 0.16.17 - '@esbuild/freebsd-arm64': 0.16.17 - '@esbuild/freebsd-x64': 0.16.17 - '@esbuild/linux-arm': 0.16.17 - '@esbuild/linux-arm64': 0.16.17 - '@esbuild/linux-ia32': 0.16.17 - '@esbuild/linux-loong64': 0.16.17 - '@esbuild/linux-mips64el': 0.16.17 - '@esbuild/linux-ppc64': 0.16.17 - '@esbuild/linux-riscv64': 0.16.17 - '@esbuild/linux-s390x': 0.16.17 - '@esbuild/linux-x64': 0.16.17 - '@esbuild/netbsd-x64': 0.16.17 - '@esbuild/openbsd-x64': 0.16.17 - '@esbuild/sunos-x64': 0.16.17 - '@esbuild/win32-arm64': 0.16.17 - '@esbuild/win32-ia32': 0.16.17 - '@esbuild/win32-x64': 0.16.17 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: false - - /find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - dev: false - - /focus-lock@0.11.5: - resolution: {integrity: sha512-1mTr6pl9HBpJ8CqY7hRc38MCrcuTZIeYAkBD1gBTzbx5/to+bRBaBYtJ68iDq7ryTzAAbKrG3dVKjkrWTaaEaw==} - engines: {node: '>=10'} - dependencies: - tslib: 2.5.0 - dev: false - - /framer-motion@9.0.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-n7ZdIUBrT1xklowQNRQ6/h54+3ysmz422CP0rrhjE1X2tshiJy0WWQ7tv6y/fcOSQd23htNA9vvbUFLYMQ5lEQ==} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - dependencies: - '@motionone/dom': 10.15.5 - hey-listen: 1.0.8 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.5.0 - optionalDependencies: - '@emotion/is-prop-valid': 0.8.8 - dev: false - - /framesync@6.1.2: - resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} - dependencies: - tslib: 2.4.0 - dev: false - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - /get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - dev: false - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - - /hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - dev: false - - /hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - dependencies: - react-is: 16.13.1 - dev: false - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: false - - /invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: false - - /is-core-module@2.11.0: - resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} - dependencies: - has: 1.0.3 - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: false - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: false - - /lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - dev: false - - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - dependencies: - js-tokens: 4.0.0 - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - /nanoid@3.3.4: - resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /node-releases@2.0.10: - resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} - - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: false - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: false - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.18.6 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: false - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: false - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - - /postcss@8.4.21: - resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.4 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: true - - /prettier@2.8.3: - resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true - - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - dev: false - - /react-clientside-effect@1.2.6(react@18.2.0): - resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} - peerDependencies: - react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@babel/runtime': 7.20.13 - react: 18.2.0 - dev: false - - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - dev: false - - /react-fast-compare@3.2.0: - resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==} - dev: false - - /react-focus-lock@2.9.3(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-cGNkz9p5Fpqio6hBHlkKxzRYrBYtcPosFOL6Q3N/LSbHjwP/PTBqHpvbgaOYoE7rWfzw8qXPKTB3Tk/VPgw4NQ==} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.20.13 - '@types/react': 18.0.27 - focus-lock: 0.11.5 - prop-types: 15.8.1 - react: 18.2.0 - react-clientside-effect: 1.2.6(react@18.2.0) - use-callback-ref: 1.3.0(@types/react@18.0.27)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.0.27)(react@18.2.0) - dev: false - - /react-icons@4.7.1(react@18.2.0): - resolution: {integrity: sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==} - peerDependencies: - react: '*' - dependencies: - react: 18.2.0 - dev: false - - /react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: false - - /react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} - engines: {node: '>=0.10.0'} - dev: true - - /react-remove-scroll-bar@2.3.4(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - react: 18.2.0 - react-style-singleton: 2.2.1(@types/react@18.0.27)(react@18.2.0) - tslib: 2.5.0 - dev: false - - /react-remove-scroll@2.5.5(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - react: 18.2.0 - react-remove-scroll-bar: 2.3.4(@types/react@18.0.27)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.0.27)(react@18.2.0) - tslib: 2.5.0 - use-callback-ref: 1.3.0(@types/react@18.0.27)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.0.27)(react@18.2.0) - dev: false - - /react-style-singleton@2.2.1(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - get-nonce: 1.0.1 - invariant: 2.2.4 - react: 18.2.0 - tslib: 2.5.0 - dev: false - - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 - dev: false - - /regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: false - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: false - - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true - dependencies: - is-core-module: 2.11.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - /rollup@3.14.0: - resolution: {integrity: sha512-o23sdgCLcLSe3zIplT9nQ1+r97okuaiR+vmAPZPTDYB7/f3tgWIYNyiQveMsZwshBT0is4eGax/HH83Q7CG+/Q==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - dev: true - - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - dev: false - - /stylis@4.1.3: - resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==} - dev: false - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - /tiny-invariant@1.3.1: - resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} - dev: false - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - - /toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - dev: false - - /tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - dev: false - - /tslib@2.5.0: - resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - dev: false - - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - - /update-browserslist-db@1.0.10(browserslist@4.21.5): - resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.21.5 - escalade: 3.1.1 - picocolors: 1.0.0 - - /use-callback-ref@1.3.0(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - react: 18.2.0 - tslib: 2.5.0 - dev: false - - /use-sidecar@1.1.2(@types/react@18.0.27)(react@18.2.0): - resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@types/react': 18.0.27 - detect-node-es: 1.1.0 - react: 18.2.0 - tslib: 2.5.0 - dev: false - - /vite@4.1.1(@types/node@18.13.0): - resolution: {integrity: sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 18.13.0 - esbuild: 0.16.17 - postcss: 8.4.21 - resolve: 1.22.1 - rollup: 3.14.0 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - /yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} - dev: false diff --git a/web/postcss.config.cjs b/web/postcss.config.cjs new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/web/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/web/public/logo.svg b/web/public/logo.svg new file mode 100644 index 0000000..b9fa38c --- /dev/null +++ b/web/public/logo.svg @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/web/src/App.svelte b/web/src/App.svelte new file mode 100644 index 0000000..f75fc8d --- /dev/null +++ b/web/src/App.svelte @@ -0,0 +1,92 @@ + + +{#if isEnvBrowser()} +
+ +
+{/if} + + +
+ + +
+ + <div class="flex h-full flex-col gap-6 overflow-y-auto"> + <Groups /> + <Players /> + </div> + <div class="flex flex-col gap-4"> + <StatusIndicators /> + <Footer /> + </div> + </div> + </Sheet.Content> + </Sheet.Root> + </main> +</VisibilityProvider> diff --git a/web/src/App.tsx b/web/src/App.tsx deleted file mode 100644 index bc045be..0000000 --- a/web/src/App.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import Scoreboard from "./components/Scoreboard"; - -const App: React.FC = () => { - return <Scoreboard />; -}; - -export default App; diff --git a/web/src/components/Footer.tsx b/web/src/components/Footer.tsx deleted file mode 100644 index 5c81a47..0000000 --- a/web/src/components/Footer.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useContext } from "react"; -import { LocaleContext } from "./Scoreboard"; -import { - Text, - Tag, - TagLeftIcon, - HStack, - Tooltip, - useClipboard, -} from "@chakra-ui/react"; -import { FaUserAlt, FaUserFriends } from "react-icons/fa"; - -interface Props { - playerCount: number; - maxPlayers: number; - serverId: number; -} - -const Footer: React.FC<Props> = (props: Props) => { - const locales = useContext(LocaleContext); - const { hasCopied, onCopy } = useClipboard(props.serverId.toString(), 2500); - - return ( - <HStack> - <Tooltip closeOnClick={false} label={locales["ui_player_count"]}> - <Tag> - <TagLeftIcon as={FaUserFriends} boxSize={4} /> - <Text> - {props.playerCount} / {props.maxPlayers} - </Text> - </Tag> - </Tooltip> - <Tooltip - closeOnClick={false} - label={hasCopied ? locales["ui_copied"] : locales["ui_your_id"]} - > - <Tag onClick={onCopy} cursor="pointer"> - <TagLeftIcon as={FaUserAlt} boxSize={3} /> - <Text>{props.serverId}</Text> - </Tag> - </Tooltip> - </HStack> - ); -}; - -export default Footer; diff --git a/web/src/components/Scoreboard.tsx b/web/src/components/Scoreboard.tsx deleted file mode 100644 index f6f8fb1..0000000 --- a/web/src/components/Scoreboard.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import { createContext, useEffect, useState } from "react"; -import { - Drawer, - DrawerBody, - DrawerFooter, - DrawerHeader, - DrawerOverlay, - DrawerContent, - Button, - VStack, -} from "@chakra-ui/react"; -import GroupList from "./body/GroupList"; -import PlayerList from "./body/PlayerList"; -import Footer from "./Footer"; -import { Group } from "../interfaces/group"; -import type { Player } from "../interfaces/player"; -import type { Locale } from "../interfaces/locale"; -import { useNuiEvent } from "../hooks/useNuiEvent"; -import { fetchNui } from "../utils/fetchNui"; -import { isEnvBrowser } from "../utils/misc"; -import { debugData } from "../utils/debugData"; - -interface InitialProps { - serverName: string; - visibleParts: "both" | "groups" | "players"; - drawerSide: "left" | "right"; - serverId: number; - locales: Locale; -} - -interface VariableProps { - playerCount: number; - maxPlayers: number; - groups?: Array<Group>; - players?: Player; -} - -interface Props extends InitialProps, VariableProps {} - -const mockData: Props = { - serverName: "Server Name", - visibleParts: "both", - drawerSide: "right", - playerCount: 20, - maxPlayers: 64, - serverId: 6, - groups: [ - { label: "Police", count: 12 }, - { label: "EMS", count: 7, separator: true }, - { label: "Taxi", count: 5 }, - { label: "Mechanic", count: 0 }, - ], - players: { - "73": "Ingrim", - "67": "Branden", - "18": "Burke", - "87": "Bob with very long name", - "15": "Marven", - "100": "Artie", - "32": "Ben", - "12": "Dewain", - "71": "Hollis", - "5": "Tommy", - "78": "Ingrim", - "11": "Raphael", - "68": "Cristobal", - "50": "Efren", - "47": "Thorstein", - "16": "Fredek", - "54": "Roley", - "48": "Perkin", - "63": "Josias", - "93": "Charley", - }, - locales: { - ui_group: "Group", - ui_count: "Count", - ui_name: "Name", - ui_id: "ID", - ui_player_count: "Player count", - ui_your_id: "Your server ID", - ui_copied: "Copied to clipboard!", - }, -}; - -debugData([ - { - action: "setData", - data: mockData, - }, -]); - -export const LocaleContext = createContext(mockData.locales); - -const Scoreboard: React.FC = () => { - const [visible, setVisible] = useState(false); - const [data, setData] = useState<Props>(mockData); - - useNuiEvent("setVisible", setVisible); - useNuiEvent<Props>("setData", (newData) => { - setData((data) => ({ ...data, ...newData })); - }); - - const closeScoreboard = () => { - setVisible(false); - fetchNui("close"); - }; - - useEffect(() => { - if (!visible) return; - - const keyHandler = (e: KeyboardEvent) => { - if (e.code === "Escape") closeScoreboard(); - }; - - window.addEventListener("keydown", keyHandler); - return () => window.removeEventListener("keydown", keyHandler); - }, [visible]); - - return ( - <> - {isEnvBrowser() && ( - <Button colorScheme="blue" onClick={() => setVisible(true)}> - Open - </Button> - )} - <LocaleContext.Provider value={data.locales}> - <Drawer - isOpen={visible} - onClose={closeScoreboard} - placement={data.drawerSide} - blockScrollOnMount={false} - > - <DrawerOverlay /> - <DrawerContent> - <DrawerHeader>{data.serverName}</DrawerHeader> - - <DrawerBody> - <VStack spacing={6}> - {data.groups && - (data.visibleParts === "both" || - data.visibleParts === "groups") && ( - <GroupList groups={data.groups} /> - )} - - {data.players && - (data.visibleParts === "both" || - data.visibleParts === "players") && ( - <PlayerList players={data.players} /> - )} - </VStack> - </DrawerBody> - - <DrawerFooter justifyContent="center"> - <Footer - playerCount={data.playerCount} - maxPlayers={data.maxPlayers} - serverId={data.serverId} - /> - </DrawerFooter> - </DrawerContent> - </Drawer> - </LocaleContext.Provider> - </> - ); -}; - -export default Scoreboard; diff --git a/web/src/components/body/GroupList.tsx b/web/src/components/body/GroupList.tsx deleted file mode 100644 index 2ebf5c0..0000000 --- a/web/src/components/body/GroupList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useContext } from "react"; -import { LocaleContext } from "../Scoreboard"; -import { Stack, Flex, Text, Tag } from "@chakra-ui/react"; -import type { Group } from "../../interfaces/group"; -import SectionHeader from "./SectionHeader"; - -interface Props { - groups: Array<Group>; -} - -const GroupList: React.FC<Props> = (props: Props) => { - const locales = useContext(LocaleContext); - - return ( - <Stack direction="column" spacing="1"> - <SectionHeader left={locales["ui_group"]} right={locales["ui_count"]} /> - {props.groups.map((group, index) => ( - <> - <Flex - key={index} - w="2xs" - p={2} - justifyContent="space-between" - bg="gray.800" - borderRadius={4} - > - <Text noOfLines={1} casing="uppercase" fontWeight="medium"> - {group.label} - </Text> - <Tag colorScheme={group.count <= 0 ? "red" : "gray"}> - {group.count} - </Tag> - </Flex> - {group.separator && ( - <div - style={{ - margin: "8px 0 4px 0", - border: "1px solid #ffffff28", - }} - /> - )} - </> - ))} - </Stack> - ); -}; - -export default GroupList; diff --git a/web/src/components/body/PlayerList.tsx b/web/src/components/body/PlayerList.tsx deleted file mode 100644 index d4f9aea..0000000 --- a/web/src/components/body/PlayerList.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useContext } from "react"; -import { LocaleContext } from "../Scoreboard"; -import { Stack, Flex, Text, Tag } from "@chakra-ui/react"; -import { Player } from "../../interfaces/player"; -import SectionHeader from "./SectionHeader"; - -interface Props { - players: Player; -} - -const PlayerList: React.FC<Props> = (props: Props) => { - const locales = useContext(LocaleContext); - - return ( - <Stack direction="column" spacing={1}> - <SectionHeader left={locales["ui_name"]} right={locales["ui_id"]} /> - {Object.entries(props.players).map(([id, name], index) => ( - <Flex - key={index} - w="2xs" - p={2} - justifyContent="space-between" - bg="gray.800" - borderRadius={4} - > - <Text noOfLines={1} casing="uppercase" fontWeight="medium"> - {name} - </Text> - <Tag>{id}</Tag> - </Flex> - ))} - </Stack> - ); -}; - -export default PlayerList; diff --git a/web/src/components/body/SectionHeader.tsx b/web/src/components/body/SectionHeader.tsx deleted file mode 100644 index 1f4fc5d..0000000 --- a/web/src/components/body/SectionHeader.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Stack, Text } from "@chakra-ui/react"; - -interface Props { - left: string; - right: string; -} - -const styledText = { - fontWeight: "bold", - fontSize: "xs", // sm - color: "gray.400", - lineHeight: 4, - textTransform: "uppercase", - letterSpacing: "wider", -}; - -const SectionHeader: React.FC<Props> = (props: Props) => { - return ( - <Stack direction="row" justifyContent="space-between" pl={2} pr={2} pb={1}> - <Text sx={styledText}>{props.left}</Text> - <Text sx={styledText}>{props.right}</Text> - </Stack> - ); -}; - -export default SectionHeader; diff --git a/web/src/components/footer.svelte b/web/src/components/footer.svelte new file mode 100644 index 0000000..5d2f81c --- /dev/null +++ b/web/src/components/footer.svelte @@ -0,0 +1,47 @@ +<script lang="ts"> + import data from '$store/data'; + import locales from '$store/locales'; + import { fetchNui } from '$utils/fetchNui'; + import { cn } from '$utils/misc'; + import Icon, { loadIcons } from '@iconify/svelte'; + import * as Tooltip from './lib/tooltip'; + + let hasCopied = false; + + const copyServerId = () => { + fetchNui('copyServerId'); + hasCopied = true; + setTimeout(() => (hasCopied = false), 4000); + }; + + const copyIcons = { + copy: 'mdi:cursor-default-click', + copied: 'mdi:clipboard-check', + }; + + loadIcons([copyIcons.copy, copyIcons.copied]); +</script> + +{#if $data.footer} + <div class="flex select-none flex-wrap items-center justify-center gap-2"> + <Tooltip.Root openDelay={250} closeOnPointerDown={false} disableHoverableContent={true}> + <Tooltip.Trigger> + <button onclick={copyServerId} class="flex h-6 items-center gap-2 rounded-md bg-slate-600 px-2"> + <Icon icon="mingcute:user-2-fill" class="h-4 w-4" /> + {$data.footer.serverId} + </button> + </Tooltip.Trigger> + <Tooltip.Content class={cn(hasCopied && 'bg-green-600')}> + <div class="flex items-center gap-1"> + <Icon icon={hasCopied ? copyIcons.copied : copyIcons.copy} class="h-4 w-4" /> + <p>{hasCopied ? $locales.server_id_copied : $locales.copy_server_id}</p> + </div> + </Tooltip.Content> + </Tooltip.Root> + + <div class="flex h-6 items-center gap-2 rounded-md bg-slate-600 px-2"> + <Icon icon="mingcute:group-fill" class="h-4 w-4" /> + {$data.footer.playerCount}/{$data.footer.maxPlayers} + </div> + </div> +{/if} diff --git a/web/src/components/groups.svelte b/web/src/components/groups.svelte new file mode 100644 index 0000000..d170209 --- /dev/null +++ b/web/src/components/groups.svelte @@ -0,0 +1,31 @@ +<script lang="ts"> + import data from '$store/data'; + import config from '$store/config'; + import locales from '$store/locales'; + import { cn } from '$utils/misc'; +</script> + +{#if $data.groups} + <div> + <div class="mb-1 select-none font-bold uppercase">{$locales.groups}</div> + + <div class={cn('grid gap-1', $config.groupColumns === 1 ? 'grid-cols-1' : 'grid-cols-2')}> + {#each $data.groups as group (group)} + <div + class={cn( + 'flex items-center justify-between gap-2 rounded-md bg-slate-700 px-2', + $config.compactGroups ? 'py-1' : 'py-2' + )} + > + <span class="truncate">{group.label}</span> + <span + class={cn( + 'min-w-9 flex-shrink-0 select-none rounded-md bg-slate-800 px-2 text-center', + $config.highlightEmptyGroups && group.count === 0 && ' text-red-400' + )}>{group.count}</span + > + </div> + {/each} + </div> + </div> +{/if} diff --git a/web/src/components/lib/sheet/index.ts b/web/src/components/lib/sheet/index.ts new file mode 100644 index 0000000..09f92cc --- /dev/null +++ b/web/src/components/lib/sheet/index.ts @@ -0,0 +1,57 @@ +import { Dialog as SheetPrimitive } from 'bits-ui'; +import { type VariantProps, tv } from 'tailwind-variants'; +import Portal from './sheet-portal.svelte'; +import Overlay from './sheet-overlay.svelte'; +import Content from './sheet-content.svelte'; + +const Root = SheetPrimitive.Root; + +export { + Root, + Content, + // + Portal as SheetPortal, + Overlay as SheetOverlay, +}; + +export const sheetVariants = tv({ + base: 'fixed z-50 gap-4 bg-slate-900 p-6 shadow-lg', + variants: { + side: { + left: 'inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm', + right: 'inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm', + }, + }, + defaultVariants: { + side: 'right', + }, +}); + +export const sheetTransitions = { + left: { + in: { + x: '-100%', + duration: 500, + opacity: 1, + }, + out: { + x: '-100%', + duration: 300, + opacity: 1, + }, + }, + right: { + in: { + x: '100%', + duration: 500, + opacity: 1, + }, + out: { + x: '100%', + duration: 300, + opacity: 1, + }, + }, +}; + +export type Side = VariantProps<typeof sheetVariants>['side']; diff --git a/web/src/components/lib/sheet/sheet-content.svelte b/web/src/components/lib/sheet/sheet-content.svelte new file mode 100644 index 0000000..3b7ba00 --- /dev/null +++ b/web/src/components/lib/sheet/sheet-content.svelte @@ -0,0 +1,37 @@ +<script lang="ts"> + import { Dialog as SheetPrimitive } from 'bits-ui'; + import { fly } from 'svelte/transition'; + import { SheetOverlay, SheetPortal, type Side, sheetTransitions, sheetVariants } from './index'; + import { cn } from '$utils/misc'; + import type SheetConfig from '$types/config'; + + type $$Props = SheetPrimitive.ContentProps & { + side?: Side; + showOverlay?: SheetConfig['showOverlay']; + }; + + let className: $$Props['class'] = undefined; + export let side: $$Props['side'] = 'right'; + export let showOverlay: $$Props['showOverlay'] = false; + export { className as class }; + export let inTransition: $$Props['inTransition'] = fly; + export let inTransitionConfig: $$Props['inTransitionConfig'] = sheetTransitions[side ?? 'right'].in; + export let outTransition: $$Props['outTransition'] = fly; + export let outTransitionConfig: $$Props['outTransitionConfig'] = sheetTransitions[side ?? 'right'].out; +</script> + +<SheetPortal> + {#if showOverlay} + <SheetOverlay /> + {/if} + <SheetPrimitive.Content + {inTransition} + {inTransitionConfig} + {outTransition} + {outTransitionConfig} + class={cn(sheetVariants({ side }), className)} + {...$$restProps} + > + <slot /> + </SheetPrimitive.Content> +</SheetPortal> diff --git a/web/src/components/lib/sheet/sheet-overlay.svelte b/web/src/components/lib/sheet/sheet-overlay.svelte new file mode 100644 index 0000000..00cf12d --- /dev/null +++ b/web/src/components/lib/sheet/sheet-overlay.svelte @@ -0,0 +1,21 @@ +<script lang="ts"> + import { Dialog as SheetPrimitive } from 'bits-ui'; + import { fade } from 'svelte/transition'; + import { cn } from '$utils/misc'; + + type $$Props = SheetPrimitive.OverlayProps; + + let className: $$Props['class'] = undefined; + export { className as class }; + export let transition: $$Props['transition'] = fade; + export let transitionConfig: $$Props['transitionConfig'] = { + duration: 150, + }; +</script> + +<SheetPrimitive.Overlay + {transition} + {transitionConfig} + class={cn('fixed inset-0 z-50 bg-slate-900/50', className)} + {...$$restProps} +/> diff --git a/web/src/components/lib/sheet/sheet-portal.svelte b/web/src/components/lib/sheet/sheet-portal.svelte new file mode 100644 index 0000000..56bbf8b --- /dev/null +++ b/web/src/components/lib/sheet/sheet-portal.svelte @@ -0,0 +1,13 @@ +<script lang="ts"> + import { Dialog as SheetPrimitive } from 'bits-ui'; + import { cn } from '$utils/misc'; + + type $$Props = SheetPrimitive.PortalProps; + + let className: $$Props['class'] = undefined; + export { className as class }; +</script> + +<SheetPrimitive.Portal class={cn(className)} {...$$restProps}> + <slot /> +</SheetPrimitive.Portal> diff --git a/web/src/components/lib/tooltip/animation.ts b/web/src/components/lib/tooltip/animation.ts new file mode 100644 index 0000000..f4c11ed --- /dev/null +++ b/web/src/components/lib/tooltip/animation.ts @@ -0,0 +1,50 @@ +import { cubicOut } from 'svelte/easing'; +import type { TransitionConfig } from 'svelte/transition'; + +type FlyAndScaleParams = { + y?: number; + x?: number; + start?: number; + duration?: number; +}; + +export const flyAndScale = ( + node: Element, + params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } +): TransitionConfig => { + const style = getComputedStyle(node); + const transform = style.transform === 'none' ? '' : style.transform; + + const scaleConversion = (valueA: number, scaleA: [number, number], scaleB: [number, number]) => { + const [minA, maxA] = scaleA; + const [minB, maxB] = scaleB; + + const percentage = (valueA - minA) / (maxA - minA); + const valueB = percentage * (maxB - minB) + minB; + + return valueB; + }; + + const styleToString = (style: Record<string, number | string | undefined>): string => { + return Object.keys(style).reduce((str, key) => { + if (style[key] === undefined) return str; + return str + `${key}:${style[key]};`; + }, ''); + }; + + return { + duration: params.duration ?? 200, + delay: 0, + css: (t) => { + const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); + const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); + const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); + + return styleToString({ + transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, + opacity: t, + }); + }, + easing: cubicOut, + }; +}; diff --git a/web/src/components/lib/tooltip/index.ts b/web/src/components/lib/tooltip/index.ts new file mode 100644 index 0000000..7e70a4d --- /dev/null +++ b/web/src/components/lib/tooltip/index.ts @@ -0,0 +1,7 @@ +import { Tooltip as TooltipPrimitive } from 'bits-ui'; +import Content from './tooltip-content.svelte'; +import Trigger from './tooltip-trigger.svelte'; + +const Root = TooltipPrimitive.Root; + +export { Root, Trigger, Content }; diff --git a/web/src/components/lib/tooltip/tooltip-content.svelte b/web/src/components/lib/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..d91953f --- /dev/null +++ b/web/src/components/lib/tooltip/tooltip-content.svelte @@ -0,0 +1,26 @@ +<script lang="ts"> + import { Tooltip as TooltipPrimitive } from 'bits-ui'; + import { cn } from '$utils/misc'; + import { flyAndScale } from './animation'; + + type $$Props = TooltipPrimitive.ContentProps; + + let className: $$Props['class'] = undefined; + export let sideOffset: $$Props['sideOffset'] = 4; + export let transition: $$Props['transition'] = flyAndScale; + export let transitionConfig: $$Props['transitionConfig'] = { + y: 8, + duration: 150, + }; + export { className as class }; +</script> + +<TooltipPrimitive.Content + {transition} + {transitionConfig} + {sideOffset} + class={cn('z-50 overflow-hidden rounded-md bg-slate-700 px-2 py-1 text-xs', className)} + {...$$restProps} +> + <slot /> +</TooltipPrimitive.Content> diff --git a/web/src/components/lib/tooltip/tooltip-trigger.svelte b/web/src/components/lib/tooltip/tooltip-trigger.svelte new file mode 100644 index 0000000..9896c7c --- /dev/null +++ b/web/src/components/lib/tooltip/tooltip-trigger.svelte @@ -0,0 +1,14 @@ +<script lang="ts"> + import { Tooltip as TooltipPrimitive } from 'bits-ui'; + + type $$Props = TooltipPrimitive.TriggerProps; + + let className: $$Props['class'] = undefined; + export { className as class }; +</script> + +<TooltipPrimitive.Trigger asChild let:builder class={className} {...$$restProps}> + <div use:builder.action {...builder}> + <slot /> + </div> +</TooltipPrimitive.Trigger> diff --git a/web/src/components/players.svelte b/web/src/components/players.svelte new file mode 100644 index 0000000..ea943d8 --- /dev/null +++ b/web/src/components/players.svelte @@ -0,0 +1,29 @@ +<script lang="ts"> + import data from '$store/data'; + import config from '$store/config'; + import locales from '$store/locales'; + import { cn } from '$utils/misc'; +</script> + +{#if $data.players} + <div> + <div class="mb-1 select-none font-bold uppercase">{$locales.players}</div> + + <div class={cn('grid gap-1', $config.playerColumns === 1 ? 'grid-cols-1' : 'grid-cols-2')}> + {#each $data.players as player (player)} + <div + class={cn( + 'flex items-center justify-between gap-2 rounded-md bg-slate-700 px-2', + $config.uppercaseNames && 'uppercase', + $config.compactPlayers ? 'py-1' : 'py-2' + )} + > + <span class="truncate">{player.name ?? $locales.anonymous_player}</span> + {#if player.id !== undefined} + <span class="min-w-9 flex-shrink-0 select-none rounded-md bg-slate-800 px-2 text-center">{player.id}</span> + {/if} + </div> + {/each} + </div> + </div> +{/if} diff --git a/web/src/components/status-indicators.svelte b/web/src/components/status-indicators.svelte new file mode 100644 index 0000000..e0f32ca --- /dev/null +++ b/web/src/components/status-indicators.svelte @@ -0,0 +1,21 @@ +<script lang="ts"> + import data from '$store/data'; + import { cn } from '$utils/misc'; + import Icon from '@iconify/svelte'; + import * as Tooltip from './lib/tooltip'; +</script> + +{#if $data.statusIndicators} + <div class="flex select-none flex-wrap items-center justify-center gap-2"> + {#each $data.statusIndicators as item} + <Tooltip.Root openDelay={250} closeOnPointerDown={false} disableHoverableContent={true}> + <Tooltip.Trigger> + <Icon icon={item.icon} class={cn('h-6 w-6', item.state ? 'text-green-500' : 'text-red-500')} /> + </Tooltip.Trigger> + <Tooltip.Content> + <p>{item.label}</p> + </Tooltip.Content> + </Tooltip.Root> + {/each} + </div> +{/if} diff --git a/web/src/components/title.svelte b/web/src/components/title.svelte new file mode 100644 index 0000000..216eb25 --- /dev/null +++ b/web/src/components/title.svelte @@ -0,0 +1,22 @@ +<script lang="ts"> + import config from '$store/config'; + + const handleMissingImage = () => { + $config.title.logo = './logo.svg'; + }; +</script> + +<div class="flex h-8 select-none items-center gap-2"> + {#if $config.title.logo !== false} + <img + class="h-full" + style="color-scheme:dark;" + src={$config.title.logo ?? 'defaultTitleLogo'} + alt="Server logo" + onerror={handleMissingImage} + /> + {/if} + {#if $config.title.text !== false} + <p class="text-xl font-semibold">{$config.title.text ?? 'AC Scoreboard'}</p> + {/if} +</div> diff --git a/web/src/hooks/useNuiEvent.ts b/web/src/hooks/useNuiEvent.ts deleted file mode 100644 index 1cca884..0000000 --- a/web/src/hooks/useNuiEvent.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MutableRefObject, useEffect, useRef } from "react"; -import { noop } from "../utils/misc"; - -interface NuiMessageData<T = unknown> { - action: string; - data: T; -} - -type NuiHandlerSignature<T> = (data: T) => void; - -/** - * A hook that manage events listeners for receiving data from the client scripts - * @param action The specific `action` that should be listened for. - * @param handler The callback function that will handle data relayed by this hook - * - * @example - * useNuiEvent<{visibility: true, wasVisible: 'something'}>('setVisible', (data) => { - * // whatever logic you want - * }) - * - **/ - -export const useNuiEvent = <T = any>( - action: string, - handler: (data: T) => void -) => { - const savedHandler: MutableRefObject<NuiHandlerSignature<T>> = useRef(noop); - - // Make sure we handle for a reactive handler - useEffect(() => { - savedHandler.current = handler; - }, [handler]); - - useEffect(() => { - const eventListener = (event: MessageEvent<NuiMessageData<T>>) => { - const { action: eventAction, data } = event.data; - - if (savedHandler.current) { - if (eventAction === action) { - savedHandler.current(data); - } - } - }; - - window.addEventListener("message", eventListener); - // Remove Event Listener on component cleanup - return () => window.removeEventListener("message", eventListener); - }, [action]); -}; diff --git a/web/src/index.css b/web/src/index.css deleted file mode 100644 index f8fcd89..0000000 --- a/web/src/index.css +++ /dev/null @@ -1,19 +0,0 @@ -body { - background: none !important; - overflow: hidden !important; - user-select: none; - margin: 0; -} - -:root { - color-scheme: normal !important; -} - -::-webkit-scrollbar { - width: 4px; -} - -::-webkit-scrollbar-thumb { - background: var(--chakra-colors-gray-400); - border-radius: 50vh; -} diff --git a/web/src/index.pcss b/web/src/index.pcss new file mode 100644 index 0000000..9a487ec --- /dev/null +++ b/web/src/index.pcss @@ -0,0 +1,84 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 217 33% 17%; + --foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --ring: hsl(212.7, 26.8%, 83.9); + + --radius: 0.5rem; + } +} + +@layer base { + * { + @apply border-border focus:outline-none; + } + + body { + @apply bg-transparent text-foreground; + } +} + +#app { + @apply h-screen w-screen; +} + +/* rem unit scaling */ +/* +@media screen and (min-width: 1920px) { + :root { + font-size: 16px; + } +} + +@media screen and (min-width: 2560px) { + :root { + font-size: 19px; + } +} +*/ + +/* scrollbar style */ +::-webkit-scrollbar { + width: 0px; +} + +::-webkit-scrollbar-track { + @apply bg-slate-700; +} + +::-webkit-scrollbar-thumb { + @apply bg-slate-500; +} + +::-webkit-scrollbar-thumb:hover { + @apply bg-slate-400; +} diff --git a/web/src/interfaces/group.ts b/web/src/interfaces/group.ts deleted file mode 100644 index dc91dd7..0000000 --- a/web/src/interfaces/group.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Group { - label: string; - count: number; - separator?: true; -} diff --git a/web/src/interfaces/locale.ts b/web/src/interfaces/locale.ts deleted file mode 100644 index 8274cbe..0000000 --- a/web/src/interfaces/locale.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Locale { - [key: string]: string; -} diff --git a/web/src/interfaces/player.ts b/web/src/interfaces/player.ts deleted file mode 100644 index 2fc7262..0000000 --- a/web/src/interfaces/player.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Player { - [key: string]: string; -} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..b9709ec --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,19 @@ +import { mount } from 'svelte'; +import './index.pcss'; +import App from './App.svelte'; +import { isEnvBrowser } from '$utils/misc'; + +const app = mount(App, { + target: document.getElementById('app')!, +}); + +if (isEnvBrowser()) { + const root = document.getElementById('app'); + + root!.style.backgroundImage = 'url("https://i.ibb.co/B6vJKtS/image.png")'; + root!.style.backgroundSize = 'cover'; + root!.style.backgroundRepeat = 'no-repeat'; + root!.style.backgroundPosition = 'center'; +} + +export default app; diff --git a/web/src/main.tsx b/web/src/main.tsx deleted file mode 100644 index c93eddf..0000000 --- a/web/src/main.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import { ChakraProvider } from "@chakra-ui/react"; -import { VisibilityProvider } from "./providers/VisibilityProvider"; -import { debugData } from "./utils/debugData"; - -import { theme } from "./theme"; -import "./index.css"; -import App from "./App"; - -debugData([ - { - action: "setVisible", - data: true, - }, -]); - -const container = document.getElementById("root") as HTMLElement; -const root = createRoot(container); -root.render( - <StrictMode> - <VisibilityProvider> - <ChakraProvider theme={theme}> - <App /> - </ChakraProvider> - </VisibilityProvider> - </StrictMode> -); diff --git a/web/src/providers/VisibilityProvider.svelte b/web/src/providers/VisibilityProvider.svelte new file mode 100644 index 0000000..92a91e0 --- /dev/null +++ b/web/src/providers/VisibilityProvider.svelte @@ -0,0 +1,14 @@ +<script lang="ts"> + import visibility from '$store/visibility'; + + let isVisible = $state(false); + + visibility.subscribe((visible) => { + isVisible = visible; + }); +</script> + +<!-- svelte-ignore slot_element_deprecated --> +{#if isVisible} + <slot /> +{/if} diff --git a/web/src/providers/VisibilityProvider.tsx b/web/src/providers/VisibilityProvider.tsx deleted file mode 100644 index 917e382..0000000 --- a/web/src/providers/VisibilityProvider.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { Context, createContext, useContext, useState } from "react"; -import { useNuiEvent } from "../hooks/useNuiEvent"; - -const VisibilityCtx = createContext<VisibilityProviderValue | null>(null); - -interface VisibilityProviderValue { - setVisible: (visible: boolean) => void; - visible: boolean; -} - -// This should be mounted at the top level of your application, it is currently set to apply a CSS visibility value. -export const VisibilityProvider: React.FC<{ children: React.ReactNode }> = ({ - children, -}) => { - const [visible, setVisible] = useState(false); - - useNuiEvent<boolean>("setVisible", setVisible); - - return ( - <VisibilityCtx.Provider - value={{ - visible, - setVisible, - }} - > - <div - style={{ visibility: visible ? "visible" : "hidden", height: "100%" }} - > - {children} - </div> - </VisibilityCtx.Provider> - ); -}; - -export const useVisibility = () => - useContext<VisibilityProviderValue>( - VisibilityCtx as Context<VisibilityProviderValue> - ); diff --git a/web/src/store/config.ts b/web/src/store/config.ts new file mode 100644 index 0000000..b146c99 --- /dev/null +++ b/web/src/store/config.ts @@ -0,0 +1,19 @@ +import { writable } from 'svelte/store'; +import type SheetConfig from '$types/config'; + +export default writable<SheetConfig>({ + title: { + text: 'AC Scoreboard', + logo: './logo.svg', + }, + side: 'right', + showOverlay: false, + closeOnEscape: true, + closeOnOutsideClick: true, + uppercaseNames: false, + highlightEmptyGroups: true, + compactPlayers: false, + compactGroups: false, + playerColumns: 1, + groupColumns: 1, +}); diff --git a/web/src/store/data.ts b/web/src/store/data.ts new file mode 100644 index 0000000..799a42f --- /dev/null +++ b/web/src/store/data.ts @@ -0,0 +1,28 @@ +import { writable } from 'svelte/store'; +import type SheetData from '$types/data'; + +export default writable<SheetData>({ + footer: { + serverId: 7, + playerCount: 63, + maxPlayers: 100, + }, + groups: [ + { label: 'Police', count: 7 }, + { label: 'EMS', count: 6 }, + { label: 'Mechanics', count: 2 }, + { label: 'Taxi', count: 0 }, + { label: 'Unemployed', count: 47 }, + ], + players: [ + { name: 'Bob', id: '7' }, + { name: 'George Washington had very long name', id: '32' }, + { name: 'Franta', id: '1' }, + { name: 'Zoo', id: '60' }, + ], + statusIndicators: [ + { label: 'House robbery', icon: 'mdi:house', state: true }, + { label: 'Store robbery', icon: 'mdi:store', state: true }, + { label: 'Bank robbery', icon: 'mdi:bank', state: false }, + ], +}); diff --git a/web/src/store/locales.ts b/web/src/store/locales.ts new file mode 100644 index 0000000..dc8fb7f --- /dev/null +++ b/web/src/store/locales.ts @@ -0,0 +1,10 @@ +import { writable } from 'svelte/store'; +import type Locales from '$types/locales'; + +export default writable<Locales>({ + groups: 'Groups', + players: 'Players', + copy_server_id: 'Copy your server ID', + server_id_copied: 'Server ID copied', + anonymous_player: 'Anonymous player', +}); diff --git a/web/src/store/visibility.ts b/web/src/store/visibility.ts new file mode 100644 index 0000000..38fbbcc --- /dev/null +++ b/web/src/store/visibility.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export default writable(false); diff --git a/web/src/theme/index.ts b/web/src/theme/index.ts deleted file mode 100644 index a88a26c..0000000 --- a/web/src/theme/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { extendTheme, type ThemeConfig } from "@chakra-ui/react"; - -const config: ThemeConfig = { - initialColorMode: "dark", - useSystemColorMode: false, -}; - -export const theme = extendTheme({ - config, -}); diff --git a/web/src/types/config.ts b/web/src/types/config.ts new file mode 100644 index 0000000..39515c7 --- /dev/null +++ b/web/src/types/config.ts @@ -0,0 +1,20 @@ +type Title = { + text?: string | false; + logo?: string | false; +}; + +type SheetConfig = { + title: Title; + side?: 'left' | 'right'; + showOverlay?: boolean; + closeOnEscape?: boolean; + closeOnOutsideClick?: boolean; + uppercaseNames?: boolean; + highlightEmptyGroups?: boolean; + compactPlayers?: boolean; + compactGroups?: boolean; + playerColumns?: 1 | 2; + groupColumns?: 1 | 2; +}; + +export type { SheetConfig as default }; diff --git a/web/src/types/data.ts b/web/src/types/data.ts new file mode 100644 index 0000000..c333cf7 --- /dev/null +++ b/web/src/types/data.ts @@ -0,0 +1,30 @@ +type Footer = { + serverId: number; + playerCount: number; + maxPlayers: number; +}; + +type Group = { + label: string; + count: number; +}; + +type Player = { + name?: string; + id?: string; +}; + +type StatusIndicator = { + label: string; + icon: string; + state: boolean; +}; + +type SheetData = { + groups?: Group[]; + players?: Player[]; + statusIndicators?: StatusIndicator[]; + footer?: Footer; +}; + +export type { SheetData as default }; diff --git a/web/src/types/locales.ts b/web/src/types/locales.ts new file mode 100644 index 0000000..f27bee4 --- /dev/null +++ b/web/src/types/locales.ts @@ -0,0 +1,9 @@ +type Locales = { + groups: string; + players: string; + copy_server_id: string; + server_id_copied: string; + anonymous_player: string; +}; + +export type { Locales as default }; diff --git a/web/src/utils/debugData.ts b/web/src/utils/debugData.ts index afb334b..a5ce7af 100644 --- a/web/src/utils/debugData.ts +++ b/web/src/utils/debugData.ts @@ -1,4 +1,4 @@ -import { isEnvBrowser } from "./misc"; +import { isEnvBrowser } from './misc'; interface DebugEvent<T = any> { action: string; @@ -13,11 +13,11 @@ interface DebugEvent<T = any> { * @param timer - How long until it should trigger (ms) */ export const debugData = <P>(events: DebugEvent<P>[], timer = 1000): void => { - if (process.env.NODE_ENV === "development" && isEnvBrowser()) { + if (isEnvBrowser()) { for (const event of events) { setTimeout(() => { window.dispatchEvent( - new MessageEvent("message", { + new MessageEvent('message', { data: { action: event.action, data: event.data, diff --git a/web/src/utils/fetchNui.ts b/web/src/utils/fetchNui.ts index a8b923a..50ab146 100644 --- a/web/src/utils/fetchNui.ts +++ b/web/src/utils/fetchNui.ts @@ -1,33 +1,24 @@ /** - * Simple wrapper around fetch API tailored for CEF/NUI use. This abstraction - * can be extended to include AbortController if needed or if the response isn't - * JSON. Tailor it to your needs. - * * @param eventName - The endpoint eventname to target * @param data - Data you wish to send in the NUI Callback * * @return returnData - A promise for the data sent back by the NuiCallbacks CB argument */ -export async function fetchNui<T = any>( - eventName: string, - data?: any -): Promise<T> { +export async function fetchNui<T = any>(eventName: string, data: unknown = {}): Promise<T> { const options = { - method: "post", + method: 'post', headers: { - "Content-Type": "application/json; charset=UTF-8", + 'Content-Type': 'application/json; charset=UTF-8', }, body: JSON.stringify(data), }; const resourceName = (window as any).GetParentResourceName ? (window as any).GetParentResourceName() - : "nui-frame-app"; + : 'nui-frame-app'; const resp = await fetch(`https://${resourceName}/${eventName}`, options); - const respFormatted = await resp.json(); - - return respFormatted; + return await resp.json(); } diff --git a/web/src/utils/misc.ts b/web/src/utils/misc.ts index 24a1032..1eaffad 100644 --- a/web/src/utils/misc.ts +++ b/web/src/utils/misc.ts @@ -1,5 +1,8 @@ -// Will return whether the current environment is in a regular browser and not CEF +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + export const isEnvBrowser = (): boolean => !(window as any).invokeNative; -// Basic no operation function -export const noop = () => {}; +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/web/src/utils/useNuiEvent.ts b/web/src/utils/useNuiEvent.ts new file mode 100644 index 0000000..e2c9d1d --- /dev/null +++ b/web/src/utils/useNuiEvent.ts @@ -0,0 +1,48 @@ +import { onDestroy } from 'svelte'; + +interface NuiMessage<T = unknown> { + action: string; + data: T; +} + +/** + * A function that manage events listeners for receiving data from the client scripts + * @param action The specific `action` that should be listened for. + * @param handler The callback function that will handle data relayed by this function + * + * @example + * useNuiEvent<{visibility: true, wasVisible: 'something'}>('setVisible', (data) => { + * // whatever logic you want + * }) + * + **/ + +type NuiEventHandler<T = any> = (data: T) => void; + +const eventListeners = new Map<string, NuiEventHandler[]>(); + +const eventListener = (event: MessageEvent<NuiMessage>) => { + const { action, data } = event.data; + const handlers = eventListeners.get(action); + + if (handlers) { + handlers.forEach((handler) => handler(data)); + } +}; + +window.addEventListener('message', eventListener); + +export function useNuiEvent<T = unknown>(action: string, handler: NuiEventHandler<T>) { + const handlers = eventListeners.get(action) || []; + handlers.push(handler); + eventListeners.set(action, handlers); + + onDestroy(() => { + const handlers = eventListeners.get(action) || []; + + eventListeners.set( + action, + handlers.filter((h) => h !== handler) + ); + }); +} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts index 11f02fe..4078e74 100644 --- a/web/src/vite-env.d.ts +++ b/web/src/vite-env.d.ts @@ -1 +1,2 @@ +/// <reference types="svelte" /> /// <reference types="vite/client" /> diff --git a/web/svelte.config.js b/web/svelte.config.js new file mode 100644 index 0000000..3bce8ea --- /dev/null +++ b/web/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +}; diff --git a/web/tailwind.config.ts b/web/tailwind.config.ts new file mode 100644 index 0000000..eb7f901 --- /dev/null +++ b/web/tailwind.config.ts @@ -0,0 +1,35 @@ +import { fontFamily } from 'tailwindcss/defaultTheme'; +import type { Config } from 'tailwindcss'; + +const config: Config = { + content: ['./src/**/*.{html,js,svelte,ts}'], + theme: { + extend: { + colors: { + border: 'hsl(var(--border) / <alpha-value>)', + input: 'hsl(var(--input) / <alpha-value>)', + ring: 'hsl(var(--ring) / <alpha-value>)', + background: 'hsl(var(--background) / <alpha-value>)', + foreground: 'hsl(var(--foreground) / <alpha-value>)', + primary: { + DEFAULT: 'hsl(var(--primary) / <alpha-value>)', + foreground: 'hsl(var(--primary-foreground) / <alpha-value>)', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary) / <alpha-value>)', + foreground: 'hsl(var(--secondary-foreground) / <alpha-value>)', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + fontFamily: { + sans: ['Inter var', ...fontFamily.sans], + }, + }, + }, +}; + +export default config; diff --git a/web/tsconfig.json b/web/tsconfig.json index 917783f..cfc7a20 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -1,22 +1,24 @@ { + "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { - "target": "esnext", + "target": "ESNext", "useDefineForClassFields": true, - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, + "module": "ESNext", "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", "resolveJsonModule": true, + "allowJs": true, + "checkJs": true, "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" + "baseUrl": ".", + "paths": { + "$utils": ["./src/utils"], + "$utils/*": ["./src/utils/*"], + "$types": ["./src/types"], + "$types/*": ["./src/types/*"], + "$store": ["./src/store"], + "$store/*": ["./src/store/*"] + } }, - "include": ["**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"], + "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/web/tsconfig.node.json b/web/tsconfig.node.json index e993792..65dbdb9 100644 --- a/web/tsconfig.node.json +++ b/web/tsconfig.node.json @@ -1,8 +1,8 @@ { "compilerOptions": { "composite": true, - "module": "esnext", - "moduleResolution": "node" + "module": "ESNext", + "moduleResolution": "Node" }, "include": ["vite.config.ts"] } diff --git a/web/vite.config.ts b/web/vite.config.ts index 4a20df2..9f53605 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -1,11 +1,21 @@ import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import * as path from 'path'; export default defineConfig({ - plugins: [react()], - base: "./", + plugins: [svelte()], + base: './', + server: { + port: 3000, + }, build: { - outDir: "build", - target: "esnext", - } + outDir: 'build', + }, + resolve: { + alias: { + $utils: path.resolve('./src/utils'), + $types: path.resolve('./src/types'), + $store: path.resolve('./src/store'), + }, + }, });