From a10bd1bbe85b744c8c119c02422135bac3f81250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sat, 4 Oct 2025 14:40:06 -0400 Subject: [PATCH 001/114] Fully restructure project --- firebase/.firebaserc => .firebaserc | 0 .github/workflows/firebase-hosting-merge.yml | 28 ++++++++ .../firebase-hosting-pull-request.yml | 28 ++++++++ firebase/.gitignore => .gitignore | 49 ++++++++++++++ frontend/.metadata => .metadata | 0 .../launch.json | 0 .../tasks.json | 22 ++++++ README.md | 17 ++++- ...ysis_options.yaml => analysis_options.yaml | 0 {frontend/assets => assets}/img/logo.png | Bin {frontend/assets => assets}/img/name.png | Bin frontend/build.yaml => build.yaml | 0 firebase.json | 63 ++++++++++++++++++ firebase/.vscode.example/tasks.json | 27 -------- firebase/firebase.json | 37 ---------- ...ore.indexes.json => firestore.indexes.json | 0 firebase/firestore.rules => firestore.rules | 0 frontend/.gitignore | 48 ------------- frontend/README.md | 16 ----- frontend/firebase.json | 1 - functions/.env.hackncsu-today | 11 +++ {firebase/functions => functions}/.gitignore | 0 .../functions => functions}/auth/__init__.py | 0 .../auth/oauth_callback.py | 2 +- .../firestore/__init__.py | 0 .../firestore/teams.py | 0 {firebase/functions => functions}/main.py | 0 .../functions => functions}/requirements.txt | 0 {frontend/lib => lib}/config/constants.dart | 2 +- .../lib => lib}/config/firebase_options.dart | 0 {frontend/lib => lib}/config/router.dart | 0 {frontend/lib => lib}/exception.dart | 0 .../features/authenticator/authenticator.dart | 0 .../features/streams/event_data_stream.dart | 0 .../features/streams/event_state_stream.dart | 0 .../features/streams/hack_user_stream.dart | 0 {frontend/lib => lib}/main.dart | 0 .../lib => lib}/models/event/event_data.dart | 0 .../lib => lib}/models/event/event_state.dart | 0 .../models/extensions/duration.dart | 0 {frontend/lib => lib}/models/hack_user.dart | 0 {frontend/lib => lib}/models/team.dart | 0 .../screens/home/components/logout_modal.dart | 0 {frontend/lib => lib}/screens/home/home.dart | 0 .../components/edit_resources_modal.dart | 0 .../components/editable_overlay.dart | 0 .../organizer/components/execute_modal.dart | 0 .../organizer/features/page_controller.dart | 0 .../home/views/organizer/models/task.dart | 0 .../home/views/organizer/organizer_view.dart | 0 .../home/views/organizer/pages/tasks.dart | 0 .../components/cards/basic_card.dart | 0 .../components/cards/checklist_card.dart | 0 .../components/cards/live_card.dart | 0 .../closing_ceremony_view.dart | 0 .../live_card_views/in_progress_view.dart | 0 .../cards/live_card_views/initial_view.dart | 0 .../opening_ceremony_view.dart | 0 .../cards/live_card_views/standby_view.dart | 0 .../components/cards/resource_card.dart | 0 .../components/cards/team_card.dart | 0 .../participant/components/discord_embed.dart | 0 .../internal_resource_item.dart | 0 .../resource_items/link_resource_item.dart | 0 .../resource_items/resource_item.dart | 0 .../views/participant/participant_view.dart | 0 .../components/authenticating_modal.dart | 0 .../screens/login/components/error_modal.dart | 0 .../login/components/primary_button.dart | 0 .../lib => lib}/screens/login/login.dart | 0 .../screens/not_found/not_found.dart | 0 .../services/firebase/auth_service.dart | 0 .../services/firebase/firestore_service.dart | 0 .../services/firebase/functions_service.dart | 0 .../lib => lib}/services/hive_service.dart | 0 .../lib => lib}/services/oauth_service.dart | 2 +- .../services/organizer/task_service.dart | 0 frontend/pubspec.lock => pubspec.lock | 0 frontend/pubspec.yaml => pubspec.yaml | 0 {frontend/test => test}/widget_test.dart | 0 {frontend/web => web}/favicon.png | Bin {frontend/web => web}/icons/Icon-192.png | Bin {frontend/web => web}/icons/Icon-512.png | Bin .../web => web}/icons/Icon-maskable-192.png | Bin .../web => web}/icons/Icon-maskable-512.png | Bin {frontend/web => web}/index.html | 0 {frontend/web => web}/manifest.json | 0 87 files changed, 219 insertions(+), 134 deletions(-) rename firebase/.firebaserc => .firebaserc (100%) create mode 100644 .github/workflows/firebase-hosting-merge.yml create mode 100644 .github/workflows/firebase-hosting-pull-request.yml rename firebase/.gitignore => .gitignore (62%) rename frontend/.metadata => .metadata (100%) rename {frontend/.vscode.example => .vscode.example}/launch.json (100%) rename {frontend/.vscode.example => .vscode.example}/tasks.json (53%) rename frontend/analysis_options.yaml => analysis_options.yaml (100%) rename {frontend/assets => assets}/img/logo.png (100%) rename {frontend/assets => assets}/img/name.png (100%) rename frontend/build.yaml => build.yaml (100%) create mode 100644 firebase.json delete mode 100644 firebase/.vscode.example/tasks.json delete mode 100644 firebase/firebase.json rename firebase/firestore.indexes.json => firestore.indexes.json (100%) rename firebase/firestore.rules => firestore.rules (100%) delete mode 100644 frontend/.gitignore delete mode 100644 frontend/README.md delete mode 100644 frontend/firebase.json create mode 100644 functions/.env.hackncsu-today rename {firebase/functions => functions}/.gitignore (100%) rename {firebase/functions => functions}/auth/__init__.py (100%) rename {firebase/functions => functions}/auth/oauth_callback.py (99%) rename {firebase/functions => functions}/firestore/__init__.py (100%) rename {firebase/functions => functions}/firestore/teams.py (100%) rename {firebase/functions => functions}/main.py (100%) rename {firebase/functions => functions}/requirements.txt (100%) rename {frontend/lib => lib}/config/constants.dart (81%) rename {frontend/lib => lib}/config/firebase_options.dart (100%) rename {frontend/lib => lib}/config/router.dart (100%) rename {frontend/lib => lib}/exception.dart (100%) rename {frontend/lib => lib}/features/authenticator/authenticator.dart (100%) rename {frontend/lib => lib}/features/streams/event_data_stream.dart (100%) rename {frontend/lib => lib}/features/streams/event_state_stream.dart (100%) rename {frontend/lib => lib}/features/streams/hack_user_stream.dart (100%) rename {frontend/lib => lib}/main.dart (100%) rename {frontend/lib => lib}/models/event/event_data.dart (100%) rename {frontend/lib => lib}/models/event/event_state.dart (100%) rename {frontend/lib => lib}/models/extensions/duration.dart (100%) rename {frontend/lib => lib}/models/hack_user.dart (100%) rename {frontend/lib => lib}/models/team.dart (100%) rename {frontend/lib => lib}/screens/home/components/logout_modal.dart (100%) rename {frontend/lib => lib}/screens/home/home.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/components/edit_resources_modal.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/components/editable_overlay.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/components/execute_modal.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/features/page_controller.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/models/task.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/organizer_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/organizer/pages/tasks.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/basic_card.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/checklist_card.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card_views/initial_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/live_card_views/standby_view.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/resource_card.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/cards/team_card.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/discord_embed.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/resource_items/internal_resource_item.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/resource_items/link_resource_item.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/components/resource_items/resource_item.dart (100%) rename {frontend/lib => lib}/screens/home/views/participant/participant_view.dart (100%) rename {frontend/lib => lib}/screens/login/components/authenticating_modal.dart (100%) rename {frontend/lib => lib}/screens/login/components/error_modal.dart (100%) rename {frontend/lib => lib}/screens/login/components/primary_button.dart (100%) rename {frontend/lib => lib}/screens/login/login.dart (100%) rename {frontend/lib => lib}/screens/not_found/not_found.dart (100%) rename {frontend/lib => lib}/services/firebase/auth_service.dart (100%) rename {frontend/lib => lib}/services/firebase/firestore_service.dart (100%) rename {frontend/lib => lib}/services/firebase/functions_service.dart (100%) rename {frontend/lib => lib}/services/hive_service.dart (100%) rename {frontend/lib => lib}/services/oauth_service.dart (97%) rename {frontend/lib => lib}/services/organizer/task_service.dart (100%) rename frontend/pubspec.lock => pubspec.lock (100%) rename frontend/pubspec.yaml => pubspec.yaml (100%) rename {frontend/test => test}/widget_test.dart (100%) rename {frontend/web => web}/favicon.png (100%) rename {frontend/web => web}/icons/Icon-192.png (100%) rename {frontend/web => web}/icons/Icon-512.png (100%) rename {frontend/web => web}/icons/Icon-maskable-192.png (100%) rename {frontend/web => web}/icons/Icon-maskable-512.png (100%) rename {frontend/web => web}/index.html (100%) rename {frontend/web => web}/manifest.json (100%) diff --git a/firebase/.firebaserc b/.firebaserc similarity index 100% rename from firebase/.firebaserc rename to .firebaserc diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml new file mode 100644 index 0000000..4274f0c --- /dev/null +++ b/.github/workflows/firebase-hosting-merge.yml @@ -0,0 +1,28 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on merge +on: + push: + branches: + - master + - dev +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.35.4 + - run: | + cd website + flutter build web --release + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: ${{ secrets.GITHUB_TOKEN }} + firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_HACKNCSU_TODAY }} + channelId: live + projectId: hackncsu-today diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml new file mode 100644 index 0000000..cecd6d2 --- /dev/null +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -0,0 +1,28 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on PR +on: pull_request +permissions: + checks: write + contents: read + pull-requests: write +jobs: + build_and_preview: + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.35.4 + - run: | + cd website + flutter build web --release + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: ${{ secrets.GITHUB_TOKEN }} + firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_HACKNCSU_TODAY }} + projectId: hackncsu-today diff --git a/firebase/.gitignore b/.gitignore similarity index 62% rename from firebase/.gitignore rename to .gitignore index f3a8527..361184f 100644 --- a/firebase/.gitignore +++ b/.gitignore @@ -1,3 +1,52 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +*.g.dart +*.freezed.dart + # Logs logs *.log diff --git a/frontend/.metadata b/.metadata similarity index 100% rename from frontend/.metadata rename to .metadata diff --git a/frontend/.vscode.example/launch.json b/.vscode.example/launch.json similarity index 100% rename from frontend/.vscode.example/launch.json rename to .vscode.example/launch.json diff --git a/frontend/.vscode.example/tasks.json b/.vscode.example/tasks.json similarity index 53% rename from frontend/.vscode.example/tasks.json rename to .vscode.example/tasks.json index 8fa254d..d29eeab 100644 --- a/frontend/.vscode.example/tasks.json +++ b/.vscode.example/tasks.json @@ -24,6 +24,28 @@ "isDefault": true }, "detail": "Runs `dart pub run build_runner watch` to automatically rebuild generated files." + }, + { + "label": "Start Firebase Emulators", + "type": "shell", + "command": "firebase", + "args": [ + "emulators:start" + ], + "options": { + "cwd": "${workspaceFolder}", + "env": { + "GOOGLE_APPLICATION_CREDENTIALS": ".json" + } + }, + "problemMatcher": [], + "presentation": { + "panel": "dedicated", + "clear": true + }, + "runOptions": { + "runOn": "folderOpen" + } } ] } \ No newline at end of file diff --git a/README.md b/README.md index 06a6dee..d9a21c7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ -# hackncsu-today +# hackncsu_today -Comprehensive software suite to manage Hack_NCState. Currently under development. +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/analysis_options.yaml b/analysis_options.yaml similarity index 100% rename from frontend/analysis_options.yaml rename to analysis_options.yaml diff --git a/frontend/assets/img/logo.png b/assets/img/logo.png similarity index 100% rename from frontend/assets/img/logo.png rename to assets/img/logo.png diff --git a/frontend/assets/img/name.png b/assets/img/name.png similarity index 100% rename from frontend/assets/img/name.png rename to assets/img/name.png diff --git a/frontend/build.yaml b/build.yaml similarity index 100% rename from frontend/build.yaml rename to build.yaml diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..e10282a --- /dev/null +++ b/firebase.json @@ -0,0 +1,63 @@ +{ + "flutter": { + "platforms": { + "dart": { + "lib/firebase_options.dart": { + "projectId": "hackncsu-today", + "configurations": { + "web": "1:638064491024:web:f32d36e7170d5a39e9a895" + } + } + } + } + }, + "functions": [ + { + "source": "functions", + "codebase": "default", + "ignore": [ + "venv", + ".git", + "firebase-debug.log", + "firebase-debug.*.log", + "*.local" + ], + "runtime": "python313" + } + ], + "emulators": { + "auth": { + "port": 9099 + }, + "functions": { + "port": 5001 + }, + "firestore": { + "port": 5500 + }, + "ui": { + "enabled": true + }, + "singleProjectMode": true + }, + "firestore": { + "database": "(default)", + "location": "nam5", + "rules": "firestore.rules", + "indexes": "firestore.indexes.json" + }, + "hosting": { + "public": "frontend/build/web", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} \ No newline at end of file diff --git a/firebase/.vscode.example/tasks.json b/firebase/.vscode.example/tasks.json deleted file mode 100644 index b501184..0000000 --- a/firebase/.vscode.example/tasks.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Start Firebase Emulators", - "type": "shell", - "command": "firebase", - "args": [ - "emulators:start" - ], - "options": { - "cwd": "${workspaceFolder}", - "env": { - "GOOGLE_APPLICATION_CREDENTIALS": ".json" - } - }, - "problemMatcher": [], - "presentation": { - "panel": "dedicated", - "clear": true - }, - "runOptions": { - "runOn": "folderOpen" - } - } - ] -} \ No newline at end of file diff --git a/firebase/firebase.json b/firebase/firebase.json deleted file mode 100644 index 15e14ba..0000000 --- a/firebase/firebase.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "functions": [ - { - "source": "functions", - "codebase": "default", - "ignore": [ - "venv", - ".git", - "firebase-debug.log", - "firebase-debug.*.log", - "*.local" - ], - "runtime": "python313" - } - ], - "emulators": { - "auth": { - "port": 9099 - }, - "functions": { - "port": 5001 - }, - "firestore": { - "port": 5500 - }, - "ui": { - "enabled": true - }, - "singleProjectMode": true - }, - "firestore": { - "database": "(default)", - "location": "nam5", - "rules": "firestore.rules", - "indexes": "firestore.indexes.json" - } -} diff --git a/firebase/firestore.indexes.json b/firestore.indexes.json similarity index 100% rename from firebase/firestore.indexes.json rename to firestore.indexes.json diff --git a/firebase/firestore.rules b/firestore.rules similarity index 100% rename from firebase/firestore.rules rename to firestore.rules diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index 959f457..0000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,48 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release - -*.g.dart -*.freezed.dart \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index d9a21c7..0000000 --- a/frontend/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# hackncsu_today - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/frontend/firebase.json b/frontend/firebase.json deleted file mode 100644 index 426f595..0000000 --- a/frontend/firebase.json +++ /dev/null @@ -1 +0,0 @@ -{"flutter":{"platforms":{"dart":{"lib/firebase_options.dart":{"projectId":"hackncsu-today","configurations":{"web":"1:638064491024:web:f32d36e7170d5a39e9a895"}}}}}} \ No newline at end of file diff --git a/functions/.env.hackncsu-today b/functions/.env.hackncsu-today new file mode 100644 index 0000000..c1b94e1 --- /dev/null +++ b/functions/.env.hackncsu-today @@ -0,0 +1,11 @@ +CLIENT_ID=1371413608394653736 +REDIRECT_URI=https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback +SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/1QoWfF3ooyeb5S9LkwmDgaG-3_01sOWNf1BUIpAALotk/edit?gid=0#gid=0 +WORKSHEET_NAME=Registrations +ORGANIZERS_LIST= +FIRST_NAME_COLUMN=0 +LAST_NAME_COLUMN=1 +PHONE_NUMBER_COLUMN=2 +EMAIL_COLUMN=3 +CHECKED_IN_COLUMN=6 +DISCORD_USERNAME_COLUMN=7 diff --git a/firebase/functions/.gitignore b/functions/.gitignore similarity index 100% rename from firebase/functions/.gitignore rename to functions/.gitignore diff --git a/firebase/functions/auth/__init__.py b/functions/auth/__init__.py similarity index 100% rename from firebase/functions/auth/__init__.py rename to functions/auth/__init__.py diff --git a/firebase/functions/auth/oauth_callback.py b/functions/auth/oauth_callback.py similarity index 99% rename from firebase/functions/auth/oauth_callback.py rename to functions/auth/oauth_callback.py index ec2e186..fa3092e 100644 --- a/firebase/functions/auth/oauth_callback.py +++ b/functions/auth/oauth_callback.py @@ -15,7 +15,7 @@ ) # set this via command: firebase functions:secrets:set CLIENT_SECRET REDIRECT_URI = StringParam( "REDIRECT_URI", - default="https://cf.today.hackncstate.org/oauth/callback", + default="https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback", description="The redirect URI for Discord OAuth2.", ) # set to http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback in .env.local for local testing diff --git a/firebase/functions/firestore/__init__.py b/functions/firestore/__init__.py similarity index 100% rename from firebase/functions/firestore/__init__.py rename to functions/firestore/__init__.py diff --git a/firebase/functions/firestore/teams.py b/functions/firestore/teams.py similarity index 100% rename from firebase/functions/firestore/teams.py rename to functions/firestore/teams.py diff --git a/firebase/functions/main.py b/functions/main.py similarity index 100% rename from firebase/functions/main.py rename to functions/main.py diff --git a/firebase/functions/requirements.txt b/functions/requirements.txt similarity index 100% rename from firebase/functions/requirements.txt rename to functions/requirements.txt diff --git a/frontend/lib/config/constants.dart b/lib/config/constants.dart similarity index 81% rename from frontend/lib/config/constants.dart rename to lib/config/constants.dart index e2ccf70..1ce09ee 100644 --- a/frontend/lib/config/constants.dart +++ b/lib/config/constants.dart @@ -1,4 +1,4 @@ const bool kFirebaseUseEmulator = true; -const bool kEmbedDiscord = false; +const bool kEmbedDiscord = true; const String kDiscordServerId = '1329464908986716265'; const String kDiscordChannelId = '1329464909641158754'; diff --git a/frontend/lib/config/firebase_options.dart b/lib/config/firebase_options.dart similarity index 100% rename from frontend/lib/config/firebase_options.dart rename to lib/config/firebase_options.dart diff --git a/frontend/lib/config/router.dart b/lib/config/router.dart similarity index 100% rename from frontend/lib/config/router.dart rename to lib/config/router.dart diff --git a/frontend/lib/exception.dart b/lib/exception.dart similarity index 100% rename from frontend/lib/exception.dart rename to lib/exception.dart diff --git a/frontend/lib/features/authenticator/authenticator.dart b/lib/features/authenticator/authenticator.dart similarity index 100% rename from frontend/lib/features/authenticator/authenticator.dart rename to lib/features/authenticator/authenticator.dart diff --git a/frontend/lib/features/streams/event_data_stream.dart b/lib/features/streams/event_data_stream.dart similarity index 100% rename from frontend/lib/features/streams/event_data_stream.dart rename to lib/features/streams/event_data_stream.dart diff --git a/frontend/lib/features/streams/event_state_stream.dart b/lib/features/streams/event_state_stream.dart similarity index 100% rename from frontend/lib/features/streams/event_state_stream.dart rename to lib/features/streams/event_state_stream.dart diff --git a/frontend/lib/features/streams/hack_user_stream.dart b/lib/features/streams/hack_user_stream.dart similarity index 100% rename from frontend/lib/features/streams/hack_user_stream.dart rename to lib/features/streams/hack_user_stream.dart diff --git a/frontend/lib/main.dart b/lib/main.dart similarity index 100% rename from frontend/lib/main.dart rename to lib/main.dart diff --git a/frontend/lib/models/event/event_data.dart b/lib/models/event/event_data.dart similarity index 100% rename from frontend/lib/models/event/event_data.dart rename to lib/models/event/event_data.dart diff --git a/frontend/lib/models/event/event_state.dart b/lib/models/event/event_state.dart similarity index 100% rename from frontend/lib/models/event/event_state.dart rename to lib/models/event/event_state.dart diff --git a/frontend/lib/models/extensions/duration.dart b/lib/models/extensions/duration.dart similarity index 100% rename from frontend/lib/models/extensions/duration.dart rename to lib/models/extensions/duration.dart diff --git a/frontend/lib/models/hack_user.dart b/lib/models/hack_user.dart similarity index 100% rename from frontend/lib/models/hack_user.dart rename to lib/models/hack_user.dart diff --git a/frontend/lib/models/team.dart b/lib/models/team.dart similarity index 100% rename from frontend/lib/models/team.dart rename to lib/models/team.dart diff --git a/frontend/lib/screens/home/components/logout_modal.dart b/lib/screens/home/components/logout_modal.dart similarity index 100% rename from frontend/lib/screens/home/components/logout_modal.dart rename to lib/screens/home/components/logout_modal.dart diff --git a/frontend/lib/screens/home/home.dart b/lib/screens/home/home.dart similarity index 100% rename from frontend/lib/screens/home/home.dart rename to lib/screens/home/home.dart diff --git a/frontend/lib/screens/home/views/organizer/components/edit_resources_modal.dart b/lib/screens/home/views/organizer/components/edit_resources_modal.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/components/edit_resources_modal.dart rename to lib/screens/home/views/organizer/components/edit_resources_modal.dart diff --git a/frontend/lib/screens/home/views/organizer/components/editable_overlay.dart b/lib/screens/home/views/organizer/components/editable_overlay.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/components/editable_overlay.dart rename to lib/screens/home/views/organizer/components/editable_overlay.dart diff --git a/frontend/lib/screens/home/views/organizer/components/execute_modal.dart b/lib/screens/home/views/organizer/components/execute_modal.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/components/execute_modal.dart rename to lib/screens/home/views/organizer/components/execute_modal.dart diff --git a/frontend/lib/screens/home/views/organizer/features/page_controller.dart b/lib/screens/home/views/organizer/features/page_controller.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/features/page_controller.dart rename to lib/screens/home/views/organizer/features/page_controller.dart diff --git a/frontend/lib/screens/home/views/organizer/models/task.dart b/lib/screens/home/views/organizer/models/task.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/models/task.dart rename to lib/screens/home/views/organizer/models/task.dart diff --git a/frontend/lib/screens/home/views/organizer/organizer_view.dart b/lib/screens/home/views/organizer/organizer_view.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/organizer_view.dart rename to lib/screens/home/views/organizer/organizer_view.dart diff --git a/frontend/lib/screens/home/views/organizer/pages/tasks.dart b/lib/screens/home/views/organizer/pages/tasks.dart similarity index 100% rename from frontend/lib/screens/home/views/organizer/pages/tasks.dart rename to lib/screens/home/views/organizer/pages/tasks.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/basic_card.dart b/lib/screens/home/views/participant/components/cards/basic_card.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/basic_card.dart rename to lib/screens/home/views/participant/components/cards/basic_card.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/checklist_card.dart b/lib/screens/home/views/participant/components/cards/checklist_card.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/checklist_card.dart rename to lib/screens/home/views/participant/components/cards/checklist_card.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card.dart b/lib/screens/home/views/participant/components/cards/live_card.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card.dart rename to lib/screens/home/views/participant/components/cards/live_card.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart rename to lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart rename to lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart rename to lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart rename to lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart rename to lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/resource_card.dart b/lib/screens/home/views/participant/components/cards/resource_card.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/resource_card.dart rename to lib/screens/home/views/participant/components/cards/resource_card.dart diff --git a/frontend/lib/screens/home/views/participant/components/cards/team_card.dart b/lib/screens/home/views/participant/components/cards/team_card.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/cards/team_card.dart rename to lib/screens/home/views/participant/components/cards/team_card.dart diff --git a/frontend/lib/screens/home/views/participant/components/discord_embed.dart b/lib/screens/home/views/participant/components/discord_embed.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/discord_embed.dart rename to lib/screens/home/views/participant/components/discord_embed.dart diff --git a/frontend/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart b/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart rename to lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart diff --git a/frontend/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart b/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart rename to lib/screens/home/views/participant/components/resource_items/link_resource_item.dart diff --git a/frontend/lib/screens/home/views/participant/components/resource_items/resource_item.dart b/lib/screens/home/views/participant/components/resource_items/resource_item.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/components/resource_items/resource_item.dart rename to lib/screens/home/views/participant/components/resource_items/resource_item.dart diff --git a/frontend/lib/screens/home/views/participant/participant_view.dart b/lib/screens/home/views/participant/participant_view.dart similarity index 100% rename from frontend/lib/screens/home/views/participant/participant_view.dart rename to lib/screens/home/views/participant/participant_view.dart diff --git a/frontend/lib/screens/login/components/authenticating_modal.dart b/lib/screens/login/components/authenticating_modal.dart similarity index 100% rename from frontend/lib/screens/login/components/authenticating_modal.dart rename to lib/screens/login/components/authenticating_modal.dart diff --git a/frontend/lib/screens/login/components/error_modal.dart b/lib/screens/login/components/error_modal.dart similarity index 100% rename from frontend/lib/screens/login/components/error_modal.dart rename to lib/screens/login/components/error_modal.dart diff --git a/frontend/lib/screens/login/components/primary_button.dart b/lib/screens/login/components/primary_button.dart similarity index 100% rename from frontend/lib/screens/login/components/primary_button.dart rename to lib/screens/login/components/primary_button.dart diff --git a/frontend/lib/screens/login/login.dart b/lib/screens/login/login.dart similarity index 100% rename from frontend/lib/screens/login/login.dart rename to lib/screens/login/login.dart diff --git a/frontend/lib/screens/not_found/not_found.dart b/lib/screens/not_found/not_found.dart similarity index 100% rename from frontend/lib/screens/not_found/not_found.dart rename to lib/screens/not_found/not_found.dart diff --git a/frontend/lib/services/firebase/auth_service.dart b/lib/services/firebase/auth_service.dart similarity index 100% rename from frontend/lib/services/firebase/auth_service.dart rename to lib/services/firebase/auth_service.dart diff --git a/frontend/lib/services/firebase/firestore_service.dart b/lib/services/firebase/firestore_service.dart similarity index 100% rename from frontend/lib/services/firebase/firestore_service.dart rename to lib/services/firebase/firestore_service.dart diff --git a/frontend/lib/services/firebase/functions_service.dart b/lib/services/firebase/functions_service.dart similarity index 100% rename from frontend/lib/services/firebase/functions_service.dart rename to lib/services/firebase/functions_service.dart diff --git a/frontend/lib/services/hive_service.dart b/lib/services/hive_service.dart similarity index 100% rename from frontend/lib/services/hive_service.dart rename to lib/services/hive_service.dart diff --git a/frontend/lib/services/oauth_service.dart b/lib/services/oauth_service.dart similarity index 97% rename from frontend/lib/services/oauth_service.dart rename to lib/services/oauth_service.dart index 2156ed7..747bc7d 100644 --- a/frontend/lib/services/oauth_service.dart +++ b/lib/services/oauth_service.dart @@ -27,7 +27,7 @@ class OAuthService { static final String _redirectUrl = kDebugMode ? 'http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback' - : 'https://cf.today.hackncstate.org/oauth/redirect'; + : 'https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback'; // TODO: https://stackoverflow.com/questions/49825799/use-custom-domain-for-firebase-function-http-calls /// performs interactive oauth2 flow diff --git a/frontend/lib/services/organizer/task_service.dart b/lib/services/organizer/task_service.dart similarity index 100% rename from frontend/lib/services/organizer/task_service.dart rename to lib/services/organizer/task_service.dart diff --git a/frontend/pubspec.lock b/pubspec.lock similarity index 100% rename from frontend/pubspec.lock rename to pubspec.lock diff --git a/frontend/pubspec.yaml b/pubspec.yaml similarity index 100% rename from frontend/pubspec.yaml rename to pubspec.yaml diff --git a/frontend/test/widget_test.dart b/test/widget_test.dart similarity index 100% rename from frontend/test/widget_test.dart rename to test/widget_test.dart diff --git a/frontend/web/favicon.png b/web/favicon.png similarity index 100% rename from frontend/web/favicon.png rename to web/favicon.png diff --git a/frontend/web/icons/Icon-192.png b/web/icons/Icon-192.png similarity index 100% rename from frontend/web/icons/Icon-192.png rename to web/icons/Icon-192.png diff --git a/frontend/web/icons/Icon-512.png b/web/icons/Icon-512.png similarity index 100% rename from frontend/web/icons/Icon-512.png rename to web/icons/Icon-512.png diff --git a/frontend/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png similarity index 100% rename from frontend/web/icons/Icon-maskable-192.png rename to web/icons/Icon-maskable-192.png diff --git a/frontend/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png similarity index 100% rename from frontend/web/icons/Icon-maskable-512.png rename to web/icons/Icon-maskable-512.png diff --git a/frontend/web/index.html b/web/index.html similarity index 100% rename from frontend/web/index.html rename to web/index.html diff --git a/frontend/web/manifest.json b/web/manifest.json similarity index 100% rename from frontend/web/manifest.json rename to web/manifest.json From 229d7c4792f082dc51e184385ce4c91a75e42b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sat, 18 Oct 2025 10:20:06 -0400 Subject: [PATCH 002/114] Remove all references to Flutter --- .github/workflows/firebase-hosting-merge.yml | 18 +- .../firebase-hosting-pull-request.yml | 17 +- .metadata | 30 - analysis_options.yaml | 33 - assets/img/logo.png | Bin 80488 -> 0 bytes assets/img/name.png | Bin 28236 -> 0 bytes build.yaml | 6 - firebase.json | 14 +- lib/config/constants.dart | 4 - lib/config/firebase_options.dart | 65 - lib/config/router.dart | 13 - lib/exception.dart | 10 - lib/features/authenticator/authenticator.dart | 187 --- lib/features/streams/event_data_stream.dart | 14 - lib/features/streams/event_state_stream.dart | 43 - lib/features/streams/hack_user_stream.dart | 12 - lib/main.dart | 53 - lib/models/event/event_data.dart | 58 - lib/models/event/event_state.dart | 33 - lib/models/extensions/duration.dart | 32 - lib/models/hack_user.dart | 33 - lib/models/team.dart | 29 - lib/screens/home/components/logout_modal.dart | 77 -- lib/screens/home/home.dart | 129 -- .../components/edit_resources_modal.dart | 290 ----- .../components/editable_overlay.dart | 27 - .../organizer/components/execute_modal.dart | 209 ---- .../organizer/features/page_controller.dart | 27 - .../home/views/organizer/models/task.dart | 43 - .../home/views/organizer/organizer_view.dart | 77 -- .../home/views/organizer/pages/tasks.dart | 67 - .../components/cards/basic_card.dart | 63 - .../components/cards/checklist_card.dart | 61 - .../components/cards/live_card.dart | 61 - .../closing_ceremony_view.dart | 10 - .../live_card_views/in_progress_view.dart | 214 ---- .../cards/live_card_views/initial_view.dart | 10 - .../opening_ceremony_view.dart | 10 - .../cards/live_card_views/standby_view.dart | 10 - .../components/cards/resource_card.dart | 113 -- .../components/cards/team_card.dart | 15 - .../participant/components/discord_embed.dart | 60 - .../internal_resource_item.dart | 22 - .../resource_items/link_resource_item.dart | 21 - .../resource_items/resource_item.dart | 68 -- .../views/participant/participant_view.dart | 62 - .../components/authenticating_modal.dart | 17 - lib/screens/login/components/error_modal.dart | 17 - .../login/components/primary_button.dart | 26 - lib/screens/login/login.dart | 154 --- lib/screens/not_found/not_found.dart | 35 - lib/services/firebase/auth_service.dart | 58 - lib/services/firebase/firestore_service.dart | 264 ---- lib/services/firebase/functions_service.dart | 87 -- lib/services/hive_service.dart | 12 - lib/services/oauth_service.dart | 119 -- lib/services/organizer/task_service.dart | 141 --- pubspec.lock | 1082 ----------------- pubspec.yaml | 115 -- test/widget_test.dart | 30 - web/favicon.png | Bin 917 -> 0 bytes web/icons/Icon-192.png | Bin 5292 -> 0 bytes web/icons/Icon-512.png | Bin 8252 -> 0 bytes web/icons/Icon-maskable-192.png | Bin 5594 -> 0 bytes web/icons/Icon-maskable-512.png | Bin 20998 -> 0 bytes web/index.html | 38 - web/manifest.json | 35 - 67 files changed, 19 insertions(+), 4661 deletions(-) delete mode 100644 .metadata delete mode 100644 analysis_options.yaml delete mode 100644 assets/img/logo.png delete mode 100644 assets/img/name.png delete mode 100644 build.yaml delete mode 100644 lib/config/constants.dart delete mode 100644 lib/config/firebase_options.dart delete mode 100644 lib/config/router.dart delete mode 100644 lib/exception.dart delete mode 100644 lib/features/authenticator/authenticator.dart delete mode 100644 lib/features/streams/event_data_stream.dart delete mode 100644 lib/features/streams/event_state_stream.dart delete mode 100644 lib/features/streams/hack_user_stream.dart delete mode 100644 lib/main.dart delete mode 100644 lib/models/event/event_data.dart delete mode 100644 lib/models/event/event_state.dart delete mode 100644 lib/models/extensions/duration.dart delete mode 100644 lib/models/hack_user.dart delete mode 100644 lib/models/team.dart delete mode 100644 lib/screens/home/components/logout_modal.dart delete mode 100644 lib/screens/home/home.dart delete mode 100644 lib/screens/home/views/organizer/components/edit_resources_modal.dart delete mode 100644 lib/screens/home/views/organizer/components/editable_overlay.dart delete mode 100644 lib/screens/home/views/organizer/components/execute_modal.dart delete mode 100644 lib/screens/home/views/organizer/features/page_controller.dart delete mode 100644 lib/screens/home/views/organizer/models/task.dart delete mode 100644 lib/screens/home/views/organizer/organizer_view.dart delete mode 100644 lib/screens/home/views/organizer/pages/tasks.dart delete mode 100644 lib/screens/home/views/participant/components/cards/basic_card.dart delete mode 100644 lib/screens/home/views/participant/components/cards/checklist_card.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart delete mode 100644 lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart delete mode 100644 lib/screens/home/views/participant/components/cards/resource_card.dart delete mode 100644 lib/screens/home/views/participant/components/cards/team_card.dart delete mode 100644 lib/screens/home/views/participant/components/discord_embed.dart delete mode 100644 lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart delete mode 100644 lib/screens/home/views/participant/components/resource_items/link_resource_item.dart delete mode 100644 lib/screens/home/views/participant/components/resource_items/resource_item.dart delete mode 100644 lib/screens/home/views/participant/participant_view.dart delete mode 100644 lib/screens/login/components/authenticating_modal.dart delete mode 100644 lib/screens/login/components/error_modal.dart delete mode 100644 lib/screens/login/components/primary_button.dart delete mode 100644 lib/screens/login/login.dart delete mode 100644 lib/screens/not_found/not_found.dart delete mode 100644 lib/services/firebase/auth_service.dart delete mode 100644 lib/services/firebase/firestore_service.dart delete mode 100644 lib/services/firebase/functions_service.dart delete mode 100644 lib/services/hive_service.dart delete mode 100644 lib/services/oauth_service.dart delete mode 100644 lib/services/organizer/task_service.dart delete mode 100644 pubspec.lock delete mode 100644 pubspec.yaml delete mode 100644 test/widget_test.dart delete mode 100644 web/favicon.png delete mode 100644 web/icons/Icon-192.png delete mode 100644 web/icons/Icon-512.png delete mode 100644 web/icons/Icon-maskable-192.png delete mode 100644 web/icons/Icon-maskable-512.png delete mode 100644 web/index.html delete mode 100644 web/manifest.json diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml index 4274f0c..0bca659 100644 --- a/.github/workflows/firebase-hosting-merge.yml +++ b/.github/workflows/firebase-hosting-merge.yml @@ -6,20 +6,20 @@ on: push: branches: - master - - dev jobs: build_and_deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up Flutter - uses: subosito/flutter-action@v2 + - uses: actions/checkout@v5 + - name: Set up Node.js + uses: actions/setup-node@v5 with: - channel: stable - flutter-version: 3.35.4 - - run: | - cd website - flutter build web --release + node-version: 'lts/*' + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Build with Vite + run: npm run build - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml index cecd6d2..c974612 100644 --- a/.github/workflows/firebase-hosting-pull-request.yml +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -12,15 +12,16 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up Flutter - uses: subosito/flutter-action@v2 + - uses: actions/checkout@v5 + - name: Set up Node.js + uses: actions/setup-node@v5 with: - channel: stable - flutter-version: 3.35.4 - - run: | - cd website - flutter build web --release + node-version: 'lts/*' + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Build with Vite + run: npm run build - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.metadata b/.metadata deleted file mode 100644 index 9fc6a8a..0000000 --- a/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "ea121f8859e4b13e47a8f845e4586164519588bc" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: ea121f8859e4b13e47a8f845e4586164519588bc - base_revision: ea121f8859e4b13e47a8f845e4586164519588bc - - platform: web - create_revision: ea121f8859e4b13e47a8f845e4586164519588bc - base_revision: ea121f8859e4b13e47a8f845e4586164519588bc - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/analysis_options.yaml b/analysis_options.yaml deleted file mode 100644 index cc4b000..0000000 --- a/analysis_options.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - prefer_single_quotes: true - -analyzer: - plugins: - - custom_lint - - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/assets/img/logo.png b/assets/img/logo.png deleted file mode 100644 index 57581ec8e732aceb035eb9e15b9f67d673ea3981..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80488 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

~pH{X`>p&Vg*2);{BIdoQc+FTu?+Y)D+F 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 diff --git a/build.yaml b/build.yaml deleted file mode 100644 index aaa6e0d..0000000 --- a/build.yaml +++ /dev/null @@ -1,6 +0,0 @@ -targets: - $default: - builders: - json_serializable: - options: - explicit_to_json: true \ No newline at end of file diff --git a/firebase.json b/firebase.json index e10282a..c860ee3 100644 --- a/firebase.json +++ b/firebase.json @@ -1,16 +1,4 @@ { - "flutter": { - "platforms": { - "dart": { - "lib/firebase_options.dart": { - "projectId": "hackncsu-today", - "configurations": { - "web": "1:638064491024:web:f32d36e7170d5a39e9a895" - } - } - } - } - }, "functions": [ { "source": "functions", @@ -47,7 +35,7 @@ "indexes": "firestore.indexes.json" }, "hosting": { - "public": "frontend/build/web", + "public": "dist", "ignore": [ "firebase.json", "**/.*", diff --git a/lib/config/constants.dart b/lib/config/constants.dart deleted file mode 100644 index 1ce09ee..0000000 --- a/lib/config/constants.dart +++ /dev/null @@ -1,4 +0,0 @@ -const bool kFirebaseUseEmulator = true; -const bool kEmbedDiscord = true; -const String kDiscordServerId = '1329464908986716265'; -const String kDiscordChannelId = '1329464909641158754'; diff --git a/lib/config/firebase_options.dart b/lib/config/firebase_options.dart deleted file mode 100644 index 3d24db4..0000000 --- a/lib/config/firebase_options.dart +++ /dev/null @@ -1,65 +0,0 @@ -// File generated by FlutterFire CLI. -// ignore_for_file: type=lint -import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; -import 'package:flutter/foundation.dart' - show defaultTargetPlatform, kIsWeb, TargetPlatform; - -/// Default [FirebaseOptions] for use with your Firebase apps. -/// -/// Example: -/// ```dart -/// import 'firebase_options.dart'; -/// // ... -/// await Firebase.initializeApp( -/// options: DefaultFirebaseOptions.currentPlatform, -/// ); -/// ``` -class DefaultFirebaseOptions { - static FirebaseOptions get currentPlatform { - if (kIsWeb) { - return web; - } - switch (defaultTargetPlatform) { - case TargetPlatform.android: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for android - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - case TargetPlatform.iOS: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for ios - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - case TargetPlatform.macOS: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for macos - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - case TargetPlatform.windows: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for windows - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - case TargetPlatform.linux: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for linux - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - default: - throw UnsupportedError( - 'DefaultFirebaseOptions are not supported for this platform.', - ); - } - } - - static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyDw7jjs3fAbi6pxiOO4_omWefLTAjf72lw', - appId: '1:638064491024:web:f32d36e7170d5a39e9a895', - messagingSenderId: '638064491024', - projectId: 'hackncsu-today', - authDomain: 'hackncsu-today.firebaseapp.com', - storageBucket: 'hackncsu-today.firebasestorage.app', - measurementId: 'G-MMCWYB3KX0', - ); - -} \ No newline at end of file diff --git a/lib/config/router.dart b/lib/config/router.dart deleted file mode 100644 index 40e43c0..0000000 --- a/lib/config/router.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/screens/home/home.dart'; -import 'package:hackncsu_today/screens/login/login.dart'; -import 'package:hackncsu_today/screens/not_found/not_found.dart'; - -GoRouter router = GoRouter( - initialLocation: '/', - routes: [ - GoRoute(path: '/login', builder: (context, state) => const LoginScreen()), - GoRoute(path: '/', builder: (context, state) => const HomeScreen()), - ], - errorBuilder: (context, state) => NotFoundScreen(), -); diff --git a/lib/exception.dart b/lib/exception.dart deleted file mode 100644 index 7ee1434..0000000 --- a/lib/exception.dart +++ /dev/null @@ -1,10 +0,0 @@ -abstract class AppException implements Exception { - final String message; - - const AppException(this.message); - - @override - String toString() { - return message; - } -} \ No newline at end of file diff --git a/lib/features/authenticator/authenticator.dart b/lib/features/authenticator/authenticator.dart deleted file mode 100644 index 07e3d3c..0000000 --- a/lib/features/authenticator/authenticator.dart +++ /dev/null @@ -1,187 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:hackncsu_today/features/streams/hack_user_stream.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:hackncsu_today/services/firebase/auth_service.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; -import 'package:hackncsu_today/services/oauth_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'authenticator.g.dart'; - -@Riverpod(keepAlive: true) -class Authenticator extends _$Authenticator { - ProviderSubscription>? _userListenerSubscription; - - @override - AuthenticatorState build() { - // try to log in automatically in the background - _autoLogin(); - return AutoAuthenticating(); - } - - Future _autoLogin() async { - final firebaseAuth = ref.read(firebaseAuthServiceProvider); - final firebaseFirestore = ref.read(firebaseFirestoreServiceProvider); - - try { - // if firebase auth isn't null, we assume the user is already logged in (get user data from Firestore) - // if firebase auth is null, they must log in again - - HackUser? existingUser; - // this is ugly but it basically checks if the user is logged in with Firebase Auth - // and if so, fetches their user data from Firestore. if it exists, we assume they are logged in - // otherwise, we try the else if block. - - if (firebaseAuth.user != null && - (existingUser = (await firebaseFirestore.fetchUser( - firebaseAuth.user!.uid, - ))) != - null) { - if (kDebugMode) print('Auto-login successful with Firebase Auth.'); - - state = Authenticated(user: existingUser!); - _listenForUserUpdates(existingUser); - - return; - } else { - if (kDebugMode) { - print('Auto-login: Manual log in required.'); - } - } - } catch (e) { - // any error during auto-login - if (kDebugMode) print('Auto-login failed: $e'); - } - - await Future.delayed( - const Duration(seconds: 1), - ); // wait a bit because idk it doesn't work without it - // TODO: fix fragility - - state = Unauthenticated(); - } - - /// Listens to the user stream and updates state whenever user data changes - /// force logs out if user data disappears - void _listenForUserUpdates(HackUser user) { - _userListenerSubscription?.close(); - - if (kDebugMode) print('Starting auto-update for user data...'); - _userListenerSubscription = ref.listen(hackUserStreamProvider(user.id), ( - previous, - next, - ) { - next.when( - data: (userData) { - if (state is Authenticated && - previous != next && - (previous?.hasValue ?? false)) { - if (userData != null) { - if (kDebugMode) { - print('User data auto-updating...'); - } - state = Authenticated(user: userData); - } else { - if (kDebugMode) { - print('User data is null in auto update. Forcing logout...'); - } - logout(); - } - } - }, - loading: () {}, - error: (error, stack) { - state = AuthenticationError(error: error); - if (kDebugMode) print('Error during user data auto update: $error'); - }, - ); - }); - } - - Future login() async { - state = Authenticating( - message: 'Please continue logging into Discord in the other window.', - ); - - final oauthService = ref.read(oauthServiceProvider); - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - final authService = ref.read(firebaseAuthServiceProvider); - - try { - final response = await oauthService.authenticate(); - - state = Authenticating( - message: 'We are now logging you in. Please wait a moment.', - ); - - await authService.login(response); - final hackUser = await firestoreService.createUser(response); - - state = Authenticated(user: hackUser); - _listenForUserUpdates(hackUser); - } on AppException catch (e) { - state = AuthenticationError(error: e); - } catch (e) { - state = AuthenticationError(error: e); - } - } - - Future logout() async { - final authService = ref.read(firebaseAuthServiceProvider); - - _userListenerSubscription?.close(); - _userListenerSubscription = null; - await authService.logout(); - state = Unauthenticated(); - if (kDebugMode) print('Logout successful.'); - } - - /// Switches the user type for debugging purposes. - Future debugSetUserType(String type) async { - if (kDebugMode) { - _userListenerSubscription?.close(); - - final firestore = ref.read(firebaseFirestoreServiceProvider); - final auth = ref.read(firebaseAuthServiceProvider); - - final userId = auth.user!.uid; - - await firestore.debugSetUserType(userId, type).catchError((error) { - state = AuthenticationError(error: error); - if (kDebugMode) print('Failed to switch view: $error'); - }); - - final user = (await firestore.fetchUser(userId))!; - - state = Authenticated(user: user); - - _listenForUserUpdates(user); - } - } -} - -sealed class AuthenticatorState {} - -class Unauthenticated extends AuthenticatorState {} - -class Authenticating extends AuthenticatorState { - final String message; - - Authenticating({this.message = 'Authentication is in progress.'}); -} - -class AutoAuthenticating extends AuthenticatorState {} - -class AuthenticationError extends AuthenticatorState { - final Object error; - - AuthenticationError({required this.error}); -} - -class Authenticated extends AuthenticatorState { - final HackUser user; - - Authenticated({required this.user}); -} diff --git a/lib/features/streams/event_data_stream.dart b/lib/features/streams/event_data_stream.dart deleted file mode 100644 index 10c7edc..0000000 --- a/lib/features/streams/event_data_stream.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'event_data_stream.g.dart'; - -@riverpod -Stream eventDataStream(Ref ref) { - final firestoreService = ref.watch(firebaseFirestoreServiceProvider); - return firestoreService.streamEventData(); -} - - diff --git a/lib/features/streams/event_state_stream.dart b/lib/features/streams/event_state_stream.dart deleted file mode 100644 index 0f0c037..0000000 --- a/lib/features/streams/event_state_stream.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/models/event/event_state.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'event_state_stream.g.dart'; - -@riverpod -Stream eventStateStream(Ref ref) { - final firestoreService = ref.watch(firebaseFirestoreServiceProvider); - return firestoreService.streamEventState(); -} - -Stream _countdownStream(DateTime to) async* { - yield to.difference(DateTime.now()).isNegative - ? Duration.zero - : to.difference(DateTime.now()); - - final ticker = Stream.periodic(const Duration(seconds: 1)); - - await for (final _ in ticker) { - final now = DateTime.now(); - final difference = to.difference(now); - - if (difference.isNegative) { - yield Duration.zero; - break; - } else { - yield difference; - } - } -} - -@riverpod -Stream inProgressCountdownStream(Ref ref) async* { - final eventState = await ref.watch(eventStateStreamProvider.future); - - if (eventState is InProgressEventState) { - yield* _countdownStream(eventState.endTime); - } else { - yield null; - } -} diff --git a/lib/features/streams/hack_user_stream.dart b/lib/features/streams/hack_user_stream.dart deleted file mode 100644 index 2d16a6a..0000000 --- a/lib/features/streams/hack_user_stream.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'hack_user_stream.g.dart'; - -@riverpod -Stream hackUserStream(Ref ref, String userId) { - final firestoreService = ref.watch(firebaseFirestoreServiceProvider); - return firestoreService.streamUser(userId); -} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart deleted file mode 100644 index 8f4e84d..0000000 --- a/lib/main.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/config/constants.dart'; -import 'package:hackncsu_today/config/router.dart'; -import 'package:hackncsu_today/config/firebase_options.dart'; -import 'package:responsive_framework/responsive_framework.dart'; // Update import path -import 'package:hive_ce_flutter/hive_flutter.dart'; - -void main() async { - await Hive.initFlutter(); - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - - if (kDebugMode && kFirebaseUseEmulator) { - print('Using Firebase Emulator'); - FirebaseFirestore.instance.useFirestoreEmulator('localhost', 5500); - FirebaseAuth.instance.useAuthEmulator('localhost', 9099); - FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001); - } - - runApp(const ProviderScope(child: MyApp())); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp.router( - routerConfig: router, - title: 'Flutter Demo', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed( - seedColor: const Color.fromARGB(255, 189, 18, 18), - brightness: Brightness.dark, - ), - ), - debugShowCheckedModeBanner: false, - builder: - (context, child) => ResponsiveBreakpoints.builder( - child: child!, - breakpoints: [ - const Breakpoint(start: 0, end: 700, name: MOBILE), - const Breakpoint(start: 701, end: double.infinity, name: DESKTOP), - ], - ), - ); - } -} diff --git a/lib/models/event/event_data.dart b/lib/models/event/event_data.dart deleted file mode 100644 index 81a0b97..0000000 --- a/lib/models/event/event_data.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'event_data.freezed.dart'; -part 'event_data.g.dart'; - -/// Represents event data that is unrelated to a specific event state -@freezed -sealed class EventData with _$EventData { - const EventData._(); - - const factory EventData({ - /// Tracks - required List tracks, - - /// Loosely related resources (e.g. hackathon website, centennial map...) - required List externalResources, - - /// Strongly related resources (e.g. schedule, catering menu, slides, Devpost, Discord) - required List internalResources, - }) = _EventData; - - factory EventData.fromJson(Map json) => - _$EventDataFromJson(json); -} - -/// Reflects how eventData holds both external and internal resources -enum ResourceSource { external, internal } - -/// Represents a resource that can be a link or an internal, hardcoded page -/// The 'hidden' property indicates whether the resource should be hidden from the UI -/// This allows us to manually show and hide resources without having to remove them from the database -@Freezed(unionKey: 'type') -sealed class Resource with _$Resource { - const Resource._(); - - /// e.g. a link to the website, Discord server, etc. - @FreezedUnionValue('link') - const factory Resource.link( - String name, - String url, { - @Default(false) bool hidden, - }) = LinkResource; - - /// hardcoded resources like a schedule page, dialog with catering menu, etc. - @FreezedUnionValue('action') - const factory Resource.action( - String name, - ActionType action, { - @Default(false) bool hidden, - }) = ActionResource; - - factory Resource.fromJson(Map json) => - _$ResourceFromJson(json); -} - -/// Represents an internal resource that can be a page or a popup. -@JsonEnum() -enum ActionType { menu } diff --git a/lib/models/event/event_state.dart b/lib/models/event/event_state.dart deleted file mode 100644 index d7a1f7b..0000000 --- a/lib/models/event/event_state.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'event_state.freezed.dart'; -part 'event_state.g.dart'; - -@Freezed(unionKey: 'type') -sealed class EventState with _$EventState { - const EventState._(); - - @FreezedUnionValue('initial') - const factory EventState.initial({String? announcement}) = InitialEventState; - - @FreezedUnionValue('standby') - const factory EventState.standby({String? announcement}) = StandbyEventState; - - @FreezedUnionValue('openingCeremony') - const factory EventState.openingCeremony({String? announcement}) = - OpeningCeremonyEventState; - - @FreezedUnionValue('inProgress') - const factory EventState.inProgress({ - required DateTime startTime, - required DateTime endTime, - String? announcement, - }) = InProgressEventState; - - @FreezedUnionValue('closingCeremony') - const factory EventState.closingCeremony({String? announcement}) = - ClosingCeremonyEventState; - - factory EventState.fromJson(Map json) => - _$EventStateFromJson(json); -} diff --git a/lib/models/extensions/duration.dart b/lib/models/extensions/duration.dart deleted file mode 100644 index ac26ffc..0000000 --- a/lib/models/extensions/duration.dart +++ /dev/null @@ -1,32 +0,0 @@ -extension DurationFormatter on Duration { - /// HH part of HH:MM:SS - String get hoursComponent => inHours.toString().padLeft(2, '0'); - /// MM part of 00:XX:SS - String get minutesComponent => (inMinutes % 60).toString().padLeft(2, '0'); - /// SS part of 00:XX:SS - String get secondsComponent => (inSeconds % 60).toString().padLeft(2, '0'); - - /// Returns a formatted string in the format HH:MM:SS - String toFormattedString() { - return '$hoursComponent:$minutesComponent:$secondsComponent'; - } - - /// Returns a formatted string in the format MM:SS - String toShortFormattedString() { - return '$minutesComponent:$secondsComponent'; - } - - /// Returns a formatted string in the format "H hours, M minutes, S seconds" - String toVerboseString() { - final hours = inHours; - final minutes = (inMinutes % 60); - final seconds = (inSeconds % 60); - - final parts = []; - if (hours > 0) parts.add('$hours hour${hours > 1 ? 's' : ''}'); - if (minutes > 0) parts.add('$minutes minute${minutes > 1 ? 's' : ''}'); - if (seconds > 0 || parts.isEmpty) parts.add('$seconds second${seconds > 1 ? 's' : ''}'); - - return parts.join(', '); - } -} \ No newline at end of file diff --git a/lib/models/hack_user.dart b/lib/models/hack_user.dart deleted file mode 100644 index 4891459..0000000 --- a/lib/models/hack_user.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'hack_user.freezed.dart'; -part 'hack_user.g.dart'; - -/// Represents a user in the HackNCSU system, which can be either an organizer or a participant. -@Freezed(unionKey: 'type') -sealed class HackUser with _$HackUser { - const HackUser._(); - - @FreezedUnionValue('organizer') - const factory HackUser.organizer({required String id}) = Organizer; - - @FreezedUnionValue('participant') - const factory HackUser.participant({ - required String id, - required String firstName, - required String lastName, - required String? phone, - required String? email, - required List dietaryRestrictions, - required String? shirtSize, - required List eventsAttended, - required bool hadFirstLunch, - required bool hadDinner, - required bool hadBreakfast, - required bool hadSecondLunch, - String? teamId - }) = Participant; - - factory HackUser.fromJson(Map json) => - _$HackUserFromJson(json); -} diff --git a/lib/models/team.dart b/lib/models/team.dart deleted file mode 100644 index fb12af0..0000000 --- a/lib/models/team.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'team.freezed.dart'; -part 'team.g.dart'; - -@freezed -sealed class Team with _$Team { - const factory Team({ - required String id, - required String name, - required List memberIds, - required String track, - @Default([]) List checklist, - String? mentor, - }) = _Team; - - factory Team.fromJson(Map json) => _$TeamFromJson(json); -} - -@freezed -sealed class ChecklistItem with _$ChecklistItem { - const factory ChecklistItem({ - required String title, - required bool isChecked, - }) = _ChecklistItem; - - factory ChecklistItem.fromJson(Map json) => - _$ChecklistItemFromJson(json); -} \ No newline at end of file diff --git a/lib/screens/home/components/logout_modal.dart b/lib/screens/home/components/logout_modal.dart deleted file mode 100644 index 28a7f8a..0000000 --- a/lib/screens/home/components/logout_modal.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/features/authenticator/authenticator.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; - -class LogoutModal extends ConsumerWidget { - const LogoutModal({super.key}); - - Widget _builder(BuildContext context, WidgetRef ref) { - return AlertDialog( - title: Text('Log out?'), - icon: Icon(Icons.logout), - content: Text( - 'Are you sure you want to log out? You will need to reconnect your Discord account to log in again.', - ), - actions: [ - TextButton(onPressed: () => context.pop(), child: Text('Cancel')), - TextButton( - onPressed: ref.read(authenticatorProvider.notifier).logout, - child: Text('Log out'), - ), - ], - ); - } - - Future _switchView(BuildContext context, WidgetRef ref) async { - context.pop(); - - final state = ref.read(authenticatorProvider); - - if (state is Authenticated) { - final user = state.user; - final auth = ref.read(authenticatorProvider.notifier); - - await auth.debugSetUserType( - user is Organizer ? 'participant' : 'organizer', - ); - } - } - - /// Debug version of the logout modal for development purposes. - Widget _debugBuilder(BuildContext context, WidgetRef ref) { - final state = ref.watch(authenticatorProvider); - - return AlertDialog( - title: Text('Debug Logout Modal'), - content: Text( - 'Perform actions for debugging purposes.\n\nCurrent User: ${state is Authenticated ? state.user : 'None'}', - ), - actions: [ - TextButton(onPressed: () => context.pop(), child: Text('Close')), - TextButton( - onPressed: ref.read(authenticatorProvider.notifier).logout, - child: Text('Log out'), - ), - Tooltip( - message: - 'Switch user type for debugging (this WILL fail if firebase is in production mode)', - child: TextButton( - onPressed: () => _switchView(context, ref), - child: Text('Switch View'), - ), - ), - ], - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - return PointerInterceptor( - child: kDebugMode ? _debugBuilder(context, ref) : _builder(context, ref), - ); - } -} diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart deleted file mode 100644 index 656d77c..0000000 --- a/lib/screens/home/home.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'dart:async'; - -import 'package:after_layout/after_layout.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/features/authenticator/authenticator.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:hackncsu_today/screens/home/components/logout_modal.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/organizer_view.dart'; -import 'package:hackncsu_today/screens/home/views/participant/participant_view.dart'; -import 'package:responsive_framework/responsive_framework.dart'; - -class HomeScreen extends ConsumerStatefulWidget { - const HomeScreen({super.key}); - - @override - ConsumerState createState() => _HomeScreenState(); -} - -class _HomeScreenState extends ConsumerState - with AfterLayoutMixin { - @override - FutureOr afterFirstLayout(BuildContext context) { - // this is if the user tries to access the page directly without logging in - - final state = ref.read(authenticatorProvider); - - if (state is Unauthenticated) { - if (context.mounted) { - context.replace('/login'); - } - } - } - - Widget _authenticatedBuilder(BuildContext context, Authenticated state) { - final hackUser = state.user; - - switch (hackUser) { - case Organizer(): - return OrganizerView(); - case Participant(): - return ParticipantView(hackUser); - } - } - - Widget _notAuthenticatedBuilder( - BuildContext context, - AuthenticatorState state, - ) { - return Center(child: CircularProgressIndicator()); - } - - AppBar _appBarBuilder( - BuildContext context, - Authenticated state, - bool isDesktop, - ) { - return AppBar( - title: Text(state.user is Participant ? 'Dashboard' : 'Scanner'), - actions: [ - if (isDesktop) ...[ - Text('Logged in as ${state.user}'), - SizedBox(width: 10), - ], - isDesktop - ? FilledButton.tonalIcon( - onPressed: - () => showDialog( - context: context, - builder: (_) => LogoutModal(), - ), - icon: const Icon(Icons.logout), - label: Text('Log out'), - ) - : IconButton.filledTonal( - onPressed: - () => showDialog( - context: context, - builder: (_) => LogoutModal(), - ), - icon: Icon(Icons.logout), - tooltip: 'Log out', - ), - SizedBox(width: 10), - ], - ); - } - - @override - Widget build(BuildContext context) { - // authenticator will try to auto login once initialized - // let's listen and redirect if it fails (or if the user logs out) - ref.listen(authenticatorProvider, (previous, next) { - print('Authenticator state changed: $next'); - if (next is Unauthenticated) { - if (context.mounted) { - context.replace('/login'); - } - } - }); - - final state = ref.watch(authenticatorProvider); - final isDesktop = ResponsiveBreakpoints.of(context).isDesktop; - - return Scaffold( - // appBar: - // state is Authenticated - // ? _appBarBuilder(context, state, isDesktop) - // : null, - body: - state is Authenticated - ? _authenticatedBuilder(context, state) - : _notAuthenticatedBuilder(context, state), - floatingActionButton: - state is Authenticated - ? FloatingActionButton( - onPressed: - () => showDialog( - context: context, - builder: (_) => LogoutModal(), - ), - tooltip: 'Log out', - child: Icon(Icons.logout), - ) - : null, - ); - } -} diff --git a/lib/screens/home/views/organizer/components/edit_resources_modal.dart b/lib/screens/home/views/organizer/components/edit_resources_modal.dart deleted file mode 100644 index ae76522..0000000 --- a/lib/screens/home/views/organizer/components/edit_resources_modal.dart +++ /dev/null @@ -1,290 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/features/streams/event_data_stream.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; - -class EditResourcesModal extends ConsumerStatefulWidget { - final ResourceSource source; - - const EditResourcesModal({super.key, required this.source}); - - @override - ConsumerState createState() => _EditResourcesModalState(); -} - -class _EditResourcesModalState extends ConsumerState { - bool _isSaving = false; - - late List _resources; - final _formKey = GlobalKey(); - - // To store form field values - final List _nameControllers = []; - final List _valueControllers = []; - final List _actionTypes = []; - - @override - void initState() { - super.initState(); - - final eventData = ref.read(eventDataStreamProvider).asData?.value; - - _resources = - (widget.source == ResourceSource.internal - ? eventData?.internalResources ?? [] - : eventData?.externalResources ?? []) - .toList(); - - for (final resource in _resources) { - _nameControllers.add(TextEditingController(text: resource.name)); - - switch (resource) { - case LinkResource(): - _valueControllers.add(TextEditingController(text: resource.url)); - _actionTypes.add(null); // Placeholder for action type - case ActionResource(): - _valueControllers.add(TextEditingController()); // Placeholder - _actionTypes.add(resource.action); - } - } - } - - @override - void dispose() { - for (var controller in _nameControllers) { - controller.dispose(); - } - for (var controller in _valueControllers) { - controller.dispose(); - } - super.dispose(); - } - - void _onSave() async { - if (_formKey.currentState!.validate()) { - setState(() { - _isSaving = true; - }); - - final newResources = []; - - for (int i = 0; i < _resources.length; i++) { - final originalResource = _resources[i]; - final name = _nameControllers[i].text; - - switch (originalResource) { - case LinkResource(:final hidden): - final url = _valueControllers[i].text; - newResources.add(Resource.link(name, url, hidden: hidden)); - case ActionResource(:final hidden): - final action = _actionTypes[i]!; - newResources.add(Resource.action(name, action, hidden: hidden)); - } - } - - final eventData = ref.read(eventDataStreamProvider).asData?.value; - - final newEventData = switch (widget.source) { - ResourceSource.internal => eventData?.copyWith( - internalResources: newResources, - ), - ResourceSource.external => eventData?.copyWith( - externalResources: newResources, - ), - }; - - if (newEventData == null) { - setState(() { - _isSaving = false; - }); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Failed to save changes.'), - behavior: SnackBarBehavior.floating, - ), - ); - return; - } - - await ref - .read(firebaseFirestoreServiceProvider) - .updateEventData(newEventData); - - if (mounted) { - context.pop(); - } - } - } - - void _removeResource(int index) { - setState(() { - _resources.removeAt(index); - _nameControllers.removeAt(index).dispose(); - _valueControllers.removeAt(index).dispose(); - _actionTypes.removeAt(index); - }); - } - - void _toggleHidden(int index) { - setState(() { - final resource = _resources[index]; - _resources[index] = switch (resource) { - LinkResource() => resource.copyWith(hidden: !resource.hidden), - ActionResource() => resource.copyWith(hidden: !resource.hidden), - }; - }); - } - - void _addLinkResource() { - setState(() { - _resources.add(const Resource.link('', '')); - _nameControllers.add(TextEditingController()); - _valueControllers.add(TextEditingController()); - _actionTypes.add(null); - }); - } - - void _addActionResource() { - setState(() { - final defaultAction = ActionType.values.first; - _resources.add(Resource.action('', defaultAction)); - _nameControllers.add(TextEditingController()); - _valueControllers.add(TextEditingController()); // Placeholder - _actionTypes.add(defaultAction); - }); - } - - Widget _linkFieldBuilder(BuildContext context, int index) { - final resource = _resources[index]; - return Row( - children: [ - Expanded( - child: TextFormField( - controller: _nameControllers[index], - decoration: const InputDecoration(labelText: 'Name'), - validator: - (value) => - value?.isEmpty ?? true ? 'Name cannot be empty' : null, - ), - ), - const SizedBox(width: 8), - Expanded( - child: TextFormField( - controller: _valueControllers[index], - decoration: const InputDecoration(labelText: 'URL'), - validator: - (value) => - value?.isEmpty ?? true ? 'URL cannot be empty' : null, - ), - ), - IconButton( - icon: Icon(resource.hidden ? Icons.visibility_off : Icons.visibility), - onPressed: () => _toggleHidden(index), - tooltip: 'Hide for Participants: ${resource.hidden}', - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () => _removeResource(index), - tooltip: 'Remove Link Resource', - ), - ], - ); - } - - Widget _actionFieldBuilder(BuildContext context, int index) { - final resource = _resources[index]; - return Row( - children: [ - Expanded( - child: TextFormField( - controller: _nameControllers[index], - decoration: const InputDecoration(labelText: 'Name'), - validator: - (value) => - value?.isEmpty ?? true ? 'Name cannot be empty' : null, - ), - ), - const SizedBox(width: 8), - Expanded( - child: DropdownButtonFormField( - value: _actionTypes[index], - items: - ActionType.values - .map( - (type) => - DropdownMenuItem(value: type, child: Text(type.name)), - ) - .toList(), - onChanged: (value) { - setState(() { - _actionTypes[index] = value; - }); - }, - decoration: const InputDecoration(labelText: 'Action'), - ), - ), - IconButton( - icon: Icon(resource.hidden ? Icons.visibility_off : Icons.visibility), - onPressed: () => _toggleHidden(index), - tooltip: 'Hide for Participants: ${resource.hidden}', - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () => _removeResource(index), - tooltip: 'Remove Action Resource', - ), - ], - ); - } - - @override - Widget build(BuildContext context) { - return AlertDialog( - icon: const Icon(Icons.build), - title: Text('Edit ${widget.source.name} Resources'), - content: Form( - key: _formKey, - child: SingleChildScrollView( - child: SizedBox( - width: double.maxFinite, - child: ListView.builder( - shrinkWrap: true, - itemCount: _resources.length, - itemBuilder: (context, index) { - final resource = _resources[index]; - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: switch (resource) { - LinkResource() => _linkFieldBuilder(context, index), - ActionResource() => _actionFieldBuilder(context, index), - }, - ); - }, - ), - ), - ), - ), - actions: [ - TextButton( - onPressed: _isSaving ? null : () => context.pop(), - child: const Text('Cancel'), - ), - TextButton( - onPressed: _addLinkResource, - child: const Text('Add Link Resource'), - ), - TextButton( - onPressed: _addActionResource, - child: const Text('Add Action Resource'), - ), - ElevatedButton( - onPressed: _isSaving ? null : _onSave, - child: const Text('Save'), - ), - ], - ); - } -} diff --git a/lib/screens/home/views/organizer/components/editable_overlay.dart b/lib/screens/home/views/organizer/components/editable_overlay.dart deleted file mode 100644 index b025171..0000000 --- a/lib/screens/home/views/organizer/components/editable_overlay.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class EditableOverlay extends StatelessWidget { - final Widget child; - final void Function() onEdit; - - const EditableOverlay({super.key, required this.child, required this.onEdit}); - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - child, - Align( - alignment: Alignment.topRight, - child: Tooltip( - message: 'Edit data', - child: IconButton.filled( - onPressed: onEdit, - icon: const Icon(Icons.edit), - ), - ), - ), - ], - ); - } -} diff --git a/lib/screens/home/views/organizer/components/execute_modal.dart b/lib/screens/home/views/organizer/components/execute_modal.dart deleted file mode 100644 index eb69292..0000000 --- a/lib/screens/home/views/organizer/components/execute_modal.dart +++ /dev/null @@ -1,209 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/models/task.dart'; - -class ExecuteModal extends ConsumerStatefulWidget { - final Task task; - - const ExecuteModal(this.task, {super.key}); - - @override - ConsumerState createState() => _ExecuteModalState(); -} - -class _ExecuteModalState extends ConsumerState { - bool _isExecuting = false; - late List _parameters; - - @override - void initState() { - super.initState(); - _parameters = widget.task.parameters?.call(ref) ?? []; - } - - Future _executeTask() async { - setState(() { - _isExecuting = true; - }); - - try { - await widget.task.onExecute(ref, _parameters); - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: const Text('Task executed successfully!'), - behavior: SnackBarBehavior.floating, - ), - ); - context.pop(); - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(e.toString()), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating, - duration: const Duration(seconds: 10), - ), - ); - context.pop(); - } - } - } - - List _buildParameterFields() { - return _parameters.map((p) { - final index = _parameters.indexOf(p); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - - child: switch (p) { - StringTaskParameter() => TextFormField( - initialValue: p.value, - decoration: InputDecoration( - labelText: p.description, - border: const OutlineInputBorder(), - ), - onChanged: (newValue) { - setState(() { - _parameters[index] = TaskParameter.string( - p.description, - value: newValue, - ); - }); - }, - ), - IntegerTaskParameter() => TextFormField( - initialValue: p.value.toString(), - decoration: InputDecoration( - labelText: p.description, - border: const OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - onChanged: (newValue) { - setState(() { - _parameters[index] = TaskParameter.integer( - p.description, - value: int.tryParse(newValue) ?? p.value, - ); - }); - }, - ), - BooleanTaskParameter() => SwitchListTile( - title: Text(p.description), - value: p.value, - onChanged: (newValue) { - setState(() { - _parameters[index] = TaskParameter.boolean( - p.description, - value: newValue, - ); - }); - }, - ), - DoubleTaskParameter() => TextFormField( - initialValue: p.value.toString(), - decoration: InputDecoration( - labelText: p.description, - border: const OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*')), - ], - onChanged: (newValue) { - setState(() { - _parameters[index] = TaskParameter.doubleValue( - p.description, - value: double.tryParse(newValue) ?? p.value, - ); - }); - }, - ), - DateTimeTaskParameter() => ListTile( - title: Text(p.description), - subtitle: Text(p.value.toString()), - trailing: const Icon(Icons.calendar_today), - onTap: () async { - final newDate = await showDatePicker( - context: context, - initialDate: p.value, - firstDate: DateTime(2000), - lastDate: DateTime(2100), - ); - if (newDate == null) return; - - if (!mounted) return; - - final newTime = await showTimePicker( - context: context, - initialTime: TimeOfDay.fromDateTime(p.value), - initialEntryMode: TimePickerEntryMode.input, - ); - if (newTime == null) return; - - setState(() { - final newDateTime = DateTime( - newDate.year, - newDate.month, - newDate.day, - newTime.hour, - newTime.minute, - ); - _parameters[index] = TaskParameter.dateTime( - p.description, - newDateTime, - ); - }); - }, - ), - }, - ); - }).toList(); - } - - @override - Widget build(BuildContext context) { - return AlertDialog( - icon: const Icon(Icons.build), - title: Text('Execute Task: ${widget.task.title}'), - content: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(widget.task.content), - if (widget.task.parameters != null) ...[ - const SizedBox(height: 16), - const Divider(), - const SizedBox(height: 16), - ..._buildParameterFields(), - ], - ], - ), - ), - actions: [ - TextButton(onPressed: () => context.pop(), child: const Text('Cancel')), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.primary, - foregroundColor: Theme.of(context).colorScheme.onPrimary, - ), - onPressed: _isExecuting ? null : _executeTask, - child: - _isExecuting - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(), - ) - : const Text('Execute'), - ), - ], - ); - } -} diff --git a/lib/screens/home/views/organizer/features/page_controller.dart b/lib/screens/home/views/organizer/features/page_controller.dart deleted file mode 100644 index f18f038..0000000 --- a/lib/screens/home/views/organizer/features/page_controller.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'page_controller.g.dart'; - -enum OrganizerPage { - dashboard(Icons.dashboard, 'Dashboard'), - tasks(Icons.build_circle, 'Tasks'), - teams(Icons.group, 'Teams'); - - final IconData icon; - final String title; - - const OrganizerPage(this.icon, this.title); -} - -@riverpod -class OrganizerPageController extends _$OrganizerPageController { - @override - OrganizerPage build() { - return OrganizerPage.dashboard; - } - - void setPage(OrganizerPage page) { - state = page; - } -} diff --git a/lib/screens/home/views/organizer/models/task.dart b/lib/screens/home/views/organizer/models/task.dart deleted file mode 100644 index e8feadd..0000000 --- a/lib/screens/home/views/organizer/models/task.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'task.freezed.dart'; - -@freezed -sealed class Task with _$Task { - const Task._(); - - const factory Task({ - required String title, - required String content, - List Function(WidgetRef)? parameters, - required Future Function(WidgetRef, List) onExecute, - }) = _Task; -} - -@freezed -sealed class TaskParameter with _$TaskParameter { - const TaskParameter._(); - const factory TaskParameter.string( - String description, { - @Default('') String value, - }) = StringTaskParameter; - - const factory TaskParameter.integer( - String description, { - @Default(0) int value, - }) = IntegerTaskParameter; - - const factory TaskParameter.boolean( - String description, { - @Default(false) bool value, - }) = BooleanTaskParameter; - - const factory TaskParameter.doubleValue( - String description, { - @Default(0.0) double value, - }) = DoubleTaskParameter; - - const factory TaskParameter.dateTime(String description, DateTime value) = - DateTimeTaskParameter; -} diff --git a/lib/screens/home/views/organizer/organizer_view.dart b/lib/screens/home/views/organizer/organizer_view.dart deleted file mode 100644 index a401674..0000000 --- a/lib/screens/home/views/organizer/organizer_view.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/features/page_controller.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/components/edit_resources_modal.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/components/editable_overlay.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/pages/tasks.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/resource_card.dart'; - -class OrganizerView extends ConsumerWidget { - const OrganizerView({super.key}); - - List _cardsBuilder(BuildContext context) => [ - const SizedBox(height: 200, child: LiveCard()), - SizedBox( - height: 200, - child: EditableOverlay( - onEdit: () => _showEditResourcesModal(context, ResourceSource.internal), - child: ResourceCard(ResourceSource.internal, showHidden: true), - ), - ), - SizedBox( - height: 200, - child: EditableOverlay( - onEdit: () => _showEditResourcesModal(context, ResourceSource.external), - child: ResourceCard(ResourceSource.external, showHidden: true), - ), - ), - ]; - - void _showEditResourcesModal(BuildContext context, ResourceSource source) { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) { - return EditResourcesModal(source: source); - }, - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final state = ref.watch(organizerPageControllerProvider); - - return Row( - children: [ - NavigationRail( - labelType: NavigationRailLabelType.all, - selectedIndex: state.index, - onDestinationSelected: (index) { - ref - .read(organizerPageControllerProvider.notifier) - .setPage(OrganizerPage.values[index]); - }, - backgroundColor: Theme.of(context).colorScheme.surfaceContainer, - destinations: - OrganizerPage.values.map((page) { - return NavigationRailDestination( - icon: Icon(page.icon), - label: Text(page.title), - ); - }).toList(), - ), - Expanded( - flex: 3, - child: switch (state) { - OrganizerPage.dashboard => Center(child: Text('Dashboard')), - OrganizerPage.tasks => TasksPage(), - OrganizerPage.teams => Center(child: Text('Teams')), - }, - ), - Expanded(child: ListView(children: _cardsBuilder(context))), - ], - ); - } -} diff --git a/lib/screens/home/views/organizer/pages/tasks.dart b/lib/screens/home/views/organizer/pages/tasks.dart deleted file mode 100644 index 6f68d9e..0000000 --- a/lib/screens/home/views/organizer/pages/tasks.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/components/execute_modal.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/models/task.dart'; -import 'package:hackncsu_today/services/organizer/task_service.dart'; - -class TasksPage extends ConsumerWidget { - const TasksPage({super.key}); - - Widget _taskWrapBuilder(BuildContext context, List tasks) { - return Wrap( - spacing: 16, - runSpacing: 16, - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - children: - tasks.map((task) { - return ElevatedButton( - onPressed: () => _showTaskExecuteModal(context, task), - child: Text(task.title), - ); - }).toList(), - ); - } - - void _showTaskExecuteModal(BuildContext context, Task task) { - showDialog( - context: context, - builder: (BuildContext context) { - return ExecuteModal(task); - }, - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final taskService = ref.watch(taskServiceProvider); - - return SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Quick Tasks', style: Theme.of(context).textTheme.titleLarge), - Text( - 'These tasks are quick actions to manage the event. Click on one to see its description.', - textAlign: TextAlign.center, - ), - const SizedBox(height: 8), - _taskWrapBuilder(context, taskService.quickTasks), - const SizedBox(height: 16), - Divider(), - const SizedBox(height: 16), - Text( - 'Event State Management', - style: Theme.of(context).textTheme.titleLarge, - ), - Text( - 'Use the tasks below to manage the event state. You may need to provide parameters for some tasks.', - textAlign: TextAlign.center, - ), - const SizedBox(height: 8), - _taskWrapBuilder(context, taskService.eventStateManagementTasks), - ], - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/basic_card.dart b/lib/screens/home/views/participant/components/cards/basic_card.dart deleted file mode 100644 index e1bcd43..0000000 --- a/lib/screens/home/views/participant/components/cards/basic_card.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/material.dart'; - -class BasicCard extends StatelessWidget { - final String? title; - final String? helpText; - final Widget? child; - final EdgeInsetsGeometry? padding; - final EdgeInsetsGeometry? margin; - final Color? color; - - const BasicCard({ - super.key, - this.title, - this.helpText, - this.child, - this.padding, - this.margin, - this.color, - }); - - @override - Widget build(BuildContext context) { - return Card.filled( - margin: margin, - color: color, - child: Padding( - padding: padding ?? const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (title != null) - Text( - title!, - style: Theme.of(context).textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - ), - ), - if (helpText != null) - Tooltip( - message: helpText, - child: Icon( - Icons.help, - size: 15, - color: Theme.of( - context, - ).colorScheme.onSurface.withValues(alpha: 0.6), - ), - ), - ], - ), - if (title != null || helpText != null) const SizedBox(height: 8.0), - Expanded(child: child ?? const SizedBox.shrink()), - ], - ), - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/checklist_card.dart b/lib/screens/home/views/participant/components/cards/checklist_card.dart deleted file mode 100644 index 14b412a..0000000 --- a/lib/screens/home/views/participant/components/cards/checklist_card.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/basic_card.dart'; - -class ChecklistCard extends StatelessWidget { - const ChecklistCard({super.key}); - - @override - Widget build(BuildContext context) { - return BasicCard( - title: 'CHECKLIST', - helpText: - 'Checklist to keep track of important tasks during the event, and even add your own tasks.\nChanges are synced with your team members.', - child: Stack( - children: [ - ListView( - children: [ - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Check in at the registration desk'), - ), - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Join the HackNC State Discord server'), - ), - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Join your team channel on Discord'), - ), - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Attend the opening ceremony'), - ), - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Attend the workshops'), - ), - CheckboxListTile( - value: false, - onChanged: (_) {}, - title: Text('Submit your project on Devpost'), - ), - SizedBox(height: 32), // Add some space at the bottom - ], - ), - Align( - alignment: Alignment.bottomRight, - child: IconButton.filled( - onPressed: () {}, - icon: const Icon(Icons.add), - ), - ), - ], - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card.dart b/lib/screens/home/views/participant/components/cards/live_card.dart deleted file mode 100644 index 3ae00a5..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/features/streams/event_state_stream.dart'; -import 'package:hackncsu_today/models/event/event_state.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/basic_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card_views/initial_view.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card_views/standby_view.dart'; - -class LiveCard extends ConsumerWidget { - const LiveCard({super.key}); - - Widget _errorPlaceholder(String error, WidgetRef ref) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Error loading state: $error'), - const SizedBox(height: 16), - TextButton( - onPressed: () { - ref.invalidate(eventStateStreamProvider); - }, - child: const Text('Retry'), - ), - ], - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final eventState = ref.watch(eventStateStreamProvider); - - return BasicCard( - title: 'LIVE', - helpText: - "Critical information such as the timer and other updates\nEnable desktop notifications to stay up to date even when you're in another tab.", - color: Theme.of(context).colorScheme.primaryContainer, - child: Center( - child: eventState.when( - data: (state) { - if (state == null) { - return Text("We're still setting things up, please stand by!"); - } - - return switch (state) { - InitialEventState() => LiveCardInitialView(), - StandbyEventState() => LiveCardStandbyView(), - InProgressEventState() => LiveCardInProgressView(state), - OpeningCeremonyEventState() => LiveCardOpeningCeremonyView(), - ClosingCeremonyEventState() => LiveCardClosingCeremonyView(), - }; - }, - loading: () => const Center(child: CircularProgressIndicator()), - error: (error, stack) => _errorPlaceholder(error.toString(), ref), - ), - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart deleted file mode 100644 index 9bf3b75..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card_views/closing_ceremony_view.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class LiveCardClosingCeremonyView extends StatelessWidget { - const LiveCardClosingCeremonyView({super.key}); - - @override - Widget build(BuildContext context) { - return const Text('Closing ceremony in progress...'); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart deleted file mode 100644 index 8d8da7a..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card_views/in_progress_view.dart +++ /dev/null @@ -1,214 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/features/streams/event_state_stream.dart'; -import 'package:hackncsu_today/models/event/event_state.dart'; -import 'package:hackncsu_today/models/extensions/duration.dart'; - -class LiveCardInProgressView extends ConsumerStatefulWidget { - final InProgressEventState state; - - const LiveCardInProgressView(this.state, {super.key}); - - @override - ConsumerState createState() => - _LiveCardInProgressViewState(); -} - -class _LiveCardInProgressViewState - extends ConsumerState { - static const Duration _firstHourEnd = Duration(hours: 23); - static const Duration _halfwayPointStart = Duration(hours: 12); - static const Duration _halfwayPointEnd = Duration(hours: 10); - static const Duration _finalStretchStart = Duration(hours: 1); - static const Duration _lastCallStart = Duration(minutes: 30); - - static const List _genericFlavorTitles = [ - 'Hack_NCState is in progress!', - ]; - static const List _genericFlavorText = [ - 'Keep coding!', - 'Lock in.', - 'I\'ll think of something later.', - ]; - - static const List _firstHourFlavorTitles = [ - 'Hack_NCState has begun!', - ]; - static const List _firstHourFlavorText = [ - 'Can your ideas change the world?', - 'Let the coding marathon commence!', - "Let's build something amazing together!", - 'Unleash your creativity and innovation!', - 'The future is yours to create!', - 'Start brainstorming and coding your ideas!', - ]; - - static const List _halfwayPointFlavorTitles = [ - 'Halfway done!', - 'You\'re halfway through!', - ]; - static const List _halfwayPointFlavorText = [ - 'Keep at it!', - 'Keep pushing forward!', - "Let's finish strong!", - 'Keep the momentum going!', - 'Let\'s keep the energy up!', - 'Keep the ideas flowing!', - ]; - - static const List _finalStretchFlavorTitles = [ - 'Final stretch!', - 'Last hour!', - 'Final hour!', - ]; - static const List _finalStretchFlavorText = [ - 'Finish strong!', - 'Let\'s wrap this up!', - 'Don\'t forget to submit your project!', - 'Make sure your project is ready for submission!', - 'Double-check your project and submit it!', - 'Make sure your project is ready for the judges!', - ]; - - static const List _lastCallFlavorTitles = [ - 'Last call!', - 'Final call!', - 'Last chance!', - 'Final chance!', - ]; - static const List _lastCallFlavorText = [ - 'Make sure your project is submitted!', - 'Submit your project now!', - 'Don\'t miss your chance to submit!', - 'Ensure your project is ready for submission!', - ]; - - late Timer _timer; - int _randomSeed = DateTime.now().millisecondsSinceEpoch; - - @override - void initState() { - super.initState(); - - _timer = Timer.periodic(const Duration(minutes: 30), (timer) { - setState(() { - _randomSeed = DateTime.now().millisecondsSinceEpoch; - }); - }); - } - - @override - void dispose() { - super.dispose(); - _timer.cancel(); - } - - /// Builds the countdown view based on the current countdown duration. - Widget _randomFlavorTextBuilder(BuildContext context, Duration countdown) { - final random = Random(_randomSeed); - - if (countdown > _firstHourEnd) { - return _flavorTextBuilder( - context, - _firstHourFlavorTitles[random.nextInt(_firstHourFlavorTitles.length)], - _firstHourFlavorText[random.nextInt(_firstHourFlavorText.length)], - ); - } else if (countdown > _halfwayPointStart) { - return _flavorTextBuilder( - context, - _genericFlavorTitles[random.nextInt(_genericFlavorTitles.length)], - _genericFlavorText[random.nextInt(_genericFlavorText.length)], - ); - } else if (countdown > _halfwayPointEnd) { - return _flavorTextBuilder( - context, - _halfwayPointFlavorTitles[random.nextInt( - _halfwayPointFlavorTitles.length, - )], - _halfwayPointFlavorText[random.nextInt(_halfwayPointFlavorText.length)], - ); - } else if (countdown > _finalStretchStart) { - return _flavorTextBuilder( - context, - _genericFlavorTitles[random.nextInt(_genericFlavorTitles.length)], - _genericFlavorText[random.nextInt(_genericFlavorText.length)], - ); - } else if (countdown > _lastCallStart) { - return _flavorTextBuilder( - context, - _finalStretchFlavorTitles[random.nextInt( - _finalStretchFlavorTitles.length, - )], - _finalStretchFlavorText[random.nextInt(_finalStretchFlavorText.length)], - ); - } else { - return _flavorTextBuilder( - context, - _lastCallFlavorTitles[random.nextInt(_lastCallFlavorTitles.length)], - _lastCallFlavorText[random.nextInt(_lastCallFlavorText.length)], - ); - } - } - - Widget _flavorTextBuilder(BuildContext context, String title, String text) { - return Text('$title $text', style: Theme.of(context).textTheme.titleLarge); - } - - Widget _announcementBuilder(BuildContext context, String announcement) { - return RichText( - text: TextSpan( - children: [ - TextSpan( - text: 'Announcement: ', - style: TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: announcement), - ], - style: Theme.of(context).textTheme.titleLarge, - ), - ); - } - - Widget _countdownBuilder(BuildContext context, Duration countdown) { - final announcement = widget.state.announcement; - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - countdown.toFormattedString(), - style: Theme.of( - context, - ).textTheme.displayMedium?.copyWith(fontWeight: FontWeight.bold), - ), - announcement == null - ? _randomFlavorTextBuilder(context, countdown) - : _announcementBuilder(context, announcement), - ], - ); - } - - Widget _nullBuilder() { - return const Text('No countdown available. Is the event in progress?'); - } - - @override - Widget build(BuildContext context) { - final countdown = ref.watch(inProgressCountdownStreamProvider); - - return countdown.when( - data: (duration) { - if (duration == null) { - return _nullBuilder(); - } - - return _countdownBuilder(context, duration); - }, - loading: () => CircularProgressIndicator(), - error: (_, _) => _nullBuilder(), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart deleted file mode 100644 index 1328547..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card_views/initial_view.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class LiveCardInitialView extends StatelessWidget { - const LiveCardInitialView({super.key}); - - @override - Widget build(BuildContext context) { - return const Text('Hack_NCState is starting soon, please stand by!'); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart deleted file mode 100644 index e89ad0e..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card_views/opening_ceremony_view.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class LiveCardOpeningCeremonyView extends StatelessWidget { - const LiveCardOpeningCeremonyView({super.key}); - - @override - Widget build(BuildContext context) { - return const Text('Opening ceremony in progress...'); - } -} diff --git a/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart b/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart deleted file mode 100644 index 742abce..0000000 --- a/lib/screens/home/views/participant/components/cards/live_card_views/standby_view.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class LiveCardStandbyView extends StatelessWidget { - const LiveCardStandbyView({super.key}); - - @override - Widget build(BuildContext context) { - return const Text('Please stand by for updates.'); - } -} diff --git a/lib/screens/home/views/participant/components/cards/resource_card.dart b/lib/screens/home/views/participant/components/cards/resource_card.dart deleted file mode 100644 index a25d2e7..0000000 --- a/lib/screens/home/views/participant/components/cards/resource_card.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/features/streams/event_data_stream.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/basic_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/resource_items/internal_resource_item.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/resource_items/link_resource_item.dart'; - -class ResourceCard extends ConsumerWidget { - final bool showHidden; - final ResourceSource source; - const ResourceCard(this.source, {super.key, this.showHidden = false}); - - Widget _buildList(List resources) { - return ListView.builder( - itemCount: resources.length, - itemBuilder: (context, index) { - final resource = resources[index]; - - switch (resource) { - case LinkResource(): - return LinkResourceItem(resource); - case ActionResource(): - return InternalResourceItem(resource); - } - }, - ); - } - - Widget _emptyListPlaceholder() { - final String name; - - switch (source) { - case ResourceSource.external: - name = 'links'; - break; - case ResourceSource.internal: - name = 'resources'; - break; - } - - return Center(child: Text('No $name available at the moment.')); - } - - Widget _errorPlaceholder(String error, WidgetRef ref) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Error loading data: $error'), - const SizedBox(height: 16), - TextButton( - onPressed: () { - ref.invalidate(eventDataStreamProvider); - }, - child: const Text('Retry'), - ), - ], - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final eventData = ref.watch(eventDataStreamProvider); - - final String title; - final String helpText; - - switch (source) { - case ResourceSource.external: - title = 'LINKS'; - helpText = - 'Helpful links to external websites\nThis card is live and updates automatically if new links are added.'; - break; - case ResourceSource.internal: - title = 'RESOURCES'; - helpText = - 'Resources essential to your Hack_NCState experience\nThis card is live and updates automatically if new resources are added.'; - break; - } - - return BasicCard( - title: title, - helpText: helpText, - child: eventData.when( - data: (data) { - final List? resourceList; - - switch (source) { - case ResourceSource.external: - resourceList = data?.externalResources; - break; - case ResourceSource.internal: - resourceList = data?.internalResources; - break; - } - - final eventData = - resourceList - ?.where((resource) => showHidden || !resource.hidden) - .toList() ?? - []; - - if (eventData.isEmpty) { - return _emptyListPlaceholder(); - } - return _buildList(eventData); - }, - loading: () => const Center(child: CircularProgressIndicator()), - error: (error, stack) => _errorPlaceholder(error.toString(), ref), - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/cards/team_card.dart b/lib/screens/home/views/participant/components/cards/team_card.dart deleted file mode 100644 index 89eab17..0000000 --- a/lib/screens/home/views/participant/components/cards/team_card.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/basic_card.dart'; - -class TeamCard extends StatelessWidget { - const TeamCard({super.key}); - - @override - Widget build(BuildContext context) { - return BasicCard( - title: 'YOUR TEAM', - helpText: - 'Information about your team such as members, assigned mentor, and judging.\nUpdates will appear automatically.', - ); - } -} diff --git a/lib/screens/home/views/participant/components/discord_embed.dart b/lib/screens/home/views/participant/components/discord_embed.dart deleted file mode 100644 index 0cdcc90..0000000 --- a/lib/screens/home/views/participant/components/discord_embed.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:hackncsu_today/config/constants.dart'; -import 'package:web/web.dart' as web; - -class DiscordEmbed extends StatelessWidget { - final String serverID; - final String channelID; - - const DiscordEmbed({ - super.key, - required this.serverID, - required this.channelID, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(4), - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: - kEmbedDiscord - ? Stack( - children: [ - Positioned.fill( - child: HtmlElementView.fromTagName( - tagName: 'script', - hitTestBehavior: - PlatformViewHitTestBehavior.transparent, - onElementCreated: (element) { - final scriptElement = - element as web.HTMLScriptElement; - scriptElement.src = - 'https://cdn.jsdelivr.net/npm/@widgetbot/html-embed'; - scriptElement.async = true; - scriptElement.defer = true; - }, - ), - ), - Positioned.fill( - child: HtmlElementView.fromTagName( - tagName: 'widgetbot', - onElementCreated: (element) { - final htmlElement = element as web.HTMLElement; - htmlElement.setAttribute('server', serverID); - htmlElement.setAttribute('channel', channelID); - - htmlElement.setAttribute('height', '100%'); - htmlElement.setAttribute('width', '100%'); - }, - ), - ), - ], - ) - : Placeholder(strokeWidth: 10), - ), - ); - } -} diff --git a/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart b/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart deleted file mode 100644 index acb5861..0000000 --- a/lib/screens/home/views/participant/components/resource_items/internal_resource_item.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/resource_items/resource_item.dart'; - -class InternalResourceItem extends StatelessWidget { - final ActionResource internalResource; - - const InternalResourceItem(this.internalResource, {super.key}); - - void _openResource(BuildContext context) { - switch (internalResource.action) { - case ActionType.menu: - // TODO: Handle this case. - throw UnimplementedError(); - } - } - - @override - Widget build(BuildContext context) { - return ResourceItem(internalResource, onTap: () => _openResource(context)); - } -} diff --git a/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart b/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart deleted file mode 100644 index 98b7ec7..0000000 --- a/lib/screens/home/views/participant/components/resource_items/link_resource_item.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/resource_items/resource_item.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class LinkResourceItem extends StatelessWidget { - final LinkResource linkResource; - - const LinkResourceItem(this.linkResource, {super.key}); - - @override - Widget build(BuildContext context) { - return ResourceItem( - linkResource, - icon: Icons.open_in_new, - onTap: () { - launchUrl(Uri.parse(linkResource.url), webOnlyWindowName: '_blank'); - }, - ); - } -} diff --git a/lib/screens/home/views/participant/components/resource_items/resource_item.dart b/lib/screens/home/views/participant/components/resource_items/resource_item.dart deleted file mode 100644 index b00ac19..0000000 --- a/lib/screens/home/views/participant/components/resource_items/resource_item.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; - -class ResourceItem extends StatelessWidget { - final Resource resource; - final IconData icon; - final void Function()? onTap; - - const ResourceItem(this.resource, {super.key, this.onTap, this.icon = Icons.chevron_right}); - - Widget _itemBuilder(BuildContext context) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(8), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - resource.name, - style: Theme.of(context).textTheme.bodyLarge, - ), - ), - Icon( - icon, - size: 20, - color: Theme.of(context).colorScheme.onSurface, - ), - ], - ), - ), - ); - } - - Widget _hiddenItemBuilder(BuildContext context) { - return Stack( - children: [ - _itemBuilder(context), - - Align( - alignment: Alignment.topRight, - child: IgnorePointer( - child: Container( - color: Colors.black.withAlpha(150), - child: Text( - 'HIDDEN TO PARTICIPANTS', - style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: Colors.white.withAlpha(255), - fontWeight: FontWeight.bold, - ), - textAlign: TextAlign.right, - ), - ), - ), - ), - ], - ); - } - - @override - Widget build(BuildContext context) { - return resource.hidden - ? _hiddenItemBuilder(context) - : _itemBuilder(context); - } -} diff --git a/lib/screens/home/views/participant/participant_view.dart b/lib/screens/home/views/participant/participant_view.dart deleted file mode 100644 index 2e6a641..0000000 --- a/lib/screens/home/views/participant/participant_view.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/config/constants.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/checklist_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/resource_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/discord_embed.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/live_card.dart'; -import 'package:hackncsu_today/screens/home/views/participant/components/cards/team_card.dart'; -import 'package:responsive_framework/responsive_framework.dart'; - -class ParticipantView extends ConsumerWidget { - final Participant participant; - - const ParticipantView(this.participant, {super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final isDesktop = ResponsiveBreakpoints.of(context).isDesktop; - - return Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - flex: 2, - child: Row( - children: [ - Expanded( - child: Column( - children: [ - Expanded(child: LiveCard()), - Expanded(flex: 2, child: TeamCard()), - ], - ), - ), - Expanded( - flex: 2, - child: DiscordEmbed( - serverID: kDiscordServerId, - channelID: kDiscordChannelId, - ), - ), - ], - ), - ), - Expanded( - child: Row( - children: [ - Expanded(child: ChecklistCard()), - Expanded(child: ResourceCard(ResourceSource.internal)), - Expanded(child: ResourceCard(ResourceSource.external)), - ], - ), - ), - ], - ), - ); - } -} diff --git a/lib/screens/login/components/authenticating_modal.dart b/lib/screens/login/components/authenticating_modal.dart deleted file mode 100644 index 561957d..0000000 --- a/lib/screens/login/components/authenticating_modal.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hackncsu_today/features/authenticator/authenticator.dart'; - -class AuthenticatingModal extends StatelessWidget { - final Authenticating state; - - const AuthenticatingModal({super.key, required this.state}); - - @override - Widget build(BuildContext context) { - return AlertDialog( - title: Text('Authenticating...'), - icon: Icon(Icons.lock_clock_outlined), - content: Text(state.message), - ); - } -} diff --git a/lib/screens/login/components/error_modal.dart b/lib/screens/login/components/error_modal.dart deleted file mode 100644 index 001d02c..0000000 --- a/lib/screens/login/components/error_modal.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class ErrorModal extends StatelessWidget { - final String content; - const ErrorModal(this.content, {super.key}); - - @override - Widget build(BuildContext context) { - return AlertDialog( - title: Text('Error Authenticating'), - icon: Icon(Icons.warning), - content: Text(content), - actions: [TextButton(onPressed: () => context.pop(), child: Text('OK'))], - ); - } -} diff --git a/lib/screens/login/components/primary_button.dart b/lib/screens/login/components/primary_button.dart deleted file mode 100644 index 6bb45ac..0000000 --- a/lib/screens/login/components/primary_button.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; - -class PrimaryButton extends StatelessWidget { - final void Function()? onTap; - final Widget child; - - const PrimaryButton({super.key, required this.onTap, required this.child}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).colorScheme; - - return Material( - color: theme.primaryContainer, - borderRadius: BorderRadius.circular(8), - child: InkWell( - borderRadius: BorderRadius.circular(8), - onTap: onTap, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: child - ), - ), - ); - } -} diff --git a/lib/screens/login/login.dart b/lib/screens/login/login.dart deleted file mode 100644 index 3841ac8..0000000 --- a/lib/screens/login/login.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'dart:async'; - -import 'package:after_layout/after_layout.dart'; -import 'package:animated_background/animated_background.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hackncsu_today/screens/login/components/primary_button.dart'; -import 'package:hackncsu_today/features/authenticator/authenticator.dart'; -import 'package:hackncsu_today/screens/login/components/authenticating_modal.dart'; -import 'package:hackncsu_today/screens/login/components/error_modal.dart'; -import 'package:responsive_framework/responsive_framework.dart'; - -class LoginScreen extends ConsumerStatefulWidget { - const LoginScreen({super.key}); - - @override - ConsumerState createState() => _LoginScreenState(); -} - -class _LoginScreenState extends ConsumerState - with TickerProviderStateMixin, AfterLayoutMixin { - @override - FutureOr afterFirstLayout(BuildContext context) { - if (ref.read(authenticatorProvider) is Authenticated) { - if (context.mounted) { - context.replace('/'); - } - } - } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).colorScheme; - final isDesktop = ResponsiveBreakpoints.of(context).isDesktop; - - // auth handler - ref.listen(authenticatorProvider, (old, current) async { - switch (current) { - case Unauthenticated(): - break; - case AutoAuthenticating(): - break; - case Authenticating(): - if (context.canPop() && old is Authenticating) context.pop(); - - await showDialog( - context: context, - builder: (_) => AuthenticatingModal(state: current), - barrierDismissible: false, - ); - - break; - - case AuthenticationError(): - if (context.canPop() && old is Authenticating) context.pop(); - - showDialog( - context: context, - builder: (_) => ErrorModal(current.error.toString()), - ); - break; - - case Authenticated(): - if (context.mounted) context.replace('/'); - break; - } - }); - - return Scaffold( - body: AnimatedBackground( - behaviour: RandomParticleBehaviour( - options: ParticleOptions( - spawnMinSpeed: 10, - spawnMaxSpeed: 50, - particleCount: 100, - baseColor: Theme.of(context).colorScheme.primaryContainer, - ), - ), - vsync: this, - child: Row( - children: [ - Expanded( - flex: 2, - child: Padding( - padding: const EdgeInsets.all(32), - child: Column( - crossAxisAlignment: - isDesktop - ? CrossAxisAlignment.start - : CrossAxisAlignment.stretch, - children: [ - Flex( - direction: isDesktop ? Axis.horizontal : Axis.vertical, - children: [ - Image.asset('img/name.png', height: 50), - Text( - '2026', - style: TextStyle( - fontSize: 45, - color: theme.onSurface, - ), - ), - ], - ), - SizedBox(height: 15), - Text( - 'Participant Login', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: isDesktop ? 100 : 30, - ), - ), - SizedBox(height: 15), - Text( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod" - 'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,' - 'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - style: TextStyle(fontSize: 20), - ), - SizedBox(height: 15), - Text( - 'Note that you must have completed check-in in order to log in. We will ' - 'compare your Discord username to your check-in information in order to ' - 'authenticate you.', - ), - SizedBox(height: 15), - PrimaryButton( - onTap: ref.read(authenticatorProvider.notifier).login, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Log in with Discord', - style: TextStyle(fontSize: 20), - ), - const SizedBox(width: 16), // Added for spacing - Icon(Icons.arrow_forward), - ], - ), - ), - ], - ), - ), - ), - if (isDesktop) SizedBox(width: 20), - if (isDesktop) Expanded(flex: 1, child: Placeholder()), - ], - ), - ), - ); - } -} diff --git a/lib/screens/not_found/not_found.dart b/lib/screens/not_found/not_found.dart deleted file mode 100644 index e9d2789..0000000 --- a/lib/screens/not_found/not_found.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class NotFoundScreen extends StatelessWidget { - const NotFoundScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - '404', - style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - const Text( - 'Oops! The page you are looking for does not exist.', - textAlign: TextAlign.center, - ), - const SizedBox(height: 24), - ElevatedButton( - onPressed: () { - context.go('/home'); - }, - child: const Text('Go to Home Page'), - ), - ], - ), - ), - ); - } -} diff --git a/lib/services/firebase/auth_service.dart b/lib/services/firebase/auth_service.dart deleted file mode 100644 index db1337c..0000000 --- a/lib/services/firebase/auth_service.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:hackncsu_today/services/firebase/functions_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'auth_service.g.dart'; - -@riverpod -FirebaseAuthService firebaseAuthService(Ref ref) { - return FirebaseAuthService(); -} - -class FirebaseAuthService { - final FirebaseAuth _auth = FirebaseAuth.instance; - - User? get user => _auth.currentUser; - - /// Authenticates the user with firebase using the token returned from the - /// firebase function that checks if the user is registered for the hackathon. - /// this way, one can only access the firebase database if they are registered. - Future login(AuthenticateFunctionResponse response) async { - final credentials = await _auth.signInWithCustomToken(response.token); - - final user = credentials.user; - - if (user == null) { - throw FirebaseAuthException( - 'Failed to sign in with custom token. User is null.', - ); - } - - if (user.displayName == null) { - await user.updateDisplayName( - '${response.firstName} ${response.lastName} (${response.username})', - ); - } - - if (kDebugMode) { - print('User logged in: ${response.firstName} ${response.lastName} (${response.username})'); - } - } - - /// logs out the user from firebase - Future logout() async { - try { - await _auth.signOut(); - if (kDebugMode) print('User logged out successfully.'); - } catch (e) { - throw FirebaseAuthException('Failed to log out: ${e.toString()}'); - } - } -} - -class FirebaseAuthException extends AppException { - const FirebaseAuthException(super.message); -} diff --git a/lib/services/firebase/firestore_service.dart b/lib/services/firebase/firestore_service.dart deleted file mode 100644 index 4204211..0000000 --- a/lib/services/firebase/firestore_service.dart +++ /dev/null @@ -1,264 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:hackncsu_today/models/event/event_data.dart'; -import 'package:hackncsu_today/models/event/event_state.dart'; -import 'package:hackncsu_today/models/hack_user.dart'; -import 'package:hackncsu_today/models/team.dart'; -import 'package:hackncsu_today/services/firebase/functions_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'firestore_service.g.dart'; - -@riverpod -FirebaseFirestoreService firebaseFirestoreService(Ref ref) { - return FirebaseFirestoreService(); -} - -/// Note: firestore rules are set up such that authenticated users may only -/// get/update their own user data. Cloud functions can be used to -/// get a small amount of data about other users -class FirebaseFirestoreService { - final FirebaseFirestore _firestore = FirebaseFirestore.instance; - - static const String _usersCollection = 'users'; - static const String _eventCollection = 'event'; - static const String _teamsCollection = 'teams'; - - static const String _eventStateDoc = 'state'; - static const String _eventDataDoc = 'data'; - - /// creates a new user document in Firestore with the given data. - /// if the user already exists, it returns the existing user document. - /// this is meant for use in the login flow - Future createUser(AuthenticateFunctionResponse response) async { - final userDocRef = _firestore.collection(_usersCollection).doc(response.id); - final docSnapshot = await userDocRef.get(); - - if (docSnapshot.exists) { - final existingUser = HackUser.fromJson(docSnapshot.data()!); - - // Skip this check in debug mode to allow for flexible testing with different user types - if (!kDebugMode) { - if (existingUser is Organizer && !response.isOrganizer) { - throw FirebaseFirestoreException( - 'User with ID ${response.id} is an organizer, but previous records indicate they are not.', - ); - } else if (existingUser is Participant && response.isOrganizer) { - throw FirebaseFirestoreException( - 'User with ID ${response.id} is a participant, but previous records indicate they are an organizer.', - ); - } - } - - return existingUser; - } else { - final HackUser hackUser; - - if (response.isOrganizer) { - hackUser = Organizer(id: response.id); - } else { - hackUser = Participant( - id: response.id, - firstName: response.firstName!, - lastName: response.lastName!, - phone: response.phone, - email: response.email, - dietaryRestrictions: - [], // TODO: add ability to get dietary restrictions - shirtSize: null, - eventsAttended: [], - hadFirstLunch: false, - hadDinner: false, - hadBreakfast: false, - hadSecondLunch: false, - ); - } - - await userDocRef.set(hackUser.toJson()).catchError((error) { - throw FirebaseFirestoreException('Failed to create user data: $error'); - }); - return hackUser; - } - } - - /// updates the user document in Firestore with the given user data. - Future updateUser(HackUser user) async { - _firestore - .collection(_usersCollection) - .doc(user.id) - .set(user.toJson(), SetOptions(merge: true)) - .catchError((error) { - throw FirebaseFirestoreException( - 'Failed to update user data: $error', - ); - }); - } - - /// fetches the user data from Firestore for the given user ID. - /// returns null if the user does not exist. - /// NOTE: this will fail for participants if they try to fetch another user's data - /// because of Firestore rules. they can only fetch their own data. - /// or use cloud functions to fetch limited data about other users. - Future fetchUser(String userId) async { - final userDocRef = _firestore.collection(_usersCollection).doc(userId); - final docSnapshot = await userDocRef.get().catchError((error) { - throw FirebaseFirestoreException('Failed to fetch user data: $error'); - }); - - if (docSnapshot.exists) { - return HackUser.fromJson(docSnapshot.data()!); - } else { - return null; - } - } - - /// Streams user data from Firestore for the given user ID. - Stream streamUser(String userId) { - final userDocRef = _firestore.collection(_usersCollection).doc(userId); - return userDocRef.snapshots().map((snapshot) { - if (snapshot.exists && snapshot.data() != null) { - return HackUser.fromJson(snapshot.data()!); - } - return null; - }); - } - - /// fetches the team data from Firestore for the given team ID. - /// returns null if the team does not exist. - /// NOTE: this will fail for participants if they try to fetch another team's data. - Future fetchTeamData(String teamId) async { - final teamDocRef = _firestore.collection(_teamsCollection).doc(teamId); - final docSnapshot = await teamDocRef.get().catchError((error) { - throw FirebaseFirestoreException('Failed to fetch team data: $error'); - }); - - if (docSnapshot.exists) { - return Team.fromJson(docSnapshot.data()!); - } else { - return null; - } - } - - /// Streams event data from Firestore. - Stream streamEventData() { - final eventDataRef = _firestore - .collection(_eventCollection) - .doc(_eventDataDoc); - - return eventDataRef.snapshots().map((snapshot) { - if (snapshot.exists && snapshot.data() != null) { - return EventData.fromJson(snapshot.data()!); - } - return null; - }); - } - - /// Streams event state from Firestore - Stream streamEventState() { - final eventStateRef = _firestore - .collection(_eventCollection) - .doc(_eventStateDoc); - - return eventStateRef.snapshots().map((snapshot) { - if (snapshot.exists && snapshot.data() != null) { - return EventState.fromJson(snapshot.data()!); - } - return null; - }); - } - - // Below are functions that are only authorized for organizers - // They will fail for participants by nature of our Firestore rules - - /// initializes event in Firestore. - /// this can be called from the admin panel to set up the event - /// it should be called once at the start of the event - /// and then we can update the relevant data as needed - Future initializeEvent() async { - final eventData = EventData( - tracks: [ - 'Track 1', - 'Track 2', - 'Track 3', - ], - externalResources: [ - Resource.link('Hack_NCState Website', 'https://hackncstate.org'), - Resource.link( - 'Centennial Map', - 'https://maps.ncsu.edu/#/buildings/783A', - ), - ], - internalResources: [ - Resource.link('Discord Server', 'https://example.com', hidden: true), - Resource.link('Schedule', 'https://example.com', hidden: true), - Resource.link( - 'Opening Ceremony Slides', - 'https://hackncstate.org', - hidden: true, - ), - Resource.action('Catering Options', ActionType.menu, hidden: true), - ], - ); - - final stateRef = _firestore - .collection(_eventCollection) - .doc(_eventStateDoc); - final dataRef = _firestore.collection(_eventCollection).doc(_eventDataDoc); - - final batch = _firestore.batch(); - - batch.set(stateRef, EventState.initial().toJson()); - batch.set(dataRef, eventData.toJson()); - - batch.commit().catchError((error) { - throw FirebaseFirestoreException( - 'Failed to initialize event data: $error', - ); - }); - } - - Future updateEventData(EventData eventData) async { - final dataRef = _firestore.collection(_eventCollection).doc(_eventDataDoc); - - await dataRef.set(eventData.toJson(), SetOptions(merge: true)).catchError(( - error, - ) { - throw FirebaseFirestoreException('Failed to update event data: $error'); - }); - } - - Future updateEventState(EventState eventState) async { - final stateRef = _firestore - .collection(_eventCollection) - .doc(_eventStateDoc); - - await stateRef.set(eventState.toJson(), SetOptions(merge: true)).catchError( - (error) { - throw FirebaseFirestoreException( - 'Failed to update event state: $error', - ); - }, - ); - } - - // Below are functions that are used only during debugging - - /// Sets the user type (useful for debugging purposes). - Future debugSetUserType(String id, String type) async { - if (kDebugMode) { - _firestore - .collection(_usersCollection) - .doc(id) - .update({'type': type}) - .catchError((error) { - throw FirebaseFirestoreException('Failed to switch view: $error'); - }); - } - } -} - -class FirebaseFirestoreException extends AppException { - const FirebaseFirestoreException(super.message); -} diff --git a/lib/services/firebase/functions_service.dart b/lib/services/firebase/functions_service.dart deleted file mode 100644 index 3e5f43f..0000000 --- a/lib/services/firebase/functions_service.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:cloud_functions/cloud_functions.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'functions_service.g.dart'; -part 'functions_service.freezed.dart'; - -@riverpod -FirebaseFunctionsService firebaseFunctionsService(Ref ref) { - return FirebaseFunctionsService(); -} - -class FirebaseFunctionsService { - final FirebaseFunctions _functions = FirebaseFunctions.instance; - - static const String _fetchUserEndpoint = 'fetchUser'; - - /// fetches the user document from Firestore with the given user ID. - /// returns only limited fields (name, last name, id) for public access. - /// if the user is an organizer, it returns null. - /// if the user is not found, it returns null. - /// TODO: implement this - Future fetchPublicUser(String id) async { - try { - final callable = _functions.httpsCallable(_fetchUserEndpoint); - final response = await callable.call({ - 'id': id, - }); - - if (response.data != null) { - return FetchPublicUserFunctionResponse.fromJson(response.data!); - } else { - return null; - } - } on FirebaseFunctionsException catch (e) { - throw FirebaseFunctionException( - 'Failed to fetch user data: ${e.message}', - ); - } - } -} - -typedef RawFirebaseFunctionResponse = Map; - -/// note: this is used in the OAuthService -/// but it's here because an (oauth redirected) firebase function handles the authentication -@freezed -sealed class AuthenticateFunctionResponse with _$AuthenticateFunctionResponse { - AuthenticateFunctionResponse._(); - - factory AuthenticateFunctionResponse({ - required String token, - required String id, - required String username, - required String? firstName, - required String? lastName, - required String? phone, - required String? email, - required bool isOrganizer, - }) = _AuthenticateFunctionResponse; - - factory AuthenticateFunctionResponse.fromJson(Map json) => - _$AuthenticateFunctionResponseFromJson(json); -} - -/// Represents the response from the fetchUser Firebase function. -/// Contains the user's public information. -@freezed -sealed class FetchPublicUserFunctionResponse with _$FetchPublicUserFunctionResponse { - FetchPublicUserFunctionResponse._(); - - factory FetchPublicUserFunctionResponse({ - required String id, - required String firstName, - required String lastName, - }) = _FetchPublicUserFunctionResponse; - - factory FetchPublicUserFunctionResponse.fromJson(Map json) => - _$FetchPublicUserFunctionResponseFromJson(json); -} - -class FirebaseFunctionException extends AppException { - const FirebaseFunctionException(super.message); -} diff --git a/lib/services/hive_service.dart b/lib/services/hive_service.dart deleted file mode 100644 index ce33edf..0000000 --- a/lib/services/hive_service.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:hackncsu_today/exception.dart'; - -/// contains box names lol -class HiveService { - static const oauth2Cache = 'oauth2_cache'; -} - -class BoxClosedException extends AppException { - final String boxName; - - const BoxClosedException(this.boxName) : super("the Box '$boxName' was used despite being closed or unopened"); -} \ No newline at end of file diff --git a/lib/services/oauth_service.dart b/lib/services/oauth_service.dart deleted file mode 100644 index 747bc7d..0000000 --- a/lib/services/oauth_service.dart +++ /dev/null @@ -1,119 +0,0 @@ -// service for performing oauth2 handshake - -import 'dart:async'; -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:hackncsu_today/services/firebase/functions_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:web/web.dart'; - -part 'oauth_service.g.dart'; - -@riverpod -OAuthService oauthService(Ref ref) { - return OAuthService(); -} - -class OAuthService { - static const String _clientID = '1371413608394653736'; - static const String _baseUrl = - 'discord.com'; - static const String _authorizationEndpoint = - '/api/oauth2/authorize'; - - static final String _redirectUrl = kDebugMode - ? 'http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback' - : 'https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback'; - // TODO: https://stackoverflow.com/questions/49825799/use-custom-domain-for-firebase-function-http-calls - - /// performs interactive oauth2 flow - /// and returns a standard auth response - Future authenticate() async { - final authUrl = Uri.https(_baseUrl, _authorizationEndpoint, { - 'client_id': _clientID, - 'redirect_uri': _redirectUrl, - 'response_type': 'code', - 'scope': 'identify', - 'state': DateTime.timestamp().millisecondsSinceEpoch.toString(), - }); - - final authWindow = window.open( - authUrl.toString(), - 'Discord Sign In', - 'opener=1,width=500,height=800', - ); - - if (authWindow == null) { - throw OAuthRedirectException( - 'Failed to open authentication window. Please ensure popups are not blocked.', - ); - } - - final completer = Completer(); - final timer = Timer.periodic(const Duration(milliseconds: 500), (timer) { - if (authWindow.closed == true) { - timer.cancel(); - if (!completer.isCompleted) { - completer.completeError( - OAuthRedirectException('Authentication was canceled.'), - ); - } - } - }); - - final StreamSubscription - messageSubscription = window.onMessage.listen((event) { - if (event.data.isA() && !completer.isCompleted) { - try { - final jsonString = (event.data as JSString).toDart; - final responseMap = jsonDecode(jsonString) as Map; - - if (responseMap['status'] == 'success') { - final data = responseMap['data'] as Map; - final authResponse = AuthenticateFunctionResponse.fromJson(data); - completer.complete(authResponse); - - } else { - final error = responseMap['error'] as Map; - final message = error['message'] as String; - - completer.completeError( - FirebaseFunctionException(message), - ); - } - } catch (e) { - completer.completeError( - OAuthRedirectException( - 'Failed to parse authentication response: $e', - ), - ); - } - } - }); - - try { - return await completer.future.timeout(const Duration(minutes: 3)); - } on TimeoutException { - throw OAuthRedirectException('Authentication timed out.'); - } finally { - timer.cancel(); - messageSubscription.cancel(); - if (!authWindow.closed) { - authWindow.close(); - } - } - } -} - -class UnauthenticatedException extends AppException { - const UnauthenticatedException() - : super('OAuth2 client accessed without first authenticating'); -} - -class OAuthRedirectException extends AppException { - const OAuthRedirectException(super.message); -} diff --git a/lib/services/organizer/task_service.dart b/lib/services/organizer/task_service.dart deleted file mode 100644 index f083102..0000000 --- a/lib/services/organizer/task_service.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:hackncsu_today/exception.dart'; -import 'package:hackncsu_today/features/streams/event_state_stream.dart'; -import 'package:hackncsu_today/models/event/event_state.dart'; -import 'package:hackncsu_today/screens/home/views/organizer/models/task.dart'; -import 'package:hackncsu_today/services/firebase/firestore_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'task_service.g.dart'; - -/// Manages tasks that organizers can run -@riverpod -TaskService taskService(Ref ref) { - return TaskService(); -} - -class TaskService { - List get quickTasks => [ - Task( - title: 'Initialize Event', - content: - 'Initializes hackathon event state and data in database, and adds sample data.\n' - 'This creates structure for hackathon state and supplementary data (links, resources, etc.)\n\n' - 'Should be executed once at the start of the event, before any participants join.\n' - 'Afterwards, edit the data to set the discord server invite etc. and make sure to set hidden to false so it shows up for participants.', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - await firestoreService.initializeEvent(); - }, - ), - Task( - title: 'Post announcement', - content: - 'Posts an announcement to the event state.\n' - 'This is useful for quick announcements or updates during the event.\n' - 'It will appear under the countdown timer on the Live Card with format "Announcement: ".\n' - 'Please remember to remove it when it is no longer relevant.', - parameters: (_) => [TaskParameter.string('Content')], - onExecute: (ref, parameters) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - final announcement = parameters[0] as StringTaskParameter; - - final eventState = ref.read(eventStateStreamProvider).valueOrNull; - if (eventState == null) { - throw TaskExecutionException('Event state is not initialized.'); - } - - final updatedEventState = eventState.copyWith( - announcement: announcement.value.trim(), - ); - await firestoreService.updateEventState(updatedEventState); - }, - ), - Task( - title: 'Remove announcement', - content: - 'Removes the announcement from the event state.\n' - 'This is useful when the announcement is no longer relevant.', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - final eventState = ref.read(eventStateStreamProvider).valueOrNull; - if (eventState == null) { - throw TaskExecutionException('Event state is not initialized.'); - } - - final updatedEventState = eventState.copyWith(announcement: null); - await firestoreService.updateEventState(updatedEventState); - }, - ), - ]; - - List get eventStateManagementTasks => [ - Task( - title: 'Set State to Initial State', - content: - 'Changes the event state to Initial.\n' - 'Pre-event state, before opening ceremony.', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - await firestoreService.updateEventState(EventState.initial()); - }, - ), - Task( - title: 'Set State to Standby', - content: - 'Changes the event state to Standby.\n' - 'This should be executed between states (between in progress and judging, for example).', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - await firestoreService.updateEventState(EventState.standby()); - }, - ), - Task( - title: 'Set State to Opening Ceremony', - content: - 'Changes the event state to Opening Ceremony.\n' - 'This should be executed when the opening ceremony starts.', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - await firestoreService.updateEventState(EventState.openingCeremony()); - }, - ), - Task( - title: 'Set State to In Progress', - content: - 'Changes the event state to In Progress.\n' - 'This should be executed when the hackathon starts.', - parameters: - (_) => [ - TaskParameter.dateTime( - 'Hackathon End Time\n(default: 24h from now)', - DateTime.now().add(const Duration(hours: 24)), - ), - ], - onExecute: (ref, parameters) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - - final startTime = DateTime.now(); - final endTime = parameters[0] as DateTimeTaskParameter; - - await firestoreService.updateEventState( - EventState.inProgress(startTime: startTime, endTime: endTime.value), - ); - }, - ), - Task( - title: 'Set State to Closing Ceremony', - content: - 'Changes the event state to Closing Ceremony.\n' - 'This should be executed when the closing ceremony starts.', - onExecute: (ref, _) async { - final firestoreService = ref.read(firebaseFirestoreServiceProvider); - await firestoreService.updateEventState(EventState.closingCeremony()); - }, - ), - ]; -} - -class TaskExecutionException extends AppException { - TaskExecutionException(super.message); -} diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 5a12311..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,1082 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 - url: "https://pub.dev" - source: hosted - version: "80.0.0" - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - sha256: bb84ee51e527053dd8e25ecc9f97a6abfdc19130fb4d883e4e8585e23e7e6dd8 - url: "https://pub.dev" - source: hosted - version: "1.3.60" - after_layout: - dependency: "direct main" - description: - name: after_layout - sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" - url: "https://pub.dev" - source: hosted - version: "7.3.0" - analyzer_plugin: - dependency: transitive - description: - name: analyzer_plugin - sha256: b3075265c5ab222f8b3188342dcb50b476286394a40323e85d1fa725035d40a4 - url: "https://pub.dev" - source: hosted - version: "0.13.0" - animated_background: - dependency: "direct main" - description: - name: animated_background - sha256: "24b05a6dca2cb0231b011f9e8fd2e9d8060faac08a78cf0643915bb7d6e9b03b" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - build: - dependency: transitive - description: - name: build - sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - build_config: - dependency: transitive - description: - name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" - url: "https://pub.dev" - source: hosted - version: "4.0.4" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 - url: "https://pub.dev" - source: hosted - version: "2.4.4" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" - url: "https://pub.dev" - source: hosted - version: "2.4.15" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" - url: "https://pub.dev" - source: hosted - version: "8.0.0" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 - url: "https://pub.dev" - source: hosted - version: "8.9.5" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - ci: - dependency: transitive - description: - name: ci - sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" - url: "https://pub.dev" - source: hosted - version: "0.1.0" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - cloud_firestore: - dependency: "direct main" - description: - name: cloud_firestore - sha256: "78d22987093d89e875102753cba0335f13b1255086925941dacb96cd0b57866e" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - cloud_firestore_platform_interface: - dependency: transitive - description: - name: cloud_firestore_platform_interface - sha256: a9ce2edd81c3578d22a35933af2f56742e628a09dcb923750d2525d3152a823d - url: "https://pub.dev" - source: hosted - version: "7.0.0" - cloud_firestore_web: - dependency: transitive - description: - name: cloud_firestore_web - sha256: b751751ca29eb8ceff95c4f6c2d21bc895de968118e98235f5ffe45f0173ae24 - url: "https://pub.dev" - source: hosted - version: "5.0.0" - cloud_functions: - dependency: "direct main" - description: - name: cloud_functions - sha256: "5765f5e87cd7a04c33135b718581249265e2633a21dcbfda0a5db730398ba8cb" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - cloud_functions_platform_interface: - dependency: transitive - description: - name: cloud_functions_platform_interface - sha256: f8953997dc4d9bd9c9b21718b761d8fa7e4e79d352002a79038c9b28770b02bb - url: "https://pub.dev" - source: hosted - version: "5.8.3" - cloud_functions_web: - dependency: transitive - description: - name: cloud_functions_web - sha256: ce52411f96b5e016a8fbab8a6cd38e1231a07b78a1775e97719bf545a8097fc8 - url: "https://pub.dev" - source: hosted - version: "5.0.0" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - custom_lint: - dependency: "direct dev" - description: - name: custom_lint - sha256: "409c485fd14f544af1da965d5a0d160ee57cd58b63eeaa7280a4f28cf5bda7f1" - url: "https://pub.dev" - source: hosted - version: "0.7.5" - custom_lint_builder: - dependency: transitive - description: - name: custom_lint_builder - sha256: "107e0a43606138015777590ee8ce32f26ba7415c25b722ff0908a6f5d7a4c228" - url: "https://pub.dev" - source: hosted - version: "0.7.5" - custom_lint_core: - dependency: transitive - description: - name: custom_lint_core - sha256: "31110af3dde9d29fb10828ca33f1dce24d2798477b167675543ce3d208dee8be" - url: "https://pub.dev" - source: hosted - version: "0.7.5" - custom_lint_visitor: - dependency: transitive - description: - name: custom_lint_visitor - sha256: "36282d85714af494ee2d7da8c8913630aa6694da99f104fb2ed4afcf8fc857d8" - url: "https://pub.dev" - source: hosted - version: "1.0.0+7.3.0" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - firebase_auth: - dependency: "direct main" - description: - name: firebase_auth - sha256: "974541532dc3f5ea3c0d7c5bb3e6c90fb81a8950e0e15c4a11e2b17a06379070" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_auth_platform_interface: - dependency: transitive - description: - name: firebase_auth_platform_interface - sha256: "86a6318fd53a2958a9323454a4b8601b19963030157d71f92e356deadf9a3551" - url: "https://pub.dev" - source: hosted - version: "8.0.0" - firebase_auth_web: - dependency: transitive - description: - name: firebase_auth_web - sha256: "042d424d50515cd62b4c0bda70872f5fa7e69c905e442b087e07e0117aac1222" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "6b343e6f7b72a4f32d7ce8df8c9a28d8f54b4ac20d7c6500f3e8b3969afca457" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: "5d28b14dd32282fb7ce2b22b897362453755b6b8541d491127dc72b755bb7b16" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - flutter_riverpod: - dependency: "direct main" - description: - name: flutter_riverpod - sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - sha256: "6022db4c7bfa626841b2a10f34dd1e1b68e8f8f9650db6112dcdeeca45ca793c" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - sha256: c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b - url: "https://pub.dev" - source: hosted - version: "3.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 - url: "https://pub.dev" - source: hosted - version: "14.8.1" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - hive_ce: - dependency: "direct main" - description: - name: hive_ce - sha256: fdc19336f03ecd01dbc1d1afe69d87ed9336bdf996c5374a25f9c21ef5f2989e - url: "https://pub.dev" - source: hosted - version: "2.11.1" - hive_ce_flutter: - dependency: "direct main" - description: - name: hive_ce_flutter - sha256: "5eaf57a5af980eda63ddaa8c34d618dc446f76fe79410f2a283522744291c05c" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - hotreloader: - dependency: transitive - description: - name: hotreloader - sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b - url: "https://pub.dev" - source: hosted - version: "4.3.0" - http: - dependency: transitive - description: - name: http - sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - isolate_channel: - dependency: transitive - description: - name: isolate_channel - sha256: bafedfbcc1e9796ada179b5dac7043b33eb85d35204b089ca37d480d9c0068df - url: "https://pub.dev" - source: hosted - version: "0.2.2" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c - url: "https://pub.dev" - source: hosted - version: "6.9.5" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" - url: "https://pub.dev" - source: hosted - version: "11.0.1" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.dev" - source: hosted - version: "5.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" - source: hosted - version: "2.2.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 - url: "https://pub.dev" - source: hosted - version: "2.2.17" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pointer_interceptor: - dependency: "direct main" - description: - name: pointer_interceptor - sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" - url: "https://pub.dev" - source: hosted - version: "0.10.1+2" - pointer_interceptor_ios: - dependency: transitive - description: - name: pointer_interceptor_ios - sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - pointer_interceptor_platform_interface: - dependency: transitive - description: - name: pointer_interceptor_platform_interface - sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" - url: "https://pub.dev" - source: hosted - version: "0.10.0+1" - pointer_interceptor_web: - dependency: transitive - description: - name: pointer_interceptor_web - sha256: "460b600e71de6fcea2b3d5f662c92293c049c4319e27f0829310e5a953b3ee2a" - url: "https://pub.dev" - source: hosted - version: "0.10.3" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - responsive_framework: - dependency: "direct main" - description: - name: responsive_framework - sha256: a8e1c13d4ba980c60cbf6fa1e9907cd60662bf2585184d7c96ca46c43de91552 - url: "https://pub.dev" - source: hosted - version: "1.5.1" - riverpod: - dependency: transitive - description: - name: riverpod - sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - riverpod_analyzer_utils: - dependency: transitive - description: - name: riverpod_analyzer_utils - sha256: "03a17170088c63aab6c54c44456f5ab78876a1ddb6032ffde1662ddab4959611" - url: "https://pub.dev" - source: hosted - version: "0.5.10" - riverpod_annotation: - dependency: "direct main" - description: - name: riverpod_annotation - sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 - url: "https://pub.dev" - source: hosted - version: "2.6.1" - riverpod_generator: - dependency: "direct dev" - description: - name: riverpod_generator - sha256: "44a0992d54473eb199ede00e2260bd3c262a86560e3c6f6374503d86d0580e36" - url: "https://pub.dev" - source: hosted - version: "2.6.5" - riverpod_lint: - dependency: "direct dev" - description: - name: riverpod_lint - sha256: "89a52b7334210dbff8605c3edf26cfe69b15062beed5cbfeff2c3812c33c9e35" - url: "https://pub.dev" - source: hosted - version: "2.6.5" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" - url: "https://pub.dev" - source: hosted - version: "1.3.5" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - state_notifier: - dependency: transitive - description: - name: state_notifier - sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb - url: "https://pub.dev" - source: hosted - version: "1.0.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" - url: "https://pub.dev" - source: hosted - version: "0.7.6" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" - url: "https://pub.dev" - source: hosted - version: "6.3.1" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" - url: "https://pub.dev" - source: hosted - version: "6.3.16" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" - url: "https://pub.dev" - source: hosted - version: "6.3.3" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" - url: "https://pub.dev" - source: hosted - version: "3.1.4" - uuid: - dependency: transitive - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" - url: "https://pub.dev" - source: hosted - version: "14.3.1" - watcher: - dependency: transitive - description: - name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web: - dependency: "direct main" - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.8.0-0 <4.0.0" - flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml deleted file mode 100644 index 08d431f..0000000 --- a/pubspec.yaml +++ /dev/null @@ -1,115 +0,0 @@ -name: hackncsu_today -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 - -environment: - sdk: ^3.7.2 - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - flutter_riverpod: ^2.6.1 - riverpod_annotation: ^2.6.1 - go_router: ^14.2.0 - animated_background: ^2.0.0 - responsive_framework: ^1.5.1 - url_launcher: ^6.3.1 - hive_ce: ^2.11.1 - hive_ce_flutter: ^2.3.0 - freezed_annotation: ^3.0.0 - json_annotation: ^4.9.0 - after_layout: ^1.2.0 - web: ^1.1.1 - pointer_interceptor: ^0.10.1+2 - firebase_core: ^4.0.0 - cloud_functions: ^6.0.0 - firebase_auth: ^6.0.0 - cloud_firestore: ^6.0.0 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^5.0.0 - riverpod_generator: ^2.6.5 - build_runner: ^2.4.15 - custom_lint: ^0.7.5 - riverpod_lint: ^2.6.5 - freezed: ^3.0.6 - json_serializable: ^6.9.5 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - assets: - - assets/img/logo.png - - assets/img/name.png - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index b679c1d..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:hackncsu_today/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/web/favicon.png b/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76e525556d5d89141648c724331630325d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c56691fbdb0b7efa65097c7cc1edac12a6d3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20998 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 MPgg&ebxsLQ025IeI{*Lx diff --git a/web/index.html b/web/index.html deleted file mode 100644 index d502b04..0000000 --- a/web/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - hackncsu_today - - - - - - diff --git a/web/manifest.json b/web/manifest.json deleted file mode 100644 index bc30eb9..0000000 --- a/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "hackncsu_today", - "short_name": "hackncsu_today", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} From 59e618a278af0fb9bd77c97d369a9dddbac8189c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sat, 18 Oct 2025 10:30:43 -0400 Subject: [PATCH 003/114] Add react stub --- .gitignore | 133 +-- README.md | 77 +- index.html | 13 + package-lock.json | 2542 ++++++++++++++++++++++++++++++++++++++++++ package.json | 29 + public/vite.svg | 1 + src/App.css | 42 + src/App.tsx | 35 + src/assets/react.svg | 1 + src/index.css | 68 ++ src/main.tsx | 10 + tsconfig.app.json | 28 + tsconfig.json | 7 + tsconfig.node.json | 26 + vite.config.ts | 7 + 15 files changed, 2895 insertions(+), 124 deletions(-) create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/App.css create mode 100644 src/App.tsx create mode 100644 src/assets/react.svg create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index 361184f..0ec7b11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,121 +1,26 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release - -*.g.dart -*.freezed.dart - # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* -firebase-debug.log* -firebase-debug.*.log* - -# Firebase cache -.firebase/ - -# Firebase config - -# Uncomment this if you'd like others to create their own Firebase project. -# For a team working on the same Firebase project(s), it is recommended to leave -# it commented so all members can deploy to the same project(s) in .firebaserc. -# .firebaserc - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# dataconnect generated files -.dataconnect +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? -.vscode/ -.idea/ +.firebase/* \ No newline at end of file diff --git a/README.md b/README.md index d9a21c7..d2e7761 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,73 @@ -# hackncsu_today +# React + TypeScript + Vite -A new Flutter project. +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. -## Getting Started +Currently, two official plugins are available: -This project is a starting point for a Flutter application. +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh -A few resources to get you started if this is your first Flutter project: +## React Compiler -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/index.html b/index.html new file mode 100644 index 0000000..8b5bfcb --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + hackncsu-today + + +

+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4124be9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2542 @@ +{ + "name": "hackncsu-today", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hackncsu-today", + "version": "0.0.0", + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "tailwindcss": "^4.1.14" + }, + "devDependencies": { + "@biomejs/biome": "2.2.6", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "typescript": "~5.9.3", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@biomejs/biome": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.6.tgz", + "integrity": "sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.2.6", + "@biomejs/cli-darwin-x64": "2.2.6", + "@biomejs/cli-linux-arm64": "2.2.6", + "@biomejs/cli-linux-arm64-musl": "2.2.6", + "@biomejs/cli-linux-x64": "2.2.6", + "@biomejs/cli-linux-x64-musl": "2.2.6", + "@biomejs/cli-win32-arm64": "2.2.6", + "@biomejs/cli-win32-x64": "2.2.6" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.6.tgz", + "integrity": "sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.6.tgz", + "integrity": "sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.6.tgz", + "integrity": "sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.6.tgz", + "integrity": "sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.6.tgz", + "integrity": "sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.6.tgz", + "integrity": "sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.6.tgz", + "integrity": "sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.6.tgz", + "integrity": "sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", + "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.0", + "lightningcss": "1.30.1", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", + "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.5.1" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-x64": "4.1.14", + "@tailwindcss/oxide-freebsd-x64": "4.1.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-x64-musl": "4.1.14", + "@tailwindcss/oxide-wasm32-wasi": "4.1.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", + "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", + "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", + "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", + "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", + "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", + "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", + "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", + "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", + "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", + "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.5", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", + "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", + "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz", + "integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.14", + "@tailwindcss/oxide": "4.1.14", + "tailwindcss": "4.1.14" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.8.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz", + "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.38", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz", + "integrity": "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", + "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", + "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1bfaff1 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "hackncsu-today", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --port 8080", + "build": "tsc -b && vite build", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "format": "biome format --write .", + "preview": "vite preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "tailwindcss": "^4.1.14" + }, + "devDependencies": { + "@biomejs/biome": "2.2.6", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "typescript": "~5.9.3", + "vite": "^7.1.7" + } +} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..3d7ded3 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' + +function App() { + const [count, setCount] = useState(0) + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..08a3ac9 --- /dev/null +++ b/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..a9b5a59 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) From deb8b0daba44a5d7c170dbcf4a0b693e352d9569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sat, 18 Oct 2025 11:03:49 -0400 Subject: [PATCH 004/114] Configure frameworks --- biome.json | 39 + components.json | 22 + index.html | 2 +- package-lock.json | 4556 ++++++++++++++++++++++++++++++++++++++++----- package.json | 7 + src/index.css | 165 +- src/lib/utils.ts | 6 + tsconfig.app.json | 53 +- tsconfig.json | 8 +- vite.config.ts | 15 +- 10 files changed, 4367 insertions(+), 506 deletions(-) create mode 100644 biome.json create mode 100644 components.json create mode 100644 src/lib/utils.ts diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..58ae074 --- /dev/null +++ b/biome.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.6/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..2b0833f --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/index.html b/index.html index 8b5bfcb..238ea4c 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + diff --git a/package-lock.json b/package-lock.json index 4124be9..4c0e339 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,13 @@ "version": "0.0.0", "dependencies": { "@tailwindcss/vite": "^4.1.14", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "jotai": "^2.15.0", + "lucide-react": "^0.546.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, "devDependencies": { @@ -19,15 +24,39 @@ "@types/react": "^19.1.16", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.4", + "shadcn": "^3.4.2", + "tw-animate-css": "^1.4.0", "typescript": "~5.9.3", "vite": "^7.1.7" } }, + "node_modules/@antfu/ni": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/@antfu/ni/-/ni-25.0.0.tgz", + "integrity": "sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.0.0", + "fzf": "^0.5.2", + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "na": "bin/na.mjs", + "nci": "bin/nci.mjs", + "ni": "bin/ni.mjs", + "nlx": "bin/nlx.mjs", + "nr": "bin/nr.mjs", + "nun": "bin/nun.mjs", + "nup": "bin/nup.mjs" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -42,7 +71,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -52,7 +81,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -83,7 +112,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", @@ -96,11 +125,24 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -113,12 +155,48 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, "engines": { "node": ">=6.9.0" } @@ -127,7 +205,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -141,7 +219,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -155,6 +233,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", @@ -165,11 +256,43 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -179,7 +302,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -189,7 +312,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -199,7 +322,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -213,7 +336,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.4" @@ -225,6 +348,55 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", @@ -257,11 +429,51 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -276,7 +488,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -295,7 +507,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -468,6 +680,161 @@ "node": ">=14.21.3" } }, + "node_modules/@dotenvx/dotenvx": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.51.0.tgz", + "integrity": "sha512-CbMGzyOYSyFF7d4uaeYwO9gpSBzLTnMmSmTVpCZjvpJFV69qYbjYPpzNnCz1mb2wIvEhjWjRwQWuBzTO0jITww==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "commander": "^11.1.0", + "dotenv": "^17.2.1", + "eciesjs": "^0.4.10", + "execa": "^5.1.1", + "fdir": "^6.2.0", + "ignore": "^5.3.0", + "object-treeify": "1.1.33", + "picomatch": "^4.0.2", + "which": "^4.0.0" + }, + "bin": { + "dotenvx": "src/cli/dotenvx.js" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@ecies/ciphers": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.4.tgz", + "integrity": "sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==", + "dev": true, + "license": "MIT", + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + }, + "peerDependencies": { + "@noble/ciphers": "^1.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.11", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", @@ -884,14 +1251,125 @@ "node": ">=18" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, + "node_modules/@inquirer/ansi": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", + "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", + "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", + "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.1", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", + "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, "engines": { "node": ">=18.0.0" } @@ -941,6 +1419,153 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.1.tgz", + "integrity": "sha512-j/P+yuxXfgxb+mW7OEoRCM3G47zCTDqUPivJo/VzpjbG8I9csTXtOprCf5FfOfHK4whOJny0aHuBEON+kS7CCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.39.8", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.8.tgz", + "integrity": "sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.38", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", @@ -1234,6 +1859,26 @@ "win32" ] }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@tailwindcss/node": { "version": "4.1.14", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", @@ -1496,6 +2141,18 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@ts-morph/common": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", + "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.3", + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1561,7 +2218,7 @@ "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1577,6 +2234,13 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/statuses": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", + "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", @@ -1598,21 +2262,155 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/baseline-browser-mapping": { "version": "2.8.18", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz", "integrity": "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.26.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -1642,27 +2440,91 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", - "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "devOptional": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -1672,197 +2534,1513 @@ "node": ">=18" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.3" + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=6.0" + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": ">=12" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.237", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", - "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" } }, - "node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", - "hasInstallScript": true, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" + "node": ">=8" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=6" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6.9.0" + "node": ">=7.0.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "node_modules/commander": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "dev": true, "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" + "engines": { + "node": ">=20" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "devOptional": true, "license": "MIT" }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" }, "engines": { - "node": ">=6" + "node": ">= 0.10" } }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "license": "MPL-2.0", + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.3" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eciesjs": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.16.tgz", + "integrity": "sha512-dS5cbA9rA2VR4Ybuvhg6jvdmp46ubLn3E+px8cG/35aEDNclrqoCjg6mt0HYZ/M+OoESS3jSkCrqk1kWAEhWAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.4", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", + "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fzf": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz", + "integrity": "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", + "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphql": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", + "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", + "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regexp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", + "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jotai": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.15.0.tgz", + "integrity": "sha512-nbp/6jN2Ftxgw0VwoVnOg0m5qYM1rVcfvij+MZx99Z5IK13eGve9FJoCwGv+17JvVthTjhSmNtT5e1coJnr6aw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0", + "@babel/template": ">=7.0.0", + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@babel/template": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "devOptional": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "devOptional": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" }, "engines": { "node": ">= 12.0.0" @@ -1884,275 +4062,804 @@ "lightningcss-win32-x64-msvc": "1.30.1" } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.546.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.546.0.tgz", + "integrity": "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, "engines": { - "node": ">= 12.0.0" + "node": "20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { - "node": ">= 12.0.0" + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/msw": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.5.tgz", + "integrity": "sha512-atFI4GjKSJComxcigz273honh8h4j5zzpk5kwG4tGm0TPcYne6bqmVrufeRll6auBeouIkXqZYXxVbWSWxM3RA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.39.1", + "@open-draft/deferred-promise": "^2.2.0", + "@types/statuses": "^2.0.4", + "cookie": "^1.0.2", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "rettime": "^0.7.0", + "statuses": "^2.0.2", + "strict-event-emitter": "^0.5.1", + "tough-cookie": "^6.0.0", + "type-fest": "^4.26.1", + "until-async": "^3.0.2", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" + "node_modules/msw/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/node-releases": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", + "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 10" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">= 0.8" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", "dependencies": { - "yallist": "^3.0.2" + "wrappy": "1" } }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/package-manager-detector": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.4.1.tgz", + "integrity": "sha512-dSMiVLBEA4XaNJ0PRb4N5cV/SEP4BWrWZKBmfF+OUm2pQTiZ6DDkKeWaltwu3JRhLoy59ayIkJ00cx9K9CaYTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { - "minipass": "^7.1.2" + "callsites": "^3.0.0" }, "engines": { - "node": ">= 18" + "node": ">=6" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "engines": { + "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">= 0.8" } }, - "node_modules/node-releases": { - "version": "2.0.25", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", - "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT" }, @@ -2162,6 +4869,28 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -2182,12 +4911,156 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/react": { @@ -2221,6 +5094,78 @@ "node": ">=0.10.0" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rettime": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", + "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.52.5", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", @@ -2262,6 +5207,86 @@ "fsevents": "~2.3.2" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -2272,19 +5297,351 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shadcn": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-3.4.2.tgz", + "integrity": "sha512-afa1UIHC9UzWX2NMHHwaZf6GfT5VGkTDen77RtyUBMfJ5i6ZQuzXOFTE1bFHTaWwftb8wQnMiG8kXdEu3Kx9IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/ni": "^25.0.0", + "@babel/core": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/plugin-transform-typescript": "^7.28.0", + "@babel/preset-typescript": "^7.27.1", + "@dotenvx/dotenvx": "^1.48.4", + "@modelcontextprotocol/sdk": "^1.17.2", + "browserslist": "^4.26.2", + "commander": "^14.0.0", + "cosmiconfig": "^9.0.0", + "dedent": "^1.6.0", + "deepmerge": "^4.3.1", + "diff": "^8.0.2", + "execa": "^9.6.0", + "fast-glob": "^3.3.3", + "fs-extra": "^11.3.1", + "fuzzysort": "^3.1.0", + "https-proxy-agent": "^7.0.6", + "kleur": "^4.1.5", + "msw": "^2.10.4", + "node-fetch": "^3.3.2", + "ora": "^8.2.0", + "postcss": "^8.5.6", + "prompts": "^2.4.2", + "recast": "^0.23.11", + "stringify-object": "^5.0.0", + "ts-morph": "^26.0.0", + "tsconfig-paths": "^4.2.0", + "zod": "^3.24.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "shadcn": "dist/index.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stringify-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", + "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-keys": "^1.0.0", + "is-obj": "^3.0.0", + "is-regexp": "^3.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/stringify-object?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" } }, "node_modules/tailwindcss": { @@ -2331,6 +5688,20 @@ "node": ">=18" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2347,33 +5718,131 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/tldts": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.17.tgz", + "integrity": "sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.17" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.17.tgz", + "integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, "engines": { - "node": ">=12.0.0" + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", + "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "engines": { + "node": ">=16" + } + }, + "node_modules/ts-morph": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", + "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.27.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "engines": { + "node": ">=6" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "devOptional": true, + "license": "0BSD" + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "dev": true, "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/typescript": { @@ -2397,11 +5866,54 @@ "devOptional": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/until-async": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", + "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/kettanaito" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -2428,6 +5940,26 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { "version": "7.1.10", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", @@ -2502,41 +6034,235 @@ } } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "bin": { + "node-which": "bin/which.js" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" } }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, + "devOptional": true, "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } } } } diff --git a/package.json b/package.json index 1bfaff1..b6709b8 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,13 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.14", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "jotai": "^2.15.0", + "lucide-react": "^0.546.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, "devDependencies": { @@ -23,6 +28,8 @@ "@types/react": "^19.1.16", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.4", + "shadcn": "^3.4.2", + "tw-animate-css": "^1.4.0", "typescript": "~5.9.3", "vite": "^7.1.7" } diff --git a/src/index.css b/src/index.css index 08a3ac9..310a9aa 100644 --- a/src/index.css +++ b/src/index.css @@ -1,68 +1,111 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} +@import "tailwindcss"; +@import "tw-animate-css"; -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} +@custom-variant dark (&:is(.dark *)); -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; +:root { + --radius: 0.65rem; + --background: oklch(1 0 0); + --foreground: oklch(0.141 0.005 285.823); + --card: oklch(1 0 0); + --card-foreground: oklch(0.141 0.005 285.823); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.141 0.005 285.823); + --primary: oklch(0.637 0.237 25.331); + --primary-foreground: oklch(0.971 0.013 17.38); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.967 0.001 286.375); + --muted-foreground: oklch(0.552 0.016 285.938); + --accent: oklch(0.967 0.001 286.375); + --accent-foreground: oklch(0.21 0.006 285.885); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.92 0.004 286.32); + --input: oklch(0.92 0.004 286.32); + --ring: oklch(0.637 0.237 25.331); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.141 0.005 285.823); + --sidebar-primary: oklch(0.637 0.237 25.331); + --sidebar-primary-foreground: oklch(0.971 0.013 17.38); + --sidebar-accent: oklch(0.967 0.001 286.375); + --sidebar-accent-foreground: oklch(0.21 0.006 285.885); + --sidebar-border: oklch(0.92 0.004 286.32); + --sidebar-ring: oklch(0.637 0.237 25.331); } -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } +.dark { + --background: oklch(0.141 0.005 285.823); + --foreground: oklch(0.985 0 0); + --card: oklch(0.21 0.006 285.885); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.21 0.006 285.885); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.637 0.237 25.331); + --primary-foreground: oklch(0.971 0.013 17.38); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.274 0.006 286.033); + --muted-foreground: oklch(0.705 0.015 286.067); + --accent: oklch(0.274 0.006 286.033); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.637 0.237 25.331); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.21 0.006 285.885); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.637 0.237 25.331); + --sidebar-primary-foreground: oklch(0.971 0.013 17.38); + --sidebar-accent: oklch(0.274 0.006 286.033); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.637 0.237 25.331); } diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/tsconfig.app.json b/tsconfig.app.json index a9b5a59..b37e868 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,28 +1,33 @@ { - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] } diff --git a/tsconfig.json b/tsconfig.json index 1ffef60..856b926 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,11 @@ "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" } - ] + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } } diff --git a/vite.config.ts b/vite.config.ts index 8b0f57b..2c1a551 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,14 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; +import path from "node:path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [react(), tailwindcss()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}); From afae98e8e6569aa83b54e7b0f77ff8d8396e3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sat, 18 Oct 2025 11:45:11 -0400 Subject: [PATCH 005/114] Add sample UI --- package-lock.json | 54 +++++++++++++++++++++++++ package.json | 1 + src/App.css | 42 -------------------- src/App.tsx | 46 +++++++++------------ src/components/ProtectedRoute.tsx | 22 +++++++++++ src/pages/Home.tsx | 66 +++++++++++++++++++++++++++++++ src/pages/Login.tsx | 59 +++++++++++++++++++++++++++ 7 files changed, 221 insertions(+), 69 deletions(-) delete mode 100644 src/App.css create mode 100644 src/components/ProtectedRoute.tsx create mode 100644 src/pages/Home.tsx create mode 100644 src/pages/Login.tsx diff --git a/package-lock.json b/package-lock.json index 4c0e339..c9db8b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "lucide-react": "^0.546.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, @@ -5094,6 +5095,53 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz", + "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/recast": { "version": "0.23.11", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", @@ -5342,6 +5390,12 @@ "node": ">= 18" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", diff --git a/package.json b/package.json index b6709b8..8b27976 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lucide-react": "^0.546.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, diff --git a/src/App.css b/src/App.css deleted file mode 100644 index b9d355d..0000000 --- a/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/src/App.tsx b/src/App.tsx index 3d7ded3..6e07b02 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,34 +1,26 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' +import Home from './pages/Home' +import Login from './pages/Login' +import ProtectedRoute from './components/ProtectedRoute' function App() { - const [count, setCount] = useState(0) - return ( - <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

+ +
+ + + + + } + /> + } /> + } /> +
-

- Click on the Vite and React logos to learn more -

- +
) } diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx new file mode 100644 index 0000000..edd0c38 --- /dev/null +++ b/src/components/ProtectedRoute.tsx @@ -0,0 +1,22 @@ +import { Navigate } from 'react-router-dom' + +interface ProtectedRouteProps { + children: React.ReactNode +} + +export default function ProtectedRoute({ children }: ProtectedRouteProps) { + // TODO: Replace with actual Firebase auth check + // Example when ready: + // const { user, loading } = useAuth() + // if (loading) return
Loading...
+ // if (!user) return + + // PLACEHOLDER: Currently allows all access + const isAuthenticated = true // Change to false to test redirect + + if (!isAuthenticated) { + return + } + + return <>{children} +} diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..5c2434c --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,66 @@ +export default function Home() { + return ( +
+
+ {/* Header */} +
+

HackNCState Dashboard

+

+ Welcome back! Here's what's happening at the hackathon. +

+
+ + {/* Main Dashboard Content */} +
+ {/* Quick Stats */} +
+
+

+ Total Participants +

+

324

+
+
+

+ Projects Submitted +

+

87

+
+
+

+ Time Remaining +

+

12h 34m

+
+
+ + {/* Announcements */} +
+

📢 Announcements

+
+
+

Lunch is being served in the main hall

+

Posted 23 minutes ago

+
+
+

Workshop: Intro to ML at 2:00 PM in Room 204

+

Posted 1 hour ago

+
+
+
+ + {/* Schedule */} +
+

🗓️ Schedule

+
+

• 2:00 PM - ML Workshop (Room 204)

+

• 4:00 PM - Mentor Office Hours (Main Hall)

+

• 6:00 PM - Dinner Service

+

• 8:00 AM Tomorrow - Project Submissions Due

+
+
+
+
+
+ ) +} diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx new file mode 100644 index 0000000..7bb5cf2 --- /dev/null +++ b/src/pages/Login.tsx @@ -0,0 +1,59 @@ +export default function Login() { + const handleDiscordLogin = () => { + // TODO: Implement Firebase Discord OAuth + console.log('Discord login clicked') + } + + return ( +
+
+ {/* Logo/Header */} +
+

HackNCState

+

+ Dashboard Login +

+
+ + {/* Login Card */} +
+
+
+

+ Sign in with your Discord account to access the hackathon dashboard +

+
+ + {/* Discord Login Button */} + + +

+ By signing in, you agree to our terms of service +

+
+
+ + {/* Footer */} +

+ Need help? Contact us at{' '} + + help@hackncstate.org + +

+
+
+ ) +} From e29aad30d5bf19941875bcc28ba226ab8138250e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sun, 19 Oct 2025 10:37:55 -0400 Subject: [PATCH 006/114] Implement login UI --- .vscode.example/launch.json | 27 -- .vscode.example/tasks.json | 24 -- biome.json | 5 - index.html | 2 +- package-lock.json | 504 ++++++++++++++++++++++++++++- package.json | 3 + src/App.tsx | 2 +- src/components/ui/alert-dialog.tsx | 155 +++++++++ src/components/ui/button.tsx | 60 ++++ src/components/ui/dialog.tsx | 141 ++++++++ src/{index.css => globals.css} | 98 +++--- src/main.tsx | 2 +- src/pages/Login.tsx | 137 ++++---- 13 files changed, 1006 insertions(+), 154 deletions(-) delete mode 100644 .vscode.example/launch.json create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/dialog.tsx rename src/{index.css => globals.css} (57%) diff --git a/.vscode.example/launch.json b/.vscode.example/launch.json deleted file mode 100644 index a8a55e0..0000000 --- a/.vscode.example/launch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - - { - "name": "hackncsu_today", - "request": "launch", - "type": "dart", - "args": ["--web-port", "8080"] - }, - { - "name": "hackncsu_today (profile mode)", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "hackncsu_today (release mode)", - "request": "launch", - "type": "dart", - "flutterMode": "release" - } - ] -} \ No newline at end of file diff --git a/.vscode.example/tasks.json b/.vscode.example/tasks.json index d29eeab..b501184 100644 --- a/.vscode.example/tasks.json +++ b/.vscode.example/tasks.json @@ -1,30 +1,6 @@ { "version": "2.0.0", "tasks": [ - { - "label": "Run build_runner watch", - "type": "shell", - "command": "dart", - "args": [ - "pub", - "run", - "build_runner", - "watch", - "--delete-conflicting-outputs" - ], - "isBackground": true, - "runOptions": { - "runOn": "folderOpen" - }, - "problemMatcher": [ - "$dart-build_runner" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "detail": "Runs `dart pub run build_runner watch` to automatically rebuild generated files." - }, { "label": "Start Firebase Emulators", "type": "shell", diff --git a/biome.json b/biome.json index 58ae074..03241ef 100644 --- a/biome.json +++ b/biome.json @@ -23,11 +23,6 @@ "quoteStyle": "double" } }, - "css": { - "parser": { - "tailwindDirectives": true - } - }, "assist": { "enabled": true, "actions": { diff --git a/index.html b/index.html index 238ea4c..44fc166 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - hackncsu-today + Hack_NCState Today
diff --git a/package-lock.json b/package-lock.json index c9db8b7..15ef273 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "hackncsu-today", "version": "0.0.0", "dependencies": { + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.14", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -1567,6 +1570,365 @@ "dev": true, "license": "MIT" }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.38", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", @@ -2229,7 +2591,7 @@ "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -2350,6 +2712,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ast-types": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", @@ -2918,6 +3292,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/diff": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", @@ -3535,6 +3915,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-own-enumerable-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", @@ -5095,6 +5484,53 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-router": { "version": "7.9.4", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", @@ -5142,6 +5578,28 @@ "node": ">=18" } }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/recast": { "version": "0.23.11", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", @@ -5858,7 +6316,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, "license": "0BSD" }, "node_modules/tw-animate-css": { @@ -6004,6 +6461,49 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 8b27976..b742c72 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.14", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/App.tsx b/src/App.tsx index 6e07b02..8070bff 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,7 +6,7 @@ import ProtectedRoute from './components/ProtectedRoute' function App() { return ( -
+
) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..21409a0 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,60 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..f12777e --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,141 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/index.css b/src/globals.css similarity index 57% rename from src/index.css rename to src/globals.css index 310a9aa..d855fce 100644 --- a/src/index.css +++ b/src/globals.css @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Splash&family=Syne+Mono&display=swap'); + @import "tailwindcss"; @import "tw-animate-css"; @@ -39,73 +41,97 @@ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); + --font-geist: 'Geist', sans-serif; + --font-playfair: 'Playfair Display', serif; + --font-synemono: 'Syne Mono', monospace; + --font-splash: 'Splash', cursive; } :root { --radius: 0.65rem; --background: oklch(1 0 0); - --foreground: oklch(0.141 0.005 285.823); + --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); - --card-foreground: oklch(0.141 0.005 285.823); + --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); - --popover-foreground: oklch(0.141 0.005 285.823); - --primary: oklch(0.637 0.237 25.331); - --primary-foreground: oklch(0.971 0.013 17.38); - --secondary: oklch(0.967 0.001 286.375); - --secondary-foreground: oklch(0.21 0.006 285.885); - --muted: oklch(0.967 0.001 286.375); - --muted-foreground: oklch(0.552 0.016 285.938); - --accent: oklch(0.967 0.001 286.375); - --accent-foreground: oklch(0.21 0.006 285.885); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.92 0.004 286.32); - --input: oklch(0.92 0.004 286.32); - --ring: oklch(0.637 0.237 25.331); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.141 0.005 285.823); - --sidebar-primary: oklch(0.637 0.237 25.331); - --sidebar-primary-foreground: oklch(0.971 0.013 17.38); - --sidebar-accent: oklch(0.967 0.001 286.375); - --sidebar-accent-foreground: oklch(0.21 0.006 285.885); - --sidebar-border: oklch(0.92 0.004 286.32); - --sidebar-ring: oklch(0.637 0.237 25.331); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { - --background: oklch(0.141 0.005 285.823); + --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); - --card: oklch(0.21 0.006 285.885); + --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.21 0.006 285.885); + --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.637 0.237 25.331); - --primary-foreground: oklch(0.971 0.013 17.38); - --secondary: oklch(0.274 0.006 286.033); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.274 0.006 286.033); - --muted-foreground: oklch(0.705 0.015 286.067); - --accent: oklch(0.274 0.006 286.033); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); - --ring: oklch(0.637 0.237 25.331); + --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); --chart-4: oklch(0.627 0.265 303.9); --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.21 0.006 285.885); + --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.637 0.237 25.331); - --sidebar-primary-foreground: oklch(0.971 0.013 17.38); - --sidebar-accent: oklch(0.274 0.006 286.033); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.637 0.237 25.331); + --sidebar-ring: oklch(0.556 0 0); } + +@layer base { + body { + @apply bg-background text-foreground; + font-family: var(--font-geist); + } + + * { + @apply border-border; + } + + /* html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow-x: hidden; + } */ +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index bef5202..d3019fe 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,6 +1,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' -import './index.css' +import './globals.css' import App from './App.tsx' createRoot(document.getElementById('root')!).render( diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 7bb5cf2..22f6da6 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -1,59 +1,82 @@ +import { Button } from "@/components/ui/button"; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { useNavigate } from "react-router-dom"; + export default function Login() { - const handleDiscordLogin = () => { - // TODO: Implement Firebase Discord OAuth - console.log('Discord login clicked') - } - - return ( -
-
- {/* Logo/Header */} -
-

HackNCState

-

- Dashboard Login -

-
- - {/* Login Card */} -
-
-
-

- Sign in with your Discord account to access the hackathon dashboard -

-
- - {/* Discord Login Button */} - - -

- By signing in, you agree to our terms of service -

-
-
- - {/* Footer */} -

- Need help? Contact us at{' '} - - help@hackncstate.org - -

-
-
- ) + const navigation = useNavigate(); + + const handleDiscordLogin = () => { + // TODO: Implement Firebase Discord OAuth + + navigation("/"); + }; + + return ( +
+
+

+ Hack_NCState Today +

+
+
+

+ Welcome to Hack_NCState 2026! Please check in, then log in with the + Discord account you used at registration. +

+

+ Thank you for joining us this weekend. We hope you have a great time! +

+
+ + + +

Team Hack_NCState

+ + + + + + + + About Hack_NCState Today + +

+ The Hack_NCState Today platform is designed to enhance your + hackathon experience by providing real-time updates, + announcements, and resources throughout the event. +

+
+

+ As long as you leave this page open, you'll receive + notifications about important happenings during the hackathon. +

+
+

+ This year is our first time launching this platform, so we'd + love to hear your feedback! +

+
+

Made with ❤️ by the Hack_NCState team.

+
+
+
+
+
+ ); } From cf2bfae5c55a96109b442aedce3287b123c86c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sun, 19 Oct 2025 11:45:39 -0400 Subject: [PATCH 007/114] Add sidebar for main screen --- src/App.tsx | 46 +++++++++++----------- src/pages/Home.tsx | 66 -------------------------------- src/pages/Home/Countdown.tsx | 8 ++++ src/pages/Home/ResourcesList.tsx | 39 +++++++++++++++++++ src/pages/Home/index.tsx | 24 ++++++++++++ 5 files changed, 94 insertions(+), 89 deletions(-) delete mode 100644 src/pages/Home.tsx create mode 100644 src/pages/Home/Countdown.tsx create mode 100644 src/pages/Home/ResourcesList.tsx create mode 100644 src/pages/Home/index.tsx diff --git a/src/App.tsx b/src/App.tsx index 8070bff..561a061 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,27 +1,27 @@ -import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' -import Home from './pages/Home' -import Login from './pages/Login' -import ProtectedRoute from './components/ProtectedRoute' +import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; +import Home from "./pages/Home"; +import Login from "./pages/Login"; +import ProtectedRoute from "./components/ProtectedRoute"; function App() { - return ( - -
- - - - - } - /> - } /> - } /> - -
-
- ) + return ( + +
+ + + + + } + /> + } /> + } /> + +
+
+ ); } -export default App +export default App; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx deleted file mode 100644 index 5c2434c..0000000 --- a/src/pages/Home.tsx +++ /dev/null @@ -1,66 +0,0 @@ -export default function Home() { - return ( -
-
- {/* Header */} -
-

HackNCState Dashboard

-

- Welcome back! Here's what's happening at the hackathon. -

-
- - {/* Main Dashboard Content */} -
- {/* Quick Stats */} -
-
-

- Total Participants -

-

324

-
-
-

- Projects Submitted -

-

87

-
-
-

- Time Remaining -

-

12h 34m

-
-
- - {/* Announcements */} -
-

📢 Announcements

-
-
-

Lunch is being served in the main hall

-

Posted 23 minutes ago

-
-
-

Workshop: Intro to ML at 2:00 PM in Room 204

-

Posted 1 hour ago

-
-
-
- - {/* Schedule */} -
-

🗓️ Schedule

-
-

• 2:00 PM - ML Workshop (Room 204)

-

• 4:00 PM - Mentor Office Hours (Main Hall)

-

• 6:00 PM - Dinner Service

-

• 8:00 AM Tomorrow - Project Submissions Due

-
-
-
-
-
- ) -} diff --git a/src/pages/Home/Countdown.tsx b/src/pages/Home/Countdown.tsx new file mode 100644 index 0000000..9448dc4 --- /dev/null +++ b/src/pages/Home/Countdown.tsx @@ -0,0 +1,8 @@ +export default function Countdown() { + return ( +
+ HALFWAY THERE + 12:59:10 +
+ ); +} diff --git a/src/pages/Home/ResourcesList.tsx b/src/pages/Home/ResourcesList.tsx new file mode 100644 index 0000000..1b90e84 --- /dev/null +++ b/src/pages/Home/ResourcesList.tsx @@ -0,0 +1,39 @@ +interface ResourcesListProps { + title?: string; + items?: ResourceItemProps[]; +} + +interface ResourceItemProps { + label: string; + href: string | (() => void); +} + +export default function ResourcesList({ + title = "Resources", + items = [], +}: ResourcesListProps) { + const linkStyles = + "hover:text-primary transition-colors underline-offset-4 hover:underline text-left"; + + return ( +
+

{title}

+ +
    + {items.map((item) => ( +
  • + {typeof item.href === "function" ? ( + + ) : ( + + {item.label} + + )} +
  • + ))} +
+
+ ); +} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx new file mode 100644 index 0000000..429fc52 --- /dev/null +++ b/src/pages/Home/index.tsx @@ -0,0 +1,24 @@ +import Countdown from "./Countdown"; +import ResourcesList from "./ResourcesList"; + +export default function Home() { + const resourcesLinks = [ + { label: "Discord Server", href: "#" }, + { label: "Opening Slides", href: "#" }, + { label: "Third Item", href: () => alert("You clicked Third Item!") }, + ]; + + return ( +
+ + +
+

Main content area

+
+
+ ); +} From 99e907cc60f722a3f6935f03dad60c51d4bc7c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sun, 19 Oct 2025 21:37:29 -0400 Subject: [PATCH 008/114] Add mobile support for main screen sidebar --- src/components/ui/sheet.tsx | 137 ++++++++++++++++++++++++++++ src/pages/Home/ResourcesList.tsx | 2 +- src/pages/Home/ResourcesSection.tsx | 20 ++++ src/pages/Home/index.tsx | 70 +++++++++++++- 4 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 src/components/ui/sheet.tsx create mode 100644 src/pages/Home/ResourcesSection.tsx diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx new file mode 100644 index 0000000..6906f5b --- /dev/null +++ b/src/components/ui/sheet.tsx @@ -0,0 +1,137 @@ +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" +}) { + return ( + + + + {children} + + + Close + + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/src/pages/Home/ResourcesList.tsx b/src/pages/Home/ResourcesList.tsx index 1b90e84..c123ef7 100644 --- a/src/pages/Home/ResourcesList.tsx +++ b/src/pages/Home/ResourcesList.tsx @@ -1,4 +1,4 @@ -interface ResourcesListProps { +export interface ResourcesListProps { title?: string; items?: ResourceItemProps[]; } diff --git a/src/pages/Home/ResourcesSection.tsx b/src/pages/Home/ResourcesSection.tsx new file mode 100644 index 0000000..ac59481 --- /dev/null +++ b/src/pages/Home/ResourcesSection.tsx @@ -0,0 +1,20 @@ +import type { ResourcesListProps } from "./ResourcesList"; +import ResourcesList from "./ResourcesList"; + +interface ResourcesSectionProps { + sections: ResourcesListProps[]; +} + +export default function ResourcesSection({ sections }: ResourcesSectionProps) { + return ( +
+ {sections.map((section, index) => ( + + ))} +
+ ); +} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 429fc52..d9cc6f5 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,5 +1,8 @@ +import { MenuIcon } from "lucide-react"; import Countdown from "./Countdown"; +import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; import ResourcesList from "./ResourcesList"; +import ResourcesSection from "./ResourcesSection"; export default function Home() { const resourcesLinks = [ @@ -8,12 +11,75 @@ export default function Home() { { label: "Third Item", href: () => alert("You clicked Third Item!") }, ]; + const sampleResourcesSection = [ + { + title: "Resources", + items: [ + { + label: "Rules", + href: "#", + }, + { + label: "Tracks", + href: "#", + }, + { + label: "Opening Slides", + href: "#", + }, + { + label: "Judging Criteria", + href: "#", + }, + ], + }, + { + title: "Quick Links", + items: [ + { + label: "Discord Server", + href: "#", + }, + { + label: "Catering Menu", + href: "#", + }, + ], + }, + { + title: "System", + items: [ + { + label: "Log out", + href: () => alert("Logging out..."), + }, + { + label: "About", + href: () => alert("HackNC 2024 - Powered by NC State University"), + }, + ], + }, + ]; + return (
From b4e1e8338bc44a071b1c112e67578bfab16f3cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sun, 19 Oct 2025 21:46:06 -0400 Subject: [PATCH 009/114] Add firebase support --- package-lock.json | 852 ++++++++++++++++++++++++++++++++++++- package.json | 1 + src/lib/firebase-config.ts | 29 ++ 3 files changed, 859 insertions(+), 23 deletions(-) create mode 100644 src/lib/firebase-config.ts diff --git a/package-lock.json b/package-lock.json index 15ef273..af146e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@tailwindcss/vite": "^4.1.14", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "firebase": "^12.4.0", "jotai": "^2.15.0", "lucide-react": "^0.546.0", "react": "^19.1.1", @@ -1255,6 +1256,645 @@ "node": ">=18" } }, + "node_modules/@firebase/ai": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.4.0.tgz", + "integrity": "sha512-YilG6AJ/nYpCKtxZyvEzBRAQv5bU+2tBOKX4Ps0rNNSdxN39aT37kGhjATbk1kq1z5Lq7mkWglw/ajAF3lOWUg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.19", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.19.tgz", + "integrity": "sha512-3wU676fh60gaiVYQEEXsbGS4HbF2XsiBphyvvqDbtC1U4/dO4coshbYktcCHq+HFaGIK07iHOh4pME0hEq1fcg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.25.tgz", + "integrity": "sha512-fdzoaG0BEKbqksRDhmf4JoyZf16Wosrl0Y7tbZtJyVDOOwziE0vrFjmZuTdviL0yhak+Nco6rMsUUbkbD+qb6Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.19", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz", + "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.4.tgz", + "integrity": "sha512-pUxEGmR+uu21OG/icAovjlu1fcYJzyVhhT0rsCrn+zi+nHtrS43Bp9KPn9KGa4NMspCUE++nkyiqziuIvJdwzw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.0.tgz", + "integrity": "sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz", + "integrity": "sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.11.0", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz", + "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.4.tgz", + "integrity": "sha512-T7ifGmb+awJEcp542Ek4HtNfBxcBrnuk1ggUdqyFEdsXHdq7+wVlhvE6YukTL7NS8hIkEfL7TMAPx/uCNqt30g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.14.4", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.11.0.tgz", + "integrity": "sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.0.tgz", + "integrity": "sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.11.0", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", + "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.0.tgz", + "integrity": "sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.11.tgz", + "integrity": "sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.0.tgz", + "integrity": "sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.0.tgz", + "integrity": "sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/database": "1.1.0", + "@firebase/database-types": "1.0.16", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.16.tgz", + "integrity": "sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.13.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.9.2.tgz", + "integrity": "sha512-iuA5+nVr/IV/Thm0Luoqf2mERUvK9g791FZpUJV1ZGXO6RL2/i/WFJUj5ZTVXy5pRjpWYO+ZzPcReNrlilmztA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "@firebase/webchannel-wrapper": "1.0.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.2.tgz", + "integrity": "sha512-cy7ov6SpFBx+PHwFdOOjbI7kH00uNKmIFurAn560WiPCZXy9EMnil1SOG7VF4hHZKdenC+AHtL4r3fNpirpm0w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/firestore": "4.9.2", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz", + "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.1.tgz", + "integrity": "sha512-sUeWSb0rw5T+6wuV2o9XNmh9yHxjFI9zVGFnjFi+n7drTEWpl7ZTz1nROgGrSu472r+LAaj+2YaSicD4R8wfbw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.1.tgz", + "integrity": "sha512-AxxUBXKuPrWaVNQ8o1cG1GaCAtXT8a0eaTDfqgS5VsRYLAR0ALcfqDLwo/QyijZj1w8Qf8n3Qrfy/+Im245hOQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/functions": "0.13.1", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz", + "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.19", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.19.tgz", + "integrity": "sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.19", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.19.tgz", + "integrity": "sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz", + "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz", + "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.23", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.23.tgz", + "integrity": "sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz", + "integrity": "sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/messaging": "0.12.23", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz", + "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.9.tgz", + "integrity": "sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.22.tgz", + "integrity": "sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/performance": "0.7.9", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz", + "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.7.0.tgz", + "integrity": "sha512-dX95X6WlW7QlgNd7aaGdjAIZUiQkgWgNS+aKNu4Wv92H1T8Ue/NDUjZHd9xb8fHxLXIHNZeco9/qbZzr500MjQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.20.tgz", + "integrity": "sha512-P/ULS9vU35EL9maG7xp66uljkZgcPMQOxLj3Zx2F289baTKSInE6+YIkgHEi1TwHoddC/AFePXPpshPlEFkbgg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/remote-config": "0.7.0", + "@firebase/remote-config-types": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz", + "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.0.tgz", + "integrity": "sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.0.tgz", + "integrity": "sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/storage": "0.14.0", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz", + "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.13.0.tgz", + "integrity": "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz", + "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==", + "license": "Apache-2.0" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@inquirer/ansi": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", @@ -1570,6 +2210,70 @@ "dev": true, "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", @@ -2571,7 +3275,6 @@ "version": "24.8.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz", "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==", - "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~7.14.0" @@ -2683,7 +3386,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -2964,7 +3666,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -2979,7 +3680,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2989,14 +3689,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3011,7 +3709,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3024,7 +3721,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3058,7 +3754,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3071,7 +3766,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/commander": { @@ -3496,7 +4190,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -3683,6 +4376,18 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -3771,6 +4476,42 @@ "node": ">= 0.8" } }, + "node_modules/firebase": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.4.0.tgz", + "integrity": "sha512-/chNgDQ6ppPPGOQO4jctxOa/5JeQxuhaxA7Y90K0I+n/wPfoO8mRveedhVUdo7ExLcWUivnnow/ouSLYSI5Icw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/ai": "2.4.0", + "@firebase/analytics": "0.10.19", + "@firebase/analytics-compat": "0.2.25", + "@firebase/app": "0.14.4", + "@firebase/app-check": "0.11.0", + "@firebase/app-check-compat": "0.4.0", + "@firebase/app-compat": "0.5.4", + "@firebase/app-types": "0.9.3", + "@firebase/auth": "1.11.0", + "@firebase/auth-compat": "0.6.0", + "@firebase/data-connect": "0.3.11", + "@firebase/database": "1.1.0", + "@firebase/database-compat": "2.1.0", + "@firebase/firestore": "4.9.2", + "@firebase/firestore-compat": "0.4.2", + "@firebase/functions": "0.13.1", + "@firebase/functions-compat": "0.4.1", + "@firebase/installations": "0.6.19", + "@firebase/installations-compat": "0.2.19", + "@firebase/messaging": "0.12.23", + "@firebase/messaging-compat": "0.2.23", + "@firebase/performance": "0.7.9", + "@firebase/performance-compat": "0.2.22", + "@firebase/remote-config": "0.7.0", + "@firebase/remote-config-compat": "0.2.20", + "@firebase/storage": "0.14.0", + "@firebase/storage-compat": "0.4.0", + "@firebase/util": "1.13.0" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -3871,7 +4612,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -4070,6 +4810,12 @@ "node": ">= 0.8" } }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -4107,6 +4853,12 @@ "node": ">=0.10.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4172,7 +4924,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4659,6 +5410,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", @@ -4689,6 +5446,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -5349,6 +6112,30 @@ "node": ">=6" } }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -5621,7 +6408,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5769,7 +6555,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -6374,7 +7159,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", - "devOptional": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -6598,6 +7382,35 @@ "node": ">= 8" } }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -6685,7 +7498,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -6702,7 +7514,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -6721,7 +7532,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -6731,7 +7541,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6741,14 +7550,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -6763,7 +7570,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" diff --git a/package.json b/package.json index b742c72..0625933 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@tailwindcss/vite": "^4.1.14", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "firebase": "^12.4.0", "jotai": "^2.15.0", "lucide-react": "^0.546.0", "react": "^19.1.1", diff --git a/src/lib/firebase-config.ts b/src/lib/firebase-config.ts new file mode 100644 index 0000000..24c31d0 --- /dev/null +++ b/src/lib/firebase-config.ts @@ -0,0 +1,29 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { connectFirestoreEmulator, getFirestore } from "firebase/firestore"; +import { connectFunctionsEmulator, getFunctions } from "firebase/functions"; +import { connectAuthEmulator, getAuth } from "firebase/auth"; + +const firebaseConfig = { + apiKey: "AIzaSyDw7jjs3fAbi6pxiOO4_omWefLTAjf72lw", + authDomain: "hackncsu-today.firebaseapp.com", + projectId: "hackncsu-today", + storageBucket: "hackncsu-today.firebasestorage.app", + messagingSenderId: "638064491024", + appId: "1:638064491024:web:f32d36e7170d5a39e9a895", + measurementId: "G-MMCWYB3KX0", +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); +export const firestore = getFirestore(app); +export const functions = getFunctions(app); +export const auth = getAuth(app); + +if (import.meta.env.DEV) { + console.log("Firebase initialized in development mode"); + + connectAuthEmulator(auth, "http://localhost:9099"); + connectFirestoreEmulator(firestore, "localhost", 5500); + connectFunctionsEmulator(functions, "localhost", 5001); +} \ No newline at end of file From c5e69aa5f9be7457c103d6c29cc411a10deb11aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Sun, 19 Oct 2025 23:32:14 -0400 Subject: [PATCH 010/114] Add rudimentary oauth reimplementation --- functions/auth/oauth_callback.py | 142 +++++++++++++++--------------- src/App.tsx | 2 + src/components/ProtectedRoute.tsx | 19 ++-- src/pages/Auth.tsx | 32 +++++++ src/pages/Login.tsx | 5 +- src/services/auth.service.ts | 45 ++++++++++ 6 files changed, 164 insertions(+), 81 deletions(-) create mode 100644 src/pages/Auth.tsx create mode 100644 src/services/auth.service.ts diff --git a/functions/auth/oauth_callback.py b/functions/auth/oauth_callback.py index fa3092e..6dde830 100644 --- a/functions/auth/oauth_callback.py +++ b/functions/auth/oauth_callback.py @@ -3,7 +3,7 @@ import requests from firebase_functions import https_fn from firebase_functions.params import SecretParam, StringParam, IntParam -from firebase_admin import auth +from firebase_admin import auth, firestore import google.auth @@ -18,6 +18,11 @@ default="https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback", description="The redirect URI for Discord OAuth2.", ) # set to http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback in .env.local for local testing +FRONTEND_AUTH_URI = StringParam( + "FRONTEND_AUTH_URI", + default="https://today.hackncstate.org/auth", + description="The frontend URI to redirect to after authentication is complete.", +) # set to http://localhost:8080/auth in .env.local for local testing SPREADSHEET_URL = StringParam( "SPREADSHEET_URL", @@ -67,10 +72,13 @@ ) -def _generate_auth_token(id: str, username: str) -> dict: +def _validate_user(id: str, username: str) -> tuple[str, dict]: """Compare a Discord user with the participants spreadsheet and give a token if they are included and checked in. Also returns - user information if available.""" + user information. + + Most user information will be missing if the user is an organizer since + organizers do not need to be in the spreadsheet.""" print(f"Generating auth token for user {username} ({id})") import gspread @@ -174,18 +182,25 @@ def _generate_auth_token(id: str, username: str) -> dict: if os.getenv("FUNCTIONS_EMULATOR") == "true": is_organizer = False - result = { - "token": custom_token.decode("utf-8"), + user = { # TODO update to be dataclass for nicer typing "id": id, "username": username, "firstName": first_name, "lastName": last_name, "phone": phone, "email": email, + "dietaryRestrictions": None, # TODO get this from spreadsheet? + "shirtSize": None, # TODO get this from spreadsheet? + "eventsAttended": [], + "hadFirstLunch": False, + "hadSecondLunch": False, + "hadDinner": False, + "hadBreakfast": False, + "notes": [], "isOrganizer": is_organizer, } - print(f"Successfully generated token and user data: {result}") - return result + print(f"Successfully generated token and user data: {user}") + return (custom_token.decode("utf-8"), user) except Exception as e: print(f"Error creating custom token: {e}") raise ValueError( @@ -194,6 +209,33 @@ def _generate_auth_token(id: str, username: str) -> dict: ) +def _create_user(data: dict): + """Create the user in Firestore (/users/{id}) if they do not already exist.""" + db = firestore.client() + user_id = data["id"] + user_ref = db.collection("users").document(user_id) + + user_doc = user_ref.get() + + if user_doc.exists: + print(f"User {user_id} already exists in Firestore. Updating...") + user_ref.update( + { + "username": data["username"], + "firstName": data.get("firstName"), + "lastName": data.get("lastName"), + "phone": data.get("phone"), + "email": data.get("email"), + "isOrganizer": data["isOrganizer"], + } + ) + else: + print(f"Creating new user {user_id} in Firestore...") + user_ref.set(data) + + print(f"User {user_id} saved successfully.") + + @https_fn.on_request(secrets=[CLIENT_SECRET]) def oauth_callback(req: https_fn.Request) -> https_fn.Response: """Handle OAuth2 callback from Discord. Returns HTML page that is listened to @@ -203,18 +245,7 @@ def oauth_callback(req: https_fn.Request) -> https_fn.Response: code = req.args.get("code") print(f"Received code: {code}") - if not code: - print("Missing 'code' parameter. Args: ", req.url) - response_json = json.dumps( - { - "status": "error", - "error": { - "code": "missing-parameter", - "message": "Missing 'code' parameter in the request.", - }, - } - ) - else: + if code: try: token_data = { "grant_type": "authorization_code", @@ -247,58 +278,31 @@ def oauth_callback(req: https_fn.Request) -> https_fn.Response: discord_user_id = discord_user["id"] discord_username = discord_user["username"] - print("Calling _generate_auth_token...") - auth_token = _generate_auth_token( + print("Calling _validate_user...") + + token, user = _validate_user( id=discord_user_id, username=discord_username, ) - print(f"Received auth token from _generate_auth_token: {auth_token}") + print(f"Received auth token from _validate_user: {token}") + + _create_user(user) + + print("Ensured user exists in Firestore.") + + # Redirect to frontend with token + redirect_url = f"{FRONTEND_AUTH_URI.value}?token={token}" + print(f"Redirecting to: {redirect_url}") + return https_fn.Response(status=302, headers={"Location": redirect_url}) - success_payload = { - "status": "success", - "data": auth_token, - } - response_json = json.dumps(success_payload) - print(f"Success payload: {response_json}") - - except ValueError as e: - # Handle specific ValueError exceptions (e.g., missing parameters, invalid format) - print(f"Caught ValueError: {e}") - error_code, error_message = e.args - error_payload = { - "status": "error", - "error": {"code": error_code, "message": error_message}, - } - response_json = json.dumps(error_payload) - print(f"Error payload (ValueError): {response_json}") except Exception as e: - # Handle unexpected errors (e.g., Discord API is down, parsing failed) - print(f"Caught unexpected exception: {e}") - error_payload = { - "status": "error", - "error": { - "code": "internal-server-error", - "message": f"An unexpected error occurred during authentication. Contact a staff member.\n{e}", - }, - } - response_json = json.dumps(error_payload) - print(f"Error payload (Exception): {response_json}") - - html_response = f""" - - - Authenticating... - -

Please wait, finishing authentication...

- - - - """ - print("Sending HTML response to close popup.") - - return https_fn.Response(html_response, status=200, content_type="text/html") + # Handle any errors during authentication + print(f"Caught exception: {e}") + redirect_url = f"{FRONTEND_AUTH_URI.value}?error=internal_error" + print(f"Redirecting to error page: {redirect_url}") + return https_fn.Response(status=302, headers={"Location": redirect_url}) + + # Handle missing code parameter + redirect_url = f"{FRONTEND_AUTH_URI.value}?error=missing_code" + print(f"Redirecting to error page: {redirect_url}") + return https_fn.Response(status=302, headers={"Location": redirect_url}) diff --git a/src/App.tsx b/src/App.tsx index 561a061..9dc8e93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import Home from "./pages/Home"; import Login from "./pages/Login"; import ProtectedRoute from "./components/ProtectedRoute"; +import Auth from "./pages/Auth"; function App() { return ( @@ -17,6 +18,7 @@ function App() { } /> } /> + } /> } />
diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx index edd0c38..6ca2ddb 100644 --- a/src/components/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute.tsx @@ -1,3 +1,4 @@ +import { useAuth } from '@/services/auth.service' import { Navigate } from 'react-router-dom' interface ProtectedRouteProps { @@ -5,18 +6,18 @@ interface ProtectedRouteProps { } export default function ProtectedRoute({ children }: ProtectedRouteProps) { - // TODO: Replace with actual Firebase auth check - // Example when ready: - // const { user, loading } = useAuth() - // if (loading) return
Loading...
- // if (!user) return - - // PLACEHOLDER: Currently allows all access - const isAuthenticated = true // Change to false to test redirect + const { user, loading } = useAuth(); - if (!isAuthenticated) { + if (loading) { + return
; + } + + if (!user) { return } + // TODO remove + console.log("User is authenticated:", user); + return <>{children} } diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx new file mode 100644 index 0000000..b10b6a0 --- /dev/null +++ b/src/pages/Auth.tsx @@ -0,0 +1,32 @@ +import { useEffect } from "react"; +import { useSearchParams, useNavigate } from "react-router-dom"; +import { signInWithCustomToken } from "firebase/auth"; +import { auth } from "@/lib/firebase-config"; + +export default function Auth() { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + + // TODO: handle errors better (make screen better) and navigate from Login to / if auth is successful + useEffect(() => { + const token = searchParams.get("token"); + const error = searchParams.get("error"); + + if (token) { + // Sign in with the token + signInWithCustomToken(auth, token) + .then(() => { + navigate("/"); + }) + .catch((err) => { + console.error("Auth error:", err); + // Handle error + }); + } else if (error) { + // Handle error case + console.error("Authentication failed"); + } + }, [navigate, searchParams]); + + return
Authenticating...
; +} diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 22f6da6..c16783f 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -8,15 +8,14 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import { authService } from "@/services/auth.service"; import { useNavigate } from "react-router-dom"; export default function Login() { const navigation = useNavigate(); const handleDiscordLogin = () => { - // TODO: Implement Firebase Discord OAuth - - navigation("/"); + authService.startOAuth(); }; return ( diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts new file mode 100644 index 0000000..78963d3 --- /dev/null +++ b/src/services/auth.service.ts @@ -0,0 +1,45 @@ +import { auth } from "@/lib/firebase-config"; +import { + onAuthStateChanged, + signInWithCustomToken, + signInWithPopup, +} from "firebase/auth"; +import { useEffect, useState } from "react"; + +const clientId = "1371413608394653736"; +const baseUrl = "https://discord.com/api/oauth2/authorize"; +const redirectUri = encodeURIComponent( + import.meta.env.DEV + ? "http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback" + : "https://us-central1-hackncsu-today.cloudfunctions.net/oauth_callback", +); + +export const authService = { + startOAuth: () => { + window.location.href = `${baseUrl}?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=identify`; + }, + + login: async (token: string) => { + const credential = await signInWithCustomToken(auth, token); + return credential; + }, + + logout: async () => auth.signOut(), + + getCurrentUser: () => auth.currentUser, +}; + +// TODO: Replace w/ atom-based firestore user data +export function useAuth() { + const [user, setUser] = useState(auth.currentUser); + const [loading, setLoading] = useState(true); + + useEffect(() => { + return onAuthStateChanged(auth, (firebaseUser) => { + setUser(firebaseUser); + setLoading(false); + }); + }, []); + + return { user, loading }; +} From 1545b85141992ec0b58a7d5eac06bd2ff982aca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Mon, 20 Oct 2025 09:10:28 -0400 Subject: [PATCH 011/114] Improve auth flow --- functions/auth/oauth_callback.py | 19 +++++++---- src/pages/Auth.tsx | 58 ++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/functions/auth/oauth_callback.py b/functions/auth/oauth_callback.py index 6dde830..5fb61ca 100644 --- a/functions/auth/oauth_callback.py +++ b/functions/auth/oauth_callback.py @@ -112,7 +112,7 @@ def _validate_user(id: str, username: str) -> tuple[str, dict]: if not cell: raise ValueError( - "participant-not-found", + "participant_not_found", "This Discord account is not associated with a registered participant.\nLet a staff member know if you think this is a mistake.", ) @@ -124,7 +124,7 @@ def _validate_user(id: str, username: str) -> tuple[str, dict]: if str(checked_in_status).upper() != "TRUE": raise ValueError( - "not-checked-in", + "not_checked_in", "You're a participant but it seems you haven't checked in yet!\nPlease check in at the registration desk or let a staff member know if you think this is a mistake.", ) @@ -136,14 +136,14 @@ def _validate_user(id: str, username: str) -> tuple[str, dict]: if not first_name or not last_name or not email: raise ValueError( - "missing-info", + "missing_info", "Participant's name or email is missing in the spreadsheet.", ) except gspread.exceptions.SpreadsheetNotFound: print("Spreadsheet not found.") raise ValueError( - "spreadsheet-not-found", + "spreadsheet_not_found", "Spreadsheet not found. Check name and permissions.", ) except https_fn.HttpsError as e: @@ -152,7 +152,7 @@ def _validate_user(id: str, username: str) -> tuple[str, dict]: except Exception as e: print(f"Caught exception while checking spreadsheet: {e}") raise ValueError( - "internal-error", + "spreadsheet_check_error", f"An error occurred checking spreadsheet: {e}", ) else: @@ -204,7 +204,7 @@ def _validate_user(id: str, username: str) -> tuple[str, dict]: except Exception as e: print(f"Error creating custom token: {e}") raise ValueError( - "token-creation-failed", + "token_creation_failed", f"Error creating custom token: {e}", ) @@ -294,6 +294,13 @@ def oauth_callback(req: https_fn.Request) -> https_fn.Response: redirect_url = f"{FRONTEND_AUTH_URI.value}?token={token}" print(f"Redirecting to: {redirect_url}") return https_fn.Response(status=302, headers={"Location": redirect_url}) + + except ValueError as ve: + error_code, error_message = ve.args + print(f"Caught ValueError: {error_code}, {error_message}") + redirect_url = f"{FRONTEND_AUTH_URI.value}?error={error_code}" + print(f"Redirecting to error page: {redirect_url}") + return https_fn.Response(status=302, headers={"Location": redirect_url}) except Exception as e: # Handle any errors during authentication diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index b10b6a0..03bc056 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -1,32 +1,78 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useSearchParams, useNavigate } from "react-router-dom"; import { signInWithCustomToken } from "firebase/auth"; import { auth } from "@/lib/firebase-config"; +import { Button } from "@/components/ui/button"; export default function Auth() { const [searchParams] = useSearchParams(); const navigate = useNavigate(); - // TODO: handle errors better (make screen better) and navigate from Login to / if auth is successful + const [errorCode, setErrorCode] = useState(""); + + // TODO: navigate from Login to / if auth is successful useEffect(() => { const token = searchParams.get("token"); const error = searchParams.get("error"); if (token) { - // Sign in with the token signInWithCustomToken(auth, token) .then(() => { navigate("/"); }) .catch((err) => { console.error("Auth error:", err); - // Handle error + setErrorCode("auth_error"); }); } else if (error) { - // Handle error case console.error("Authentication failed"); + setErrorCode(error); + } else { + setErrorCode("no_token"); } }, [navigate, searchParams]); - return
Authenticating...
; + function getErrorMessage(code: string) { + switch (code) { + case "invalid_token": + return "Invalid authorization token. Please try logging in again."; + case "participant_not_found": + return "This Discord account is not associated with a registered participant. Let a staff member know if you think this is a mistake."; + case "not_checked_in": + return "You're a participant but it seems you haven't checked in yet! Please check in at the registration desk or let a staff member know if you think this is a mistake."; + case "missing_info": + return "Participant information is incomplete. Please contact a staff member."; + case "auth_error": + return "An unexpected error occurred while logging in. Please try again."; + case "no_token": + return "No authentication token provided."; + default: + return "An unknown error occurred."; + } + } + + return ( +
+

+ {errorCode ? "Authentication Failed" : "One moment please"} +

+ {errorCode ? ( +
+

{getErrorMessage(errorCode)}

+ + +
+ ) : ( +

+ If you are not redirected automatically, please click{" "} + + here + + . +

+ )} +
+ ); } From e637cee96c5ac90d0c2d4bad49d73e534b14ab5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Mon, 20 Oct 2025 09:50:37 -0400 Subject: [PATCH 012/114] Add redirect on login --- src/pages/Login.tsx | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index c16783f..8751d41 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -8,22 +8,35 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { authService } from "@/services/auth.service"; +import { authService, useAuth } from "@/services/auth.service"; +import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; export default function Login() { const navigation = useNavigate(); + const { user, loading } = useAuth(); const handleDiscordLogin = () => { authService.startOAuth(); }; + useEffect(() => { + if (!loading && user) { + navigation("/", { replace: true }); + } + }, [user, loading, navigation]); + return (

Hack_NCState Today

+ Hack_NCState Today - Login +

@@ -46,7 +59,7 @@ export default function Login() {

Team Hack_NCState

- + @@ -55,23 +68,23 @@ export default function Login() { About Hack_NCState Today -

+

The Hack_NCState Today platform is designed to enhance your hackathon experience by providing real-time updates, announcements, and resources throughout the event. -

+

-

+

As long as you leave this page open, you'll receive notifications about important happenings during the hackathon. -

+

-

+

This year is our first time launching this platform, so we'd love to hear your feedback! -

+

-

Made with ❤️ by the Hack_NCState team.

+
Made with ❤️ by the Hack_NCState team.
From c3ef78abbe4f019d4fb4b2a212f5865cf4ad7dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Mon, 20 Oct 2025 09:51:06 -0400 Subject: [PATCH 013/114] Clean up code --- src/pages/Auth.tsx | 1 - src/pages/Home/index.tsx | 31 +++++++++++++++++++++++-------- src/services/auth.service.ts | 3 ++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index 03bc056..e7bb8eb 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -10,7 +10,6 @@ export default function Auth() { const [errorCode, setErrorCode] = useState(""); - // TODO: navigate from Login to / if auth is successful useEffect(() => { const token = searchParams.get("token"); const error = searchParams.get("error"); diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index d9cc6f5..ff272a9 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,16 +1,16 @@ import { MenuIcon } from "lucide-react"; import Countdown from "./Countdown"; -import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; -import ResourcesList from "./ResourcesList"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; import ResourcesSection from "./ResourcesSection"; export default function Home() { - const resourcesLinks = [ - { label: "Discord Server", href: "#" }, - { label: "Opening Slides", href: "#" }, - { label: "Third Item", href: () => alert("You clicked Third Item!") }, - ]; - const sampleResourcesSection = [ { title: "Resources", @@ -63,6 +63,13 @@ export default function Home() { return (
+
+

Hack_NCState Today

+

+ Welcome to Hack_NCState 2026! Your real-time event dashboard is here. +

+
+
-

Main content area

+

Main content area

{user?.username}
); diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 8751d41..c3c6c0f 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -8,13 +8,16 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { authService, useAuth } from "@/services/auth.service"; +import { authService } from "@/services/auth.service"; import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; +import { useAtomValue } from "jotai"; +import { userAtom } from "@/atoms/user"; export default function Login() { const navigation = useNavigate(); - const { user, loading } = useAuth(); + const user = useAtomValue(userAtom); + const loading = user === undefined; const handleDiscordLogin = () => { authService.startOAuth(); diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index 9dbebec..9728841 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -1,9 +1,5 @@ import { auth } from "@/lib/firebase-config"; -import { - onAuthStateChanged, - signInWithCustomToken, -} from "firebase/auth"; -import { useEffect, useState } from "react"; +import { signInWithCustomToken } from "firebase/auth"; const clientId = "1371413608394653736"; const baseUrl = "https://discord.com/api/oauth2/authorize"; @@ -29,18 +25,3 @@ export const authService = { getCurrentUser: () => auth.currentUser, }; - -// TODO: Replace w/ atom-based firestore user data -export function useAuth() { - const [user, setUser] = useState(auth.currentUser); - const [loading, setLoading] = useState(true); - - useEffect(() => { - return onAuthStateChanged(auth, (firebaseUser) => { - setUser(firebaseUser); - setLoading(false); - }); - }, []); - - return { user, loading }; -} diff --git a/src/services/firestore.service.ts b/src/services/firestore.service.ts new file mode 100644 index 0000000..387f473 --- /dev/null +++ b/src/services/firestore.service.ts @@ -0,0 +1,22 @@ +import { firestore } from "@/lib/firebase-config"; +import { UserSchema } from "@/types/user"; +import { doc, getDoc } from "firebase/firestore"; + +const collections = { + users: "users", +}; + +export const firestoreService = { + // this will fail if the user is a participant + // and they try accessing other user's data + fetchUser: async (userId: string) => { + const userDocRef = doc(firestore, collections.users, userId); + const userSnapshot = await getDoc(userDocRef); + + if (userSnapshot.exists()) { + return UserSchema.parse(userSnapshot.data()); + } + + return null; + }, +}; diff --git a/src/types/user.ts b/src/types/user.ts new file mode 100644 index 0000000..a503ec7 --- /dev/null +++ b/src/types/user.ts @@ -0,0 +1,39 @@ +import { z } from "zod"; + +const BaseUserSchema = z.object({ + id: z.string(), + username: z.string(), + attrs: z.array(z.string()).optional(), +}); + +export const OrganizerSchema = BaseUserSchema.extend({ + role: z.literal("organizer"), +}); + +export const ParticipantSchema = BaseUserSchema.extend({ + role: z.literal("participant"), + + email: z.string(), + firstName: z.string(), + lastName: z.string(), + phone: z.string(), + shirtSize: z.string(), + dietaryRestrictions: z.string(), + rfidUUID: z.string(), + + teamId: z.string().optional(), + attendedEvents: z.array(z.string()), + hadFirstLunch: z.boolean(), + hadSecondLunch: z.boolean(), + hadBreakfast: z.boolean(), + hadDinner: z.boolean(), +}); + +export const UserSchema = z.discriminatedUnion("role", [ + OrganizerSchema, + ParticipantSchema, +]); + +export type Organizer = z.infer; +export type Participant = z.infer; +export type UserData = z.infer; From 67bd86a5a5b8b69cfb9109309d77808e69b83373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Fri, 28 Nov 2025 18:00:43 -0500 Subject: [PATCH 018/114] Add user data to homepage --- src/globals.css | 7 +++- src/pages/Home/ResourcesList.tsx | 45 +++++++------------------ src/pages/Home/ResourcesListSection.tsx | 39 +++++++++++++++++++++ src/pages/Home/ResourcesSection.tsx | 20 ----------- src/pages/Home/index.tsx | 16 +++++++-- 5 files changed, 71 insertions(+), 56 deletions(-) create mode 100644 src/pages/Home/ResourcesListSection.tsx delete mode 100644 src/pages/Home/ResourcesSection.tsx diff --git a/src/globals.css b/src/globals.css index 6f5e7de..d7bb46b 100644 --- a/src/globals.css +++ b/src/globals.css @@ -137,6 +137,10 @@ @apply border-border; } + .firebase-emulator-warning { + display: none !important; + } + /* html, body { margin: 0; padding: 0; @@ -144,4 +148,5 @@ height: 100%; overflow-x: hidden; } */ -} \ No newline at end of file +} + diff --git a/src/pages/Home/ResourcesList.tsx b/src/pages/Home/ResourcesList.tsx index c123ef7..db5715f 100644 --- a/src/pages/Home/ResourcesList.tsx +++ b/src/pages/Home/ResourcesList.tsx @@ -1,39 +1,20 @@ -export interface ResourcesListProps { - title?: string; - items?: ResourceItemProps[]; -} +import type { ResourcesListProps } from "./ResourcesListSection"; +import ResourcesListSection from "./ResourcesListSection"; -interface ResourceItemProps { - label: string; - href: string | (() => void); +interface ResourcesSectionProps { + sections: ResourcesListProps[]; } -export default function ResourcesList({ - title = "Resources", - items = [], -}: ResourcesListProps) { - const linkStyles = - "hover:text-primary transition-colors underline-offset-4 hover:underline text-left"; - +export default function ResourcesList({ sections }: ResourcesSectionProps) { return ( -
-

{title}

- -
+
+ {sections.map((section) => ( + + ))}
); } diff --git a/src/pages/Home/ResourcesListSection.tsx b/src/pages/Home/ResourcesListSection.tsx new file mode 100644 index 0000000..f645c69 --- /dev/null +++ b/src/pages/Home/ResourcesListSection.tsx @@ -0,0 +1,39 @@ +export interface ResourcesListProps { + title?: string; + items?: ResourceItemProps[]; +} + +interface ResourceItemProps { + label: string; + href: string | (() => void); +} + +export default function ResourcesListSection({ + title = "Resources", + items = [], +}: ResourcesListProps) { + const linkStyles = + "hover:text-primary transition-colors underline-offset-4 hover:underline text-left"; + + return ( +
+

{title}

+ +
    + {items.map((item) => ( +
  • + {typeof item.href === "function" ? ( + + ) : ( + + {item.label} + + )} +
  • + ))} +
+
+ ); +} diff --git a/src/pages/Home/ResourcesSection.tsx b/src/pages/Home/ResourcesSection.tsx deleted file mode 100644 index ac59481..0000000 --- a/src/pages/Home/ResourcesSection.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { ResourcesListProps } from "./ResourcesList"; -import ResourcesList from "./ResourcesList"; - -interface ResourcesSectionProps { - sections: ResourcesListProps[]; -} - -export default function ResourcesSection({ sections }: ResourcesSectionProps) { - return ( -
- {sections.map((section, index) => ( - - ))} -
- ); -} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 63878a8..4e8475c 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -8,7 +8,7 @@ import { SheetTitle, SheetTrigger, } from "@/components/ui/sheet"; -import ResourcesSection from "./ResourcesSection"; +import ResourcesList from "./ResourcesList"; import { authService } from "@/services/auth.service"; import { useAtomValue } from "jotai"; import { userAtom } from "@/atoms/user"; @@ -66,8 +66,12 @@ export default function Home() { const user = useAtomValue(userAtom); - const resourcesContent = ( - + const resourcesContent = ; + + const sidebarFooter = ( +
+ Hack_NCState Today +
); return ( @@ -97,11 +101,17 @@ export default function Home() { {resourcesContent} + +
{sidebarFooter}
{resourcesContent}
+ +

(temporary) {user?.username}

+ +
{sidebarFooter}
From 6e8e7549e44c7fd58f9ddb2faeca6e0dc4f31a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Fri, 19 Dec 2025 16:47:09 -0800 Subject: [PATCH 019/114] Update spreadsheet search to use header names --- functions/.env.hackncsu-today | 14 ---- functions/auth/oauth_callback.py | 125 ++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 51 deletions(-) delete mode 100644 functions/.env.hackncsu-today diff --git a/functions/.env.hackncsu-today b/functions/.env.hackncsu-today deleted file mode 100644 index b11a52c..0000000 --- a/functions/.env.hackncsu-today +++ /dev/null @@ -1,14 +0,0 @@ -SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/160mQFRW4EXJpxHGi2QGIWsn0yqPNyMfmfXf5gxvYHCU/edit?gid=0#gid=0 -REDIRECT_URI=http://127.0.0.1:5001/hackncsu-today/us-central1/oauth_callback -CLIENT_ID=1371413608394653736 -ORGANIZERS_LIST= -FRONTEND_AUTH_URI=http://localhost:8080/auth -SHIRT_SIZE_COL_R=16 -CHECKED_IN_COL_C=0 -FIRST_NAME_COL_C=1 -LAST_NAME_COL_C=2 -PHONE_NUMBER_COL_C=3 -EMAIL_COL_C=4 -DIETARY_RESTRICTIONS_COL_C=5 -RFID_UUID_COL_C=7 -USERNAME_COL_R=6 diff --git a/functions/auth/oauth_callback.py b/functions/auth/oauth_callback.py index 36c8a52..03fa23a 100644 --- a/functions/auth/oauth_callback.py +++ b/functions/auth/oauth_callback.py @@ -3,7 +3,7 @@ import os import requests from firebase_functions import https_fn -from firebase_functions.params import SecretParam, StringParam, IntParam +from firebase_functions.params import SecretParam, StringParam from firebase_admin import auth, firestore import google.auth @@ -38,54 +38,73 @@ description="Comma-separated list of organizer Discord IDs. These users will be logged in as organizers.", ) -USERNAME_COL_R = IntParam( +USERNAME_COL_R = StringParam( "USERNAME_COL_R", - default=6, - description="The zero-based index of the column containing Discord usernames in the Registrations sheet.", + default="Discord", + description="The header name of the column containing Discord usernames in the Registrations sheet.", ) -SHIRT_SIZE_COL_R = IntParam( +SHIRT_SIZE_COL_R = StringParam( "SHIRT_SIZE_COL_R", - default=16, - description="The zero-based index of the column containing shirt sizes in the Registrations sheet.", + default="Shirt Size", + description="The header name of the column containing shirt sizes in the Registrations sheet.", ) -CHECKED_IN_COL_C = IntParam( +CHECKED_IN_COL_C = StringParam( "CHECKED_IN_COL_C", - default=0, - description="The zero-based index of the column indicating whether the participant has checked in.", + default="Checked in", + description="The header name of the column indicating whether the participant has checked in.", ) -FIRST_NAME_COL_C = IntParam( +FIRST_NAME_COL_C = StringParam( "FIRST_NAME_COL_C", - default=1, - description="The zero-based index of the column containing participants' first names.", + default="First Name", + description="The header name of the column containing participants' first names.", ) -LAST_NAME_COL_C = IntParam( +LAST_NAME_COL_C = StringParam( "LAST_NAME_COL_C", - default=2, - description="The zero-based index of the column containing participants' last names.", + default="Last Name", + description="The header name of the column containing participants' last names.", ) -PHONE_NUMBER_COL_C = IntParam( +PHONE_NUMBER_COL_C = StringParam( "PHONE_NUMBER_COL_C", - default=3, - description="The zero-based index of the column containing participants' phone numbers.", + default="Phone", + description="The header name of the column containing participants' phone numbers.", ) -EMAIL_COL_C = IntParam( +EMAIL_COL_C = StringParam( "EMAIL_COL_C", - default=4, - description="The zero-based index of the column containing participants' email addresses.", + default="Email", + description="The header name of the column containing participants' email addresses.", ) -DIETARY_RESTRICTIONS_COL_C = IntParam( +DIETARY_RESTRICTIONS_COL_C = StringParam( "DIETARY_RESTRICTIONS_COL_C", - default=5, - description="The zero-based index of the column containing participants' dietary restrictions.", + default="Dietary Restrictions", + description="The header name of the column containing participants' dietary restrictions.", ) -RFID_UUID_COL_C = IntParam( +RFID_UUID_COL_C = StringParam( "RFID_UUID_COL_C", - default=6, - description="The zero-based index of the column containing participants' RFID UUIDs.", + default="RFID UUID", + description="The header name of the column containing participants' RFID UUIDs.", ) +def _get_col_index_from_headers(headers: list[str], name: str) -> int: + """Return 1-based column index for a given header name. + + Matches case-insensitively and trims whitespace. Raises ValueError + if the header is not found. + """ + name_norm = name.strip().lower() + for i, h in enumerate(headers): + if h.strip().lower() == name_norm: + return i + 1 + raise ValueError("column_not_found") + + +def _get_cell_from_row(row: list[str], index_1based: int) -> str: + """Get cell value from row given a 1-based column index.""" + index_0based = index_1based - 1 + return row[index_0based] if len(row) > index_0based else "" + + def _get_registration(uid: str, username: str) -> User: """Gets a participant's registration and returns their User. Organizers will not need to be present on the spreadsheet @@ -115,7 +134,14 @@ def _get_registration(uid: str, username: str) -> User: reg_sheet = spreadsheet.worksheet("Registration Submissions") checkin_sheet = spreadsheet.worksheet("Check-in") - cell = reg_sheet.find(username, in_column=USERNAME_COL_R.value + 1) + reg_headers = reg_sheet.row_values(1) + checkin_headers = checkin_sheet.row_values(1) + + username_col_idx = _get_col_index_from_headers( + reg_headers, USERNAME_COL_R.value + ) + + cell = reg_sheet.find(username, in_column=username_col_idx) # participant not registered if not cell: @@ -124,7 +150,10 @@ def _get_registration(uid: str, username: str) -> User: reg_row = reg_sheet.row_values(cell.row) checkin_row = checkin_sheet.row_values(cell.row) - checked_in = checkin_row[CHECKED_IN_COL_C.value] + checked_in_idx = _get_col_index_from_headers( + checkin_headers, CHECKED_IN_COL_C.value + ) + checked_in = _get_cell_from_row(checkin_row, checked_in_idx) # participant did not check in if str(checked_in).upper() != "TRUE": @@ -132,14 +161,36 @@ def _get_registration(uid: str, username: str) -> User: "not_checked_in", ) - shirt_size = reg_row[SHIRT_SIZE_COL_R.value] + shirt_size_idx = _get_col_index_from_headers( + reg_headers, SHIRT_SIZE_COL_R.value + ) + shirt_size = _get_cell_from_row(reg_row, shirt_size_idx) + + email_idx = _get_col_index_from_headers(checkin_headers, EMAIL_COL_C.value) + email = _get_cell_from_row(checkin_row, email_idx) + + first_name_idx = _get_col_index_from_headers( + checkin_headers, FIRST_NAME_COL_C.value + ) + first_name = _get_cell_from_row(checkin_row, first_name_idx) + + last_name_idx = _get_col_index_from_headers( + checkin_headers, LAST_NAME_COL_C.value + ) + last_name = _get_cell_from_row(checkin_row, last_name_idx) + + phone_idx = _get_col_index_from_headers( + checkin_headers, PHONE_NUMBER_COL_C.value + ) + phone = _get_cell_from_row(checkin_row, phone_idx) + + dietary_idx = _get_col_index_from_headers( + checkin_headers, DIETARY_RESTRICTIONS_COL_C.value + ) + dietary_restrictions = _get_cell_from_row(checkin_row, dietary_idx) - email = checkin_row[EMAIL_COL_C.value] - first_name = checkin_row[FIRST_NAME_COL_C.value] - last_name = checkin_row[LAST_NAME_COL_C.value] - phone = checkin_row[PHONE_NUMBER_COL_C.value] - dietary_restrictions = checkin_row[DIETARY_RESTRICTIONS_COL_C.value] - rfid_uuid = checkin_row[RFID_UUID_COL_C.value] + rfid_idx = _get_col_index_from_headers(checkin_headers, RFID_UUID_COL_C.value) + rfid_uuid = _get_cell_from_row(checkin_row, rfid_idx) print( email, From 1a31b4bf0100dd4d7287b840372dc88dd0469068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Fri, 19 Dec 2025 17:21:22 -0800 Subject: [PATCH 020/114] Add adaptive UI --- src/pages/Home/index.tsx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 4e8475c..77125ff 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -75,7 +75,7 @@ export default function Home() { ); return ( -
+

Hack_NCState Today

@@ -83,7 +83,7 @@ export default function Home() {

- +
{sidebarFooter}
+ -
-

Main content area

{user?.username} -
+
+
+

Main content area

{user?.username} +
+ + +
); } From 71a2e9e3c61a5c47f3f5449c6546755db1849ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Fri, 19 Dec 2025 19:58:09 -0800 Subject: [PATCH 021/114] Refactor and add schedule UI --- src/components/ui/timeline.tsx | 57 +++++ src/pages/Home/components/Main/FeedItem.tsx | 20 ++ src/pages/Home/components/Main/index.tsx | 28 +++ .../Home/{ => components/Nav}/Countdown.tsx | 0 .../{ => components/Nav}/ResourcesList.tsx | 0 .../Nav}/ResourcesListSection.tsx | 0 src/pages/Home/components/Nav/index.tsx | 105 +++++++++ src/pages/Home/components/Schedule/index.tsx | 215 ++++++++++++++++++ src/pages/Home/index.tsx | 115 +--------- 9 files changed, 433 insertions(+), 107 deletions(-) create mode 100644 src/components/ui/timeline.tsx create mode 100644 src/pages/Home/components/Main/FeedItem.tsx create mode 100644 src/pages/Home/components/Main/index.tsx rename src/pages/Home/{ => components/Nav}/Countdown.tsx (100%) rename src/pages/Home/{ => components/Nav}/ResourcesList.tsx (100%) rename src/pages/Home/{ => components/Nav}/ResourcesListSection.tsx (100%) create mode 100644 src/pages/Home/components/Nav/index.tsx create mode 100644 src/pages/Home/components/Schedule/index.tsx diff --git a/src/components/ui/timeline.tsx b/src/components/ui/timeline.tsx new file mode 100644 index 0000000..fb99b24 --- /dev/null +++ b/src/components/ui/timeline.tsx @@ -0,0 +1,57 @@ +import { cn } from "@/lib/utils"; +import React from "react"; + +interface TimelineItemProps extends React.HTMLAttributes { + time: string; + title: string; + description?: string; + state?: "upcoming" | "current" | "passed"; +} + +export const TimelineItem = React.forwardRef( + ( + { time, title, description, state = "upcoming", className, ...props }, + ref, + ) => { + return ( +
+
+
+
+ +
+ +
+ + {time} + +

{title}

+ {description && ( +

{description}

+ )} +
+
+ ); + }, +); +TimelineItem.displayName = "TimelineItem"; + +export function Timeline({ children }: { children: React.ReactNode }) { + return
{children}
; +} diff --git a/src/pages/Home/components/Main/FeedItem.tsx b/src/pages/Home/components/Main/FeedItem.tsx new file mode 100644 index 0000000..7490300 --- /dev/null +++ b/src/pages/Home/components/Main/FeedItem.tsx @@ -0,0 +1,20 @@ +interface FeedItemProps { + title: string; + description: string; + children?: React.ReactNode; +} + +export default function FeedItem({ + title, + description, + children, +}: FeedItemProps) { + return ( +
+

{title}

+

{description}

+ +
{children}
+
+ ); +} diff --git a/src/pages/Home/components/Main/index.tsx b/src/pages/Home/components/Main/index.tsx new file mode 100644 index 0000000..fe3447f --- /dev/null +++ b/src/pages/Home/components/Main/index.tsx @@ -0,0 +1,28 @@ +import FeedItem from "./FeedItem"; + +export default function Main() { + return ( +
+ +

No new announcements.

+
+ + +

Sample text within this space.

+
+ + +

Sample text within this space.

+
+
+ ); +} diff --git a/src/pages/Home/Countdown.tsx b/src/pages/Home/components/Nav/Countdown.tsx similarity index 100% rename from src/pages/Home/Countdown.tsx rename to src/pages/Home/components/Nav/Countdown.tsx diff --git a/src/pages/Home/ResourcesList.tsx b/src/pages/Home/components/Nav/ResourcesList.tsx similarity index 100% rename from src/pages/Home/ResourcesList.tsx rename to src/pages/Home/components/Nav/ResourcesList.tsx diff --git a/src/pages/Home/ResourcesListSection.tsx b/src/pages/Home/components/Nav/ResourcesListSection.tsx similarity index 100% rename from src/pages/Home/ResourcesListSection.tsx rename to src/pages/Home/components/Nav/ResourcesListSection.tsx diff --git a/src/pages/Home/components/Nav/index.tsx b/src/pages/Home/components/Nav/index.tsx new file mode 100644 index 0000000..d0794ff --- /dev/null +++ b/src/pages/Home/components/Nav/index.tsx @@ -0,0 +1,105 @@ +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; +import Countdown from "./Countdown"; +import { MenuIcon } from "lucide-react"; +import ResourcesList from "./ResourcesList"; +import { authService } from "@/services/auth.service"; + +export default function Nav() { + const sampleResourcesSection = [ + { + title: "Resources", + items: [ + { + label: "Rules", + href: "#", + }, + { + label: "Tracks", + href: "#", + }, + { + label: "Opening Slides", + href: "#", + }, + { + label: "Judging Criteria", + href: "#", + }, + ], + }, + { + title: "Quick Links", + items: [ + { + label: "Discord Server", + href: "#", + }, + { + label: "Catering Menu", + href: "#", + }, + ], + }, + { + title: "System", + items: [ + { + label: "Log out", + href: () => authService.logout(), + }, + { + label: "About", + href: () => alert("HackNC 2024 - Powered by NC State University"), + }, + ], + }, + ]; + + const resourcesContent = ; + + const sidebarFooter = ( +
+ Hack_NCState Today +
+ ); + + return ( + + ); +} diff --git a/src/pages/Home/components/Schedule/index.tsx b/src/pages/Home/components/Schedule/index.tsx new file mode 100644 index 0000000..0c02c7d --- /dev/null +++ b/src/pages/Home/components/Schedule/index.tsx @@ -0,0 +1,215 @@ +import { Timeline, TimelineItem } from "@/components/ui/timeline"; +import { useEffect, useRef } from "react"; + +type ScheduleItem = { + time: string; + title: string; + description: string; + state: "upcoming" | "current" | "passed"; +}; + +type DaySchedule = { + day: string; + items: ScheduleItem[]; +}; + +const scheduleData: DaySchedule[] = [ + { + day: "Day 1", + items: [ + { + time: "09:00 AM", + title: "Check-in Starts", + description: "Outside State Ballroom", + state: "passed", + }, + { + time: "10:00 AM", + title: "Opening Ceremony", + description: "State Ballroom", + state: "passed", + }, + { + time: "10:30 AM", + title: "Team Formation", + description: "State Ballroom", + state: "passed", + }, + { + time: "11:00 AM", + title: "Competition Begins", + description: "All Venues", + state: "current", + }, + { + time: "12:00 PM", + title: "Lunch", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "02:00 PM", + title: "Sponsor Workshop/Panel #1", + description: "Talley Conference Room", + state: "upcoming", + }, + { + time: "03:00 PM", + title: "Sponsor Workshop/Panel #2", + description: "Talley Conference Room", + state: "upcoming", + }, + { + time: "04:00 PM", + title: "Sponsor Workshop/Panel #3", + description: "Talley Conference Room", + state: "upcoming", + }, + { + time: "06:00 PM", + title: "Dinner", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "06:05 PM", + title: "Sponsor-led Dinner Activity", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "07:00 PM", + title: "Sponsor Workshop/Panel #4", + description: "Talley Conference Room", + state: "upcoming", + }, + { + time: "09:00 PM", + title: "Midnight Game Event", + description: "State Ballroom", + state: "upcoming", + }, + ], + }, + { + day: "Day 2", + items: [ + { + time: "12:00 AM", + title: "Overnight Work Time", + description: "Across Talley", + state: "upcoming", + }, + { + time: "09:00 AM", + title: "Breakfast", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "11:00 AM", + title: "Project Submission", + description: "Through DevPost", + state: "upcoming", + }, + { + time: "12:00 PM", + title: "Lunch", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "01:00 PM", + title: "Judging Starts", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "03:00 PM", + title: "Judging Ends", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "04:00 PM", + title: "Closing Ceremony", + description: "State Ballroom", + state: "upcoming", + }, + { + time: "05:00 PM", + title: "Event Ends", + description: "All Venues", + state: "upcoming", + }, + ], + }, +]; + +export default function Schedule() { + const containerRef = useRef(null); + const currentItemRef = useRef(null); + + useEffect(() => { + if (currentItemRef.current && containerRef.current) { + // Check if screen is lg (1024px) or larger + if (window.matchMedia("(min-width: 1024px)").matches) { + const container = containerRef.current; + const item = currentItemRef.current; + + const containerRect = container.getBoundingClientRect(); + const itemRect = item.getBoundingClientRect(); + + // Calculate the position of the item relative to the container's current scroll position + const relativeTop = itemRect.top - containerRect.top; + const currentScrollTop = container.scrollTop; + + // Scroll so item is in the middle + container.scrollTo({ + top: + currentScrollTop + + relativeTop - + container.clientHeight / 2 + + item.clientHeight / 2, + behavior: "smooth", + }); + } + } + }, [scheduleData]); + + return ( + + ); +} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 77125ff..35de627 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,79 +1,13 @@ -import { MenuIcon } from "lucide-react"; -import Countdown from "./Countdown"; -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, - SheetTrigger, -} from "@/components/ui/sheet"; -import ResourcesList from "./ResourcesList"; -import { authService } from "@/services/auth.service"; import { useAtomValue } from "jotai"; import { userAtom } from "@/atoms/user"; +import FeedItem from "./components/Main/FeedItem"; +import Schedule from "./components/Schedule"; +import Nav from "./components/Nav"; +import Main from "./components/Main"; export default function Home() { - const sampleResourcesSection = [ - { - title: "Resources", - items: [ - { - label: "Rules", - href: "#", - }, - { - label: "Tracks", - href: "#", - }, - { - label: "Opening Slides", - href: "#", - }, - { - label: "Judging Criteria", - href: "#", - }, - ], - }, - { - title: "Quick Links", - items: [ - { - label: "Discord Server", - href: "#", - }, - { - label: "Catering Menu", - href: "#", - }, - ], - }, - { - title: "System", - items: [ - { - label: "Log out", - href: () => authService.logout(), - }, - { - label: "About", - href: () => alert("HackNC 2024 - Powered by NC State University"), - }, - ], - }, - ]; - const user = useAtomValue(userAtom); - const resourcesContent = ; - - const sidebarFooter = ( -
- Hack_NCState Today -
- ); - return (
@@ -83,45 +17,12 @@ export default function Home() {
- +
); From e069513cbf82ee250c79bc8ff9c1b26fe0784a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Tue, 23 Dec 2025 17:38:49 -0800 Subject: [PATCH 032/114] Add new event atoms --- src/atoms/event.ts | 37 +++++++++++++++++-- .../Home/Main/AnnouncementsView/index.tsx | 1 - src/pages/Home/Main/OrganizerView/index.tsx | 27 +++++++------- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/atoms/event.ts b/src/atoms/event.ts index 26f62a0..9cdea93 100644 --- a/src/atoms/event.ts +++ b/src/atoms/event.ts @@ -1,10 +1,41 @@ +import { firestoreService } from "@/services/firestore.service"; import type { EventConfig } from "@/types/event"; import { atom } from "jotai"; // undefined = loading, null = no config (should create one i reckon), EventConfig = config export const eventConfigAtom = atom(undefined); +export const updateEventConfigAtom = atom( + null, + async (_, __, updatedConfig: Partial | null) => { + if (updatedConfig === null) { + await firestoreService.clearEventConfig(); + return; + } + + await firestoreService.updateEventConfig(updatedConfig); + }, +); + export const announcementsAtom = atom((get) => { - const config = get(eventConfigAtom); - return config?.announcements ?? []; -}); \ No newline at end of file + const config = get(eventConfigAtom); + return config?.announcements ?? []; +}); + +export const deleteAnnouncementAtom = atom( + null, + async (get, _, index: string) => { + const announcements = get(announcementsAtom); + if (!announcements) return; + + const updatedAnnouncements = announcements.filter( + (_, i) => i.toString() !== index, + ); + + const updatedConfig = { + announcements: updatedAnnouncements, + }; + + await firestoreService.updateEventConfig(updatedConfig); + }, +); diff --git a/src/pages/Home/Main/AnnouncementsView/index.tsx b/src/pages/Home/Main/AnnouncementsView/index.tsx index f0647b8..370b296 100644 --- a/src/pages/Home/Main/AnnouncementsView/index.tsx +++ b/src/pages/Home/Main/AnnouncementsView/index.tsx @@ -7,7 +7,6 @@ import { useAtomValue } from "jotai"; import { Dialog, DialogContent, - DialogDescription, DialogHeader, DialogTitle, DialogTrigger, diff --git a/src/pages/Home/Main/OrganizerView/index.tsx b/src/pages/Home/Main/OrganizerView/index.tsx index b47a64f..b62868e 100644 --- a/src/pages/Home/Main/OrganizerView/index.tsx +++ b/src/pages/Home/Main/OrganizerView/index.tsx @@ -1,19 +1,20 @@ import { Button } from "@/components/ui/button"; import { ButtonGroup } from "@/components/ui/button-group"; import { Input } from "@/components/ui/input"; -import { firestoreService } from "@/services/firestore.service"; import { EventConfigSchema } from "@/types/event"; import { SendIcon } from "lucide-react"; import { useEffect, useState } from "react"; import FeedItem from "../FeedItem"; import HackingDatesPicker from "./HackingDatesPicker"; import { Label } from "@/components/ui/label"; -import { useAtomValue } from "jotai"; -import { eventConfigAtom } from "@/atoms/event"; +import { useAtomValue, useSetAtom } from "jotai"; +import { eventConfigAtom, updateEventConfigAtom } from "@/atoms/event"; import { useBreakpoint } from "@/hooks/use-media-query"; export default function OrganizerView() { const config = useAtomValue(eventConfigAtom); + const updateConfig = useSetAtom(updateEventConfigAtom); + const isDesktop = useBreakpoint("lg"); const [announcementText, setAnnouncementText] = useState(""); @@ -35,11 +36,11 @@ export default function OrganizerView() { resources: [], }); - firestoreService.updateEventConfig(defaultConfig); + updateConfig(defaultConfig); console.log("No event config found, initializing default config"); } - }, [config]); + }, [config, updateConfig]); const handlePostAnnouncement = (e: React.FormEvent) => { // should also handle sending to discord webhook @@ -52,7 +53,7 @@ export default function OrganizerView() { timestamp: new Date().toISOString(), }; - firestoreService.updateEventConfig({ + updateConfig({ announcements: [newAnnouncement, ...config.announcements], }); setAnnouncementText(""); @@ -102,7 +103,7 @@ export default function OrganizerView() { : undefined } onStartDateChange={(date) => - firestoreService.updateEventConfig({ + updateConfig({ hackingStartTime: date?.toISOString(), }) } @@ -110,7 +111,7 @@ export default function OrganizerView() { config.hackingEndTime ? new Date(config.hackingEndTime) : undefined } onEndDateChange={(date) => - firestoreService.updateEventConfig({ + updateConfig({ hackingEndTime: date?.toISOString(), }) } @@ -121,7 +122,7 @@ export default function OrganizerView() { @@ -133,7 +134,7 @@ export default function OrganizerView() { All Announcements +
{announcements.map((announcement, index) => ( -

- - {formatAnnouncementTime(announcement.timestamp)} - - — {announcement.content} -

+ {isOrganizer && ( + + )} +

+ + {formatAnnouncementTime(announcement.timestamp)} + + — {announcement.content} +

+
))}
diff --git a/src/pages/Home/Main/index.tsx b/src/pages/Home/Main/index.tsx index b304b82..fa394bf 100644 --- a/src/pages/Home/Main/index.tsx +++ b/src/pages/Home/Main/index.tsx @@ -1,6 +1,6 @@ import { useAtomValue } from "jotai"; import FeedItem from "./FeedItem"; -import { userAtom } from "@/atoms/user"; +import { isOrganizerAtom } from "@/atoms/user"; import OrganizerView from "./OrganizerView"; import AnnouncementCard from "./AnnouncementsView/AnnouncementCard"; import { Button } from "@/components/ui/button"; @@ -8,11 +8,11 @@ import { Maximize2 } from "lucide-react"; import AnnouncementsView from "./AnnouncementsView"; export default function Main() { - const user = useAtomValue(userAtom); + const isOrganizer = useAtomValue(isOrganizerAtom); return (
- {user?.role === "organizer" && ( + {isOrganizer && ( <> From 76542ccd853eb4fe6b0001dc012fa0564ef17041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Tue, 23 Dec 2025 18:04:54 -0800 Subject: [PATCH 034/114] Rename media query file --- src/hooks/{use-media-query.ts => useMediaQuery.ts} | 0 src/pages/Home/Main/OrganizerView/index.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/hooks/{use-media-query.ts => useMediaQuery.ts} (100%) diff --git a/src/hooks/use-media-query.ts b/src/hooks/useMediaQuery.ts similarity index 100% rename from src/hooks/use-media-query.ts rename to src/hooks/useMediaQuery.ts diff --git a/src/pages/Home/Main/OrganizerView/index.tsx b/src/pages/Home/Main/OrganizerView/index.tsx index b62868e..fabc1c5 100644 --- a/src/pages/Home/Main/OrganizerView/index.tsx +++ b/src/pages/Home/Main/OrganizerView/index.tsx @@ -9,7 +9,7 @@ import HackingDatesPicker from "./HackingDatesPicker"; import { Label } from "@/components/ui/label"; import { useAtomValue, useSetAtom } from "jotai"; import { eventConfigAtom, updateEventConfigAtom } from "@/atoms/event"; -import { useBreakpoint } from "@/hooks/use-media-query"; +import { useBreakpoint } from "@/hooks/useMediaQuery"; export default function OrganizerView() { const config = useAtomValue(eventConfigAtom); From 0a00c45724bcf7a40d9bf490560538cc25dd84d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Tue, 23 Dec 2025 18:14:06 -0800 Subject: [PATCH 035/114] Set up resource atoms --- src/atoms/event.ts | 49 ++++++++++++++++--- .../OrganizerView/ResourceEditorDialog.tsx | 0 src/types/event.ts | 19 ++++++- 3 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/pages/Home/Main/OrganizerView/ResourceEditorDialog.tsx diff --git a/src/atoms/event.ts b/src/atoms/event.ts index ecb03b5..ff28f87 100644 --- a/src/atoms/event.ts +++ b/src/atoms/event.ts @@ -1,5 +1,5 @@ import { firestoreService } from "@/services/firestore.service"; -import type { EventConfig } from "@/types/event"; +import type { EventConfig, Resource } from "@/types/event"; import { atom } from "jotai"; // undefined = loading, null = no config (should create one i reckon), EventConfig = config @@ -28,14 +28,49 @@ export const deleteAnnouncementAtom = atom( const announcements = get(announcementsAtom); if (!announcements) return; - const updatedAnnouncements = announcements.filter( - (_, i) => i !== index, - ); + const updatedAnnouncements = announcements.filter((_, i) => i !== index); - const updatedConfig = { + await firestoreService.updateEventConfig({ announcements: updatedAnnouncements, - }; + }); + }, +); - await firestoreService.updateEventConfig(updatedConfig); +export const resourcesAtom = atom((get) => { + const config = get(eventConfigAtom); + return config?.resources ?? []; +}); + +export const addResourceAtom = atom( + null, + async (get, _, resource: Resource) => { + const resources = get(resourcesAtom); + + const updatedResources = [resource, ...resources]; + + await firestoreService.updateEventConfig({ resources: updatedResources }); + }, +); + +export const deleteResourceAtom = atom(null, async (get, _, index: number) => { + const resources = get(resourcesAtom); + if (!resources) return; + + const updatedResources = resources.filter((_, i) => i !== index); + + await firestoreService.updateEventConfig({ resources: updatedResources }); +}); + +export const setResourceAtom = atom( + null, + async (get, _, payload: { index: number; resource: Resource }) => { + const resources = get(resourcesAtom); + if (!resources) return; + + const updatedResources = resources.map((res, i) => + i === payload.index ? payload.resource : res, + ); + + await firestoreService.updateEventConfig({ resources: updatedResources }); }, ); diff --git a/src/pages/Home/Main/OrganizerView/ResourceEditorDialog.tsx b/src/pages/Home/Main/OrganizerView/ResourceEditorDialog.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/types/event.ts b/src/types/event.ts index 035608c..932a3a2 100644 --- a/src/types/event.ts +++ b/src/types/event.ts @@ -21,11 +21,26 @@ export const AnnouncementSchema = z.object({ timestamp: z.iso.datetime(), }); -export const ResourceSchema = z.object({ +export const BaseResourceSchema = z.object({ label: z.string(), - href: z.url(), + hidden: z.boolean().default(false), }); +export const LinkResourceSchema = BaseResourceSchema.extend({ + type: z.literal("link"), + url: z.url(), +}); + +export const TextResourceSchema = BaseResourceSchema.extend({ + type: z.literal("text"), + content: z.string(), +}); + +export const ResourceSchema = z.discriminatedUnion("type", [ + LinkResourceSchema, + TextResourceSchema, +]); + export const EventConfigSchema = z.object({ hackingState: z.enum(["setup", "started", "judging", "ended"]), hackingStartTime: z.iso.datetime(), From 4db7b34ec4843c9ee0706600afb6761dd60d709f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Koray=20=C3=96zturkler?= Date: Tue, 23 Dec 2025 18:49:03 -0800 Subject: [PATCH 036/114] Add resource manager UI --- package-lock.json | 196 +++++++++++++++ package.json | 2 + src/atoms/event.ts | 1 + src/components/ui/checkbox.tsx | 30 +++ src/components/ui/select.tsx | 188 ++++++++++++++ src/components/ui/textarea.tsx | 18 ++ .../Main/OrganizerView/ResourceEditor.tsx | 232 ++++++++++++++++++ .../OrganizerView/ResourceEditorDialog.tsx | 0 src/pages/Home/Main/OrganizerView/index.tsx | 43 ++-- 9 files changed, 693 insertions(+), 17 deletions(-) create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/pages/Home/Main/OrganizerView/ResourceEditor.tsx delete mode 100644 src/pages/Home/Main/OrganizerView/ResourceEditorDialog.tsx diff --git a/package-lock.json b/package-lock.json index d20d616..3ded640 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "version": "0.0.0", "dependencies": { "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@tailwindcss/vite": "^4.1.14", @@ -2334,6 +2336,12 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", @@ -2409,6 +2417,80 @@ } } }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -2493,6 +2575,21 @@ } } }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-dismissable-layer": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", @@ -2800,6 +2897,67 @@ } } }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", @@ -2949,6 +3107,21 @@ } } }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-rect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", @@ -2985,6 +3158,29 @@ } } }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/rect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", diff --git a/package.json b/package.json index 9e4158e..6806ec0 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ }, "dependencies": { "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@tailwindcss/vite": "^4.1.14", diff --git a/src/atoms/event.ts b/src/atoms/event.ts index ff28f87..444b82f 100644 --- a/src/atoms/event.ts +++ b/src/atoms/event.ts @@ -61,6 +61,7 @@ export const deleteResourceAtom = atom(null, async (get, _, index: number) => { await firestoreService.updateEventConfig({ resources: updatedResources }); }); +// TODO: add reorderResourceAtom? export const setResourceAtom = atom( null, async (get, _, payload: { index: number; resource: Resource }) => { diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..0e2a6cd --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,30 @@ +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Checkbox({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + + ) +} + +export { Checkbox } diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx new file mode 100644 index 0000000..b8aab97 --- /dev/null +++ b/src/components/ui/select.tsx @@ -0,0 +1,188 @@ +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Select({ + ...props +}: React.ComponentProps) { + return +} + +function SelectGroup({ + ...props +}: React.ComponentProps) { + return +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default" +}) { + return ( + + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "item-aligned", + align = "center", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx new file mode 100644 index 0000000..7f21b5e --- /dev/null +++ b/src/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +