diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..cda6db4 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,49 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.12.3" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 djangorestframework psycopg2-binary pytest-django + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Create test settings.py + run: | + cp backend/settings_template.txt backend/settings.py + # use sed to use SQLite for testing + sed -i "s/'ENGINE': 'django.db.backends.postgresql'/'ENGINE': 'django.db.backends.sqlite3'/g" backend/settings.py + sed -i "s/'NAME': 'your_database_name'/'NAME': ':memory:'/g" backend/settings.py + - name: Make and run migrations + run: | + python manage.py makemigrations + python manage.py migrate + - name: Test with pytest + run: | + pytest diff --git a/.gitignore b/.gitignore index cabf345..acf3a81 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ backend/__pycache/* # personal settings backend/settings.py +# pytest +.pytest_cache/ +*.py[cod] + # Personal Migrations backend/quickstart/migrations/* diff --git a/README.md b/README.md index 3f02ec5..96c08d5 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,13 @@ This will generate the build files in the `build` directory. - `tsconfig.json`: TypeScript configuration file. - `package.json`: Contains the project dependencies and scripts. -## Backend (Windows/Linux) +### Contributing + +When making a pull request to the frontend, you *must* follow these rules to ensure your PR is not automatically rejected: +- Pull requests must be made to the `dev` branch, *NOT* `main`. +- Pull requests must include an image of the changes made to the frontend. + +## Backend (Windows/ Generic Linux) ### Prerequisites This guide expects that you have [Python](https://www.python.org/downloads/) (At least 3.12.0) installed. @@ -233,3 +239,98 @@ If Python was installed via either Homebrew or the official Python installer, yo ``` If it all goes well, cool stuff, it's working! + +### Setup (Arch Linux) + +- This guide assumes an installation using `systemd`. If you're using something else like OpenRC or runit, tweak the `systemctl` commands accordingly. + +1. **Create the venv** + + ```sh + cd Studygatchi + python3 -m venv env + ``` + + ```sh + source ./env/bin/activate + ``` + + +2. **Run the following command to install Django and the Django Rest Framework:** + + ```sh + pip install django djangorestframework + ``` + +3. **Install PostgreSQL (version 17)** + + ```sh + pacman -Syu postgresql + ``` + + +4. **Activate the venv (if it's not already active) using the corresponding command and install psycopg2** + + ```sh + pip install psycopg2-binary + ``` + + We will use this to be able to connect Django with Postgres! + +5. **Initialize the database cluster** + + ```sh + sudo -u postgres initdb -D /var/lib/postgres/data + ``` + +6. **Start the PostgreSQL service** + + ```sh + sudo systemctl start postgresql + ``` + + - It's optional, but recommended that you have PostgreSQL run at startup: + + ```sh + sudo systemctl enable postgresql + ``` + +7. **Access the PostgreSQL shell, logged in as the superuser:** + + ```sh + psql -U postgres + ``` + +8. **Run the following SQL commands:** + + ```sql + CREATE USER WITH PASSWORD ''; + CREATE DATABASE studygatchi_db OWNER ; + GRANT ALL PRIVILEGES ON DATABASE studygatchi_db TO ; + \q + ``` + Replace `` with whatever username you want, and likewise for the password. + +9. **In the backend directory, create a file called `settings.py` with the contents of `settings_template.txt`.** + + ```sh + cd backend/ + cp settings_template.txt settings.py + ``` + +10. **In `settings.py`, go to where it says `DATABASES`, and insert your info from step 6 into the corresponding places.** + +11. **At the root of the project, run the following commands** ***with the venv active*** **to apply migrations:** + + ```sh + python3 manage.py makemigrations + python3 manage.py migrate + ``` + +12. **Test the connection by running this command:** + + ```sh + python3 manage.py runserver + ``` + + If it all goes well, cool stuff; it's working! diff --git a/backend/api.py b/backend/api.py index a427e2f..782d4d7 100644 --- a/backend/api.py +++ b/backend/api.py @@ -3,4 +3,5 @@ urlpatterns = [ path("ping/", ping), + path("create_task/", create_task), ] diff --git a/backend/quickstart/admin.py b/backend/quickstart/admin.py index 8c38f3f..723d07a 100644 --- a/backend/quickstart/admin.py +++ b/backend/quickstart/admin.py @@ -1,3 +1,7 @@ from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import StudyUser + +admin.site.register(StudyUser, UserAdmin) # Register your models here. diff --git a/backend/quickstart/models.py b/backend/quickstart/models.py index 03b1a92..ac31acb 100644 --- a/backend/quickstart/models.py +++ b/backend/quickstart/models.py @@ -1,9 +1,9 @@ from django.db import models -from django.contrib.auth.models import User +from django.contrib.auth.models import AbstractUser # Create your models here. -class StudyUser(User): +class StudyUser(AbstractUser): # inherits: username, password, email, ... money = models.IntegerField(default=100) @@ -14,4 +14,4 @@ class Task(models.Model): category = models.TextField(null=True) due_date = models.DateTimeField() description = models.TextField() - username = models.ForeignKey(StudyUser, on_delete=models.CASCADE) + user = models.ForeignKey(StudyUser, on_delete=models.CASCADE) diff --git a/backend/quickstart/serializers.py b/backend/quickstart/serializers.py new file mode 100644 index 0000000..c34aed4 --- /dev/null +++ b/backend/quickstart/serializers.py @@ -0,0 +1,11 @@ +from .models import Task +from rest_framework import serializers + +# serializers are cool because they allow you to skip having to deal with the model constructors + +class TaskSerializer(serializers.HyperlinkedModelSerializer): + user = serializers.HiddenField(default=serializers.CurrentUserDefault()) + + class Meta: + model = Task + fields = ["reward", "name", "category", "due_date", "description", "user"] \ No newline at end of file diff --git a/backend/quickstart/tests.py b/backend/quickstart/tests.py index 7ce503c..876257f 100644 --- a/backend/quickstart/tests.py +++ b/backend/quickstart/tests.py @@ -1,3 +1,55 @@ -from django.test import TestCase +# Some tests created with aid from Gemini +import pytest +from rest_framework import status +from .models import StudyUser, Task + +@pytest.fixture +def api_client(): + from rest_framework.test import APIClient + return APIClient() + +@pytest.fixture +def test_user(db): + """Creates a StudyUser for testing.""" + return StudyUser.objects.create_user( + username="andres", + password="password123", + money=500 + ) + +@pytest.mark.django_db +class TestTaskCreation: + def test_create_task_authenticated(self, api_client, test_user): + # 1. Authenticate + api_client.force_authenticate(user=test_user) + + # 2. Prepare Data (No user info in JSON, handled by CurrentUserDefault) + url = "/api/create_task/" # Ensure this matches your urls.py + data = { + "name": "Math Homework", + "reward": 50, + "description": "Finish algebra 1", + "due_date": "2026-12-31" + } + + # 3. Request + response = api_client.post(url, data, format='json') + + # 4. Assertions + assert response.status_code == status.HTTP_201_CREATED + + # Verify DB entry + task = Task.objects.get(name="Math Homework") + assert task.user == test_user + assert task.user.money == 500 + + def test_create_task_unauthenticated(self, api_client): + """Ensure logged-out users can't create tasks.""" + url = "/api/create_task/" + data = {"name": "Ghost Task"} + + response = api_client.post(url, data, format='json') + + assert response.status_code == status.HTTP_403_FORBIDDEN # Create your tests here. diff --git a/backend/quickstart/views.py b/backend/quickstart/views.py index 4c9a04b..c2cfcc9 100644 --- a/backend/quickstart/views.py +++ b/backend/quickstart/views.py @@ -1,13 +1,27 @@ from django.shortcuts import render from rest_framework.response import Response -from rest_framework.decorators import api_view +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import IsAuthenticated from rest_framework import status -from .models import StudyUser + +from .models import StudyUser # remove, should be serializer +from .serializers import TaskSerializer # Create your views here. -@api_view(['GET',]) +@api_view(['GET']) def ping(request): - if request.method == 'GET': - print(type(StudyUser)) - return Response(b"pong") \ No newline at end of file + print(type(StudyUser)) + return Response("pong") + +@api_view(['POST']) # Some of this function was made with the help of Gemini +@permission_classes([IsAuthenticated]) +def create_task(request): + serializer = TaskSerializer(data=request.data, context={"request": request}) + + if serializer.is_valid(): + # save and return + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/backend/requirements.txt b/backend/requirements.txt index f646522..d5da976 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,4 +1,4 @@ django djangorestframework psycopg2-binary - +pytest-django diff --git a/backend/settings_template.txt b/backend/settings_template.txt index 216e5e9..51d9aee 100644 --- a/backend/settings_template.txt +++ b/backend/settings_template.txt @@ -85,6 +85,8 @@ DATABASES = { } } +AUTH_USER_MODEL = "quickstart.StudyUser" + # Password validation # https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators diff --git a/db.sqlite3 b/db.sqlite3 deleted file mode 100644 index de798d6..0000000 Binary files a/db.sqlite3 and /dev/null differ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c0ee928..f5d5e4c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,7 +18,8 @@ "tailwindcss": "^4.1.14" }, "devDependencies": { - "@types/chrome": "^0.1.4", + "@types/chrome": "^0.1.43", + "@types/firefox-webext-browser": "^143.0.0", "@types/node": "^24.9.2", "@types/react": "^19.1.12", "@types/react-dom": "^19.1.9", @@ -79,7 +80,6 @@ "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -838,9 +838,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -849,9 +849,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -909,9 +909,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -930,9 +930,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1141,9 +1141,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", - "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], @@ -1155,9 +1155,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", - "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], @@ -1169,9 +1169,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", - "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], @@ -1183,9 +1183,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", - "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], @@ -1197,9 +1197,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", - "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], @@ -1211,9 +1211,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", - "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], @@ -1225,13 +1225,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", - "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1239,13 +1242,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", - "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1253,13 +1259,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", - "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1267,27 +1276,50 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", - "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", - "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1295,13 +1327,33 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", - "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1309,13 +1361,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", - "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1323,13 +1378,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", - "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1337,13 +1395,16 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", - "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1351,13 +1412,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", - "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1365,23 +1429,40 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", - "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", - "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], @@ -1393,9 +1474,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", - "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], @@ -1407,9 +1488,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", - "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], @@ -1420,10 +1501,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", - "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], @@ -1480,9 +1575,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.4.tgz", - "integrity": "sha512-vfISO7SPppN3OKVUqWujtZ4vux3nhDqKaHYEHgfQuPARHuWJ3jjyc1s13H0ckzEc86/neTkCl1TeW72UK6jYKA==", + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.43.tgz", + "integrity": "sha512-ukH/HhmR6ht+UTX3PLUWJxgJ/RQcK2Foj4lBzsF24SIWsXgqhGuXqjd8FFuwioPP7d/JUKLM4g8GZxw3F4HTcA==", "dev": true, "license": "MIT", "dependencies": { @@ -1491,9 +1586,9 @@ } }, "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==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1514,6 +1609,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/firefox-webext-browser": { + "version": "143.0.0", + "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-143.0.0.tgz", + "integrity": "sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/har-format": { "version": "1.2.16", "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", @@ -1534,7 +1636,6 @@ "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1545,7 +1646,6 @@ "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1596,7 +1696,6 @@ "integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.41.0", "@typescript-eslint/types": "8.41.0", @@ -1823,7 +1922,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1842,9 +1940,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1935,9 +2033,9 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -1977,7 +2075,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", @@ -2121,12 +2218,16 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { @@ -2254,7 +2355,6 @@ "integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -2364,9 +2464,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -2398,9 +2498,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -2606,9 +2706,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -2800,10 +2900,20 @@ "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==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -2954,13 +3064,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2977,9 +3087,9 @@ "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==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -3132,9 +3242,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -3145,9 +3255,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -3165,7 +3275,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3219,7 +3329,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3247,9 +3356,9 @@ } }, "node_modules/react-router": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz", - "integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz", + "integrity": "sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -3269,12 +3378,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.5.tgz", - "integrity": "sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz", + "integrity": "sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==", "license": "MIT", "dependencies": { - "react-router": "7.9.5" + "react-router": "7.17.0" }, "engines": { "node": ">=20.0.0" @@ -3319,13 +3428,13 @@ } }, "node_modules/rollup": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", - "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -3335,27 +3444,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.0", - "@rollup/rollup-android-arm64": "4.50.0", - "@rollup/rollup-darwin-arm64": "4.50.0", - "@rollup/rollup-darwin-x64": "4.50.0", - "@rollup/rollup-freebsd-arm64": "4.50.0", - "@rollup/rollup-freebsd-x64": "4.50.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", - "@rollup/rollup-linux-arm-musleabihf": "4.50.0", - "@rollup/rollup-linux-arm64-gnu": "4.50.0", - "@rollup/rollup-linux-arm64-musl": "4.50.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", - "@rollup/rollup-linux-ppc64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-musl": "4.50.0", - "@rollup/rollup-linux-s390x-gnu": "4.50.0", - "@rollup/rollup-linux-x64-gnu": "4.50.0", - "@rollup/rollup-linux-x64-musl": "4.50.0", - "@rollup/rollup-openharmony-arm64": "4.50.0", - "@rollup/rollup-win32-arm64-msvc": "4.50.0", - "@rollup/rollup-win32-ia32-msvc": "4.50.0", - "@rollup/rollup-win32-x64-msvc": "4.50.0", + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" } }, @@ -3519,12 +3632,11 @@ } }, "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==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3587,7 +3699,6 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3655,12 +3766,11 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -3769,12 +3879,11 @@ } }, "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==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, diff --git a/frontend/package.json b/frontend/package.json index ea1997a..4487ade 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,8 @@ "tailwindcss": "^4.1.14" }, "devDependencies": { - "@types/chrome": "^0.1.4", + "@types/chrome": "^0.1.43", + "@types/firefox-webext-browser": "^143.0.0", "@types/node": "^24.9.2", "@types/react": "^19.1.12", "@types/react-dom": "^19.1.9", diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json index c085dd2..002172f 100644 --- a/frontend/public/manifest.json +++ b/frontend/public/manifest.json @@ -1,16 +1,25 @@ { - "manifest_version": 3, - "name": "Studygatchi", - "version": "1.0.0", - "description": "Virtual pet & study assistant", - "action": { - "default_popup": "index.html" - }, - "background": { - "service_worker": "background.js" - }, - "permissions": ["sidePanel"], - "side_panel": { - "default_path": "index.html" + "manifest_version": 3, + "name": "Studygatchi", + "version": "1.0.0", + "description": "Virtual pet & study assistant", + "action": { + "default_popup": "index.html" + }, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": ["https://*.instructure.com/*"], + "js": ["content.js"] } - } \ No newline at end of file + ], + "permissions": ["sidePanel", "storage", "tabs"], + "host_permissions": [ + "https://*.instructure.com/*" + ], + "side_panel": { + "default_path": "index.html" + } +} \ No newline at end of file diff --git a/frontend/src/App.css b/frontend/src/App.css index 0e0ea7b..1961075 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -32,6 +32,22 @@ padding: 2em; } +.card.bCard, +.card { + background-color: var(--card-bg) !important; + color: var(--text-color) !important; +} + +.card-header { + background-color: var(--bg-color) !important; + color: var(--text-color) !important; +} + +.card-body { + background-color: var(--card-bg) !important; + color: var(--text-color) !important; +} + .read-the-docs { color: #888; } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 2aa6c1e..c902b68 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,55 +1,58 @@ import "./App.css"; import { useState } from "react"; import SettingsMenu from "./components/SettingsMenu"; -import NavBar from "./components/NavBar"; // +import NavBar from "./components/NavBar"; import Home from "./components/Home"; import Timer from "./components/Timer"; import ToDoList from "./ToDoList"; import GooberMenu from "./components/GooberMenu"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; +import { ThemeProvider } from './components/ThemeProvider'; +import CanvasFetcher from './components/CanvasFetcher.tsx'; function App() { - // had to add because bootstrap defaults to light mode document.documentElement.setAttribute("data-bs-theme", "dark"); - // Current Players data const [currentXP, setXP] = useState(50); const [level, setLevel] = useState(9); const [money, setMoney] = useState(0); const [currentHealth, setHealth] = useState(50); return ( - -
-
- + + +
+
+ +
+ + + } /> + } /> + } /> + } /> + } /> + } /> +
- - - } /> - } /> - } /> - } /> - } /> - -
- + + ); } -export default App; +export default App; \ No newline at end of file diff --git a/frontend/src/assets/goober-doggo.png b/frontend/src/assets/goober-doggo.png new file mode 100644 index 0000000..562bac8 Binary files /dev/null and b/frontend/src/assets/goober-doggo.png differ diff --git a/frontend/src/assets/goobers/goober-bear.png b/frontend/src/assets/goobers/goober-bear.png new file mode 100644 index 0000000..84bb1ed Binary files /dev/null and b/frontend/src/assets/goobers/goober-bear.png differ diff --git a/frontend/src/assets/goobers/goober-cat.png b/frontend/src/assets/goobers/goober-cat.png new file mode 100644 index 0000000..3e0ef9f Binary files /dev/null and b/frontend/src/assets/goobers/goober-cat.png differ diff --git a/frontend/src/assets/goobers/goober-doggo.png b/frontend/src/assets/goobers/goober-doggo.png new file mode 100644 index 0000000..562bac8 Binary files /dev/null and b/frontend/src/assets/goobers/goober-doggo.png differ diff --git a/frontend/src/assets/goobers/goober-fox.png b/frontend/src/assets/goobers/goober-fox.png new file mode 100644 index 0000000..c628b75 Binary files /dev/null and b/frontend/src/assets/goobers/goober-fox.png differ diff --git a/frontend/src/assets/goobers/goober-panda.png b/frontend/src/assets/goobers/goober-panda.png new file mode 100644 index 0000000..8536496 Binary files /dev/null and b/frontend/src/assets/goobers/goober-panda.png differ diff --git a/frontend/src/components/CanvasFetcher.tsx b/frontend/src/components/CanvasFetcher.tsx new file mode 100644 index 0000000..dfb532d --- /dev/null +++ b/frontend/src/components/CanvasFetcher.tsx @@ -0,0 +1,76 @@ +import React, { useState } from 'react'; +import { browser } from '../lib/browser'; + +const CanvasFetcher: React.FC = () => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchCanvasData = async () => { + setLoading(true); + setError(null); + + try { + const startDate = '2026-06-07'; + const endDate = '2026-06-13'; + + // Get the active Canvas tab + const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); + + if (!tab?.id) { + throw new Error('No active tab found'); + } + + // Send message to content script + browser.tabs.sendMessage( + tab.id, + { action: 'fetchCanvasData', startDate, endDate }, + (response: any) => { + if (chrome.runtime.lastError) { + setError(chrome.runtime.lastError.message || 'Failed to communicate with Canvas'); + setLoading(false); + return; + } + + if (response?.success) { + setData(response.data); + } else { + setError(response?.error || 'Failed to fetch'); + } + setLoading(false); + } + ); + } catch (err) { + setError(err instanceof Error ? err.message : 'Unknown error'); + setLoading(false); + } + }; + + return ( +
+

Canvas Data Fetcher

+ + + {error &&

Error: {error}

} + + {data && ( +
+

Found {data.length} items:

+
+            {JSON.stringify(data, null, 2)}
+          
+
+ )} +
+ ); +}; + +export default CanvasFetcher; \ No newline at end of file diff --git a/frontend/src/components/GooberFoodMenu.tsx b/frontend/src/components/GooberFoodMenu.tsx index 4bae68d..5b16850 100644 --- a/frontend/src/components/GooberFoodMenu.tsx +++ b/frontend/src/components/GooberFoodMenu.tsx @@ -5,8 +5,10 @@ interface Props { export default function GooberFoodMenu({ pageSetter }: Props) { return ( <> - place gober food menu here - +
+ place gober food menu here + +
); } diff --git a/frontend/src/components/GooberGiftMenu.tsx b/frontend/src/components/GooberGiftMenu.tsx index 862bc28..86b5861 100644 --- a/frontend/src/components/GooberGiftMenu.tsx +++ b/frontend/src/components/GooberGiftMenu.tsx @@ -5,8 +5,10 @@ interface Props { export default function GooberGiftMenu({ pageSetter }: Props) { return ( <> - place gober gift menu here - +
+ place gober gift menu here + +
); } diff --git a/frontend/src/components/GooberInfo.css b/frontend/src/components/GooberInfo.css index 07ff5fe..df0d92b 100644 --- a/frontend/src/components/GooberInfo.css +++ b/frontend/src/components/GooberInfo.css @@ -1,7 +1,9 @@ .infoBackground { - background-color: "grey"; display: "grid"; grid-template-columns: "1fr 1fr 1fr"; margin: "-16px"; padding: "10px"; +} +.gooberInfo{ + background-color: var(--bg-color); } \ No newline at end of file diff --git a/frontend/src/components/GooberInfo.tsx b/frontend/src/components/GooberInfo.tsx index 9e846db..28d95f0 100644 --- a/frontend/src/components/GooberInfo.tsx +++ b/frontend/src/components/GooberInfo.tsx @@ -42,9 +42,8 @@ export default function GooberInfo({ return ( <> -
Cash money: ${money}
-
Shop
-
@@ -88,9 +89,8 @@ export default function GooberMenu({ > {gooberName} -
setPage("food")} @@ -111,7 +111,7 @@ export default function GooberMenu({ +
+ place gober play menu here + +
); } diff --git a/frontend/src/components/Home.css b/frontend/src/components/Home.css index 13e7e95..a35b313 100644 --- a/frontend/src/components/Home.css +++ b/frontend/src/components/Home.css @@ -130,7 +130,6 @@ cursor: pointer } - .wrapper label::before { content: ""; position: absolute; diff --git a/frontend/src/components/Home.tsx b/frontend/src/components/Home.tsx index aa58ebf..73eecfc 100644 --- a/frontend/src/components/Home.tsx +++ b/frontend/src/components/Home.tsx @@ -1,38 +1,36 @@ -import { useState } from "react"; +import { useState as _useState } from "react"; import oscLogo from "../assets/osc-logo.png"; import githubLogo from "../assets/github-mark-white.svg"; +import CanvasFetcher from "./CanvasFetcher"; import "./Home.css"; import "bootstrap/dist/css/bootstrap.min.css"; - const Home = () => { - const [count, setCount] = useState(0); - - // had to add because bootstrap defaults to light mode - return ( -
+

Welcome to StudyGatchi!

+
-

Welcome to the Studygatchi Project!

+ {/* We don't really need the counter so I just overwrote it + to show the JSON fetching working */} +
+

Click on the OSC link to get to OSC!

Click on the Github Link to get to this project's GitHub repository!

- ) -} + ); +}; export default Home; \ No newline at end of file diff --git a/frontend/src/components/SettingsMenu.css b/frontend/src/components/SettingsMenu.css index f4855a9..042abce 100644 --- a/frontend/src/components/SettingsMenu.css +++ b/frontend/src/components/SettingsMenu.css @@ -5,6 +5,6 @@ .themeChoice{ border-radius: 15%; width: 50px; - height: 50px; - background-color: white; -} \ No newline at end of file + height: 45px; +} + diff --git a/frontend/src/components/SettingsMenu.tsx b/frontend/src/components/SettingsMenu.tsx index bb3f6a5..097f168 100644 --- a/frontend/src/components/SettingsMenu.tsx +++ b/frontend/src/components/SettingsMenu.tsx @@ -1,8 +1,17 @@ -import { useState } from "react"; +// FIXME useEffect is unused, preventing build +import { useState, useEffect as _useEffect, useContext } from "react"; import "./SettingsMenu.css"; import "bootstrap/dist/css/bootstrap.min.css"; +import { ThemeContext } from "./ThemeProvider.tsx"; export default function SettingsMenu() { + const context = useContext(ThemeContext); + if (!context) { + throw new Error("SettingsMenu must be used within a ThemeProvider"); + } + // FIXME theme unused, preventing build + const { theme: _theme, setTheme, themes } = context; + const [firstOption, setFirst] = useState(false); const [secondOption, setSecond] = useState(false); @@ -65,13 +74,21 @@ export default function SettingsMenu() { Themes
-
-
- -
+ + + + +
Miscellaneous diff --git a/frontend/src/components/ThemeProvider.tsx b/frontend/src/components/ThemeProvider.tsx new file mode 100644 index 0000000..31fa955 --- /dev/null +++ b/frontend/src/components/ThemeProvider.tsx @@ -0,0 +1,46 @@ +import { useState, useEffect, createContext } from 'react'; + +export type Theme = { + bg: string; + text: string; + card: string; + button: string; +} + +export const themes: Record = { + pink: {bg: "#F2B8CF", text: "#4A2B33", card: "#F6D1E6", button: "#4A2B33"}, + green: {bg: "#B7E0A6", text: "#2F3A2D", card: "#D4F5D0", button: "#2F3A2D"}, + lightblue: {bg: "#9bd0ec", text: "#0F2B3A", card:"#C9ECF6", button: "#0F2B3A"}, + white: {bg: "#E8E8E8", text: "#1A1A1A", card: "#d8d6d6", button: "#3A3A3A"}, + black: {bg: "#383838", text: "#F5F5F5", card: "#2A2A2A", button: "#8C8C8C"} +}; + +type ThemeContextType = { + theme: Theme; + setTheme: React.Dispatch>; + themes: typeof themes; +} + +export const ThemeContext = createContext(undefined); + +type ThemeProviderProps = { + children: React.ReactNode; +} + +export function ThemeProvider({children}: ThemeProviderProps){ + const [theme, setTheme] = useState(themes.black); + + useEffect(() => { + console.log("Theme changed:", theme); + document.documentElement.style.setProperty("--bg-color", theme.bg); + document.documentElement.style.setProperty("--text-color", theme.text); + document.documentElement.style.setProperty("--card-bg", theme.card); + document.documentElement.style.setProperty("--button-bg", theme.button); + }, [theme]); + + return ( + + {children} + + ); +} diff --git a/frontend/src/content.ts b/frontend/src/content.ts new file mode 100644 index 0000000..411e88d --- /dev/null +++ b/frontend/src/content.ts @@ -0,0 +1,15 @@ +// Manifest v3 requires that content scripts be self-contained, so we have to inline it +const browser = (typeof chrome !== 'undefined' ? chrome : (window as any).browser); + +browser.runtime.onMessage.addListener((request: any, _sender: any, sendResponse: any) => { + if (request.action === 'fetchCanvasData') { + const { startDate, endDate } = request; + + fetch(`/api/v1/planner/items?per_page=100&start_date=${startDate}&end_date=${endDate}`) + .then(r => r.json()) + .then(data => sendResponse({ success: true, data })) + .catch(error => sendResponse({ success: false, error: error.message })); + + return true; + } +}); \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css index 2a6dc22..be9e8ce 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,12 +1,12 @@ - :root { font-family: Inter, 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; + --bg-color: #080909; + --text-color: rgba(255, 255, 255, 0.87); + --card-bg: #dd9ec7; font-synthesis: none; text-rendering: optimizeLegibility; @@ -24,6 +24,8 @@ a:hover { } body { + background-color: var(--bg-color); + color: var(--text-color); margin: 0; display: flex; place-items: center; @@ -37,18 +39,25 @@ h1 { } button { + border: none; + border: 2px solid var(--text-color); border-radius: 8px; border: 1px solid transparent; + padding: 0.6em 1.2em; + margin: 3px; + font-size: 1em; font-weight: 500; font-family: inherit; - background-color: #1a1a1a; + background-color: var(--button-bg); cursor: pointer; transition: border-color 0.25s; } button:hover { - border-color: #646cff; + background-color: var(--bg-bg); + color: var(--text-color); + border: 2px solid var(--text-color); } button:focus, button:focus-visible { diff --git a/frontend/src/lib/browser.ts b/frontend/src/lib/browser.ts new file mode 100644 index 0000000..58fec33 --- /dev/null +++ b/frontend/src/lib/browser.ts @@ -0,0 +1 @@ +export const browser = (typeof chrome !== 'undefined' ? chrome : (window as any).browser); \ No newline at end of file diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 7629dc7..9feaa6c 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -15,17 +15,36 @@ export default defineConfig({ ], }), ], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + server: { + proxy: { + '/api': { + target: 'https://ufl.instructure.com', + changeOrigin: true, + secure: false, + } + } + }, build: { outDir: 'build', rollupOptions: { input: { main: './index.html', background: './src/background.ts', + content: './src/content.ts', }, output: { entryFileNames: (chunkInfo) => { - return chunkInfo.name === 'background' ? 'background.js' : 'assets/[name]-[hash].js'; + if (chunkInfo.name === 'background') return 'background.js'; + if (chunkInfo.name === 'content') return 'content.js'; + return 'assets/[name]-[hash].js'; }, + inlineDynamicImports: false, + manualChunks: undefined, }, }, }, diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..9600dcb --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +DJANGO_SETTINGS_MODULE = backend.settings +pythonpath = . +python_files = tests.py test_*.py *_tests.py \ No newline at end of file