commit 85b035fd27cef365ff7ac71d8b35bc6efffa65c1 Author: Brunobrno Date: Wed Oct 1 18:31:30 2025 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4b60b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +backend/__pycache__/ +backend/**/*.pyc +backend/db.sqlite3 +backend/media/ +backend/static/ +backend/*.log +backend/.env +backend/.venv/ +backend/env/ +backend/.mypy_cache/ +backend/.pytest_cache/ +backend/.coverage +backend/htmlcov/ +backend/.vscode/ +backend/.DS_Store +frontend/node_modules/ +frontend/dist/ +frontend/.env +frontend/.DS_Store +frontend/.vscode/ +frontend/*.log +frontend/.eslintcache +frontend/.parcel-cache/ +frontend/.turbo/ +frontend/.next/ +frontend/.yarn/ +frontend/.pnp* +frontend/yarn-error.log +frontend/.npm/ +frontend/.cache/ +frontend/.idea/ +frontend/.swc/ +frontend/.coverage +frontend/coverage/ +frontend/.env.local +frontend/.env.development.local +frontend/.env.test.local +frontend/.env.production.local +frontend/.DS_Store +frontend/.vscode/ +frontend/.history/ +frontend/.sass-cache/ +frontend/.tmp/ +frontend/.log/ +frontend/.vercel/ +frontend/.firebase/ +frontend/.netlify/ +frontend/.expo/ +frontend/.expo-shared/ +frontend/.nx/ +frontend/.storybook/ +frontend/.husky/ +frontend/.lintstagedrc* +frontend/.prettier* +frontend/.stylelint* +frontend/.editorconfig +frontend/.gitattributes +frontend/.gitmodules +frontend/.npmrc +frontend/.yarnrc +frontend/.yarnrc.yml +frontend/.pnpmfile.cjs +frontend/.pnpmfile.js +frontend/.pnpm-debug.log +frontend/.lock +frontend/.env.*.local +frontend/.env.*.prod +frontend/.env.*.test +frontend/.env.*.dev +frontend/.env.*.staging +frontend/.env.*.production +frontend/.env.*.development +frontend/.env.*.example +frontend/.env.*.sample +frontend/.env.*.template +frontend/.env.*.backup +frontend/.env.*.bak +frontend/.env.*.old +frontend/.env.*.new +frontend/.env.*.dist +frontend/.env.*.orig +.env + +venv +.venv \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/backend/vontor_cz/__init__.py b/backend/vontor_cz/__init__.py new file mode 100644 index 0000000..fa8437a --- /dev/null +++ b/backend/vontor_cz/__init__.py @@ -0,0 +1,3 @@ +from .celery import app as celery_app + +__all__ = ["celery_app"] \ No newline at end of file diff --git a/backend/vontor_cz/asgi.py b/backend/vontor_cz/asgi.py new file mode 100644 index 0000000..44ef2fb --- /dev/null +++ b/backend/vontor_cz/asgi.py @@ -0,0 +1,25 @@ +""" +ASGI config for vontor_cz project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/ +""" + +import os +from django.core.asgi import get_asgi_application +from channels.routing import ProtocolTypeRouter, URLRouter +from channels.auth import AuthMiddlewareStack +#import myapp.routing # your app's routing + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trznice.settings') + +application = ProtocolTypeRouter({ + "http": get_asgi_application(), + "websocket": AuthMiddlewareStack( + URLRouter( + #myapp.routing.websocket_urlpatterns + ) + ), +}) diff --git a/backend/vontor_cz/celery.py b/backend/vontor_cz/celery.py new file mode 100644 index 0000000..96a43e1 --- /dev/null +++ b/backend/vontor_cz/celery.py @@ -0,0 +1,8 @@ +import os +from celery import Celery + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") + +app = Celery("backend") +app.config_from_object("django.conf:settings", namespace="CELERY") +app.autodiscover_tasks() diff --git a/backend/vontor_cz/models.py b/backend/vontor_cz/models.py new file mode 100644 index 0000000..a4e05d8 --- /dev/null +++ b/backend/vontor_cz/models.py @@ -0,0 +1,61 @@ +from django.db import models +from django.utils import timezone + +class ActiveManager(models.Manager): + def get_queryset(self): + return super().get_queryset().filter(is_deleted=False) + +class AllManager(models.Manager): + def get_queryset(self): + return super().get_queryset() + +# How to use custom object Managers: add these fields to your model, to override objects behaviour and all_objects behaviour +# objects = ActiveManager() +# all_objects = AllManager() + + +class SoftDeleteModel(models.Model): + is_deleted = models.BooleanField(default=False) + deleted_at = models.DateTimeField(null=True, blank=True) + + def delete(self, using=None, keep_parents=False): + self.is_deleted = True + self.deleted_at = timezone.now() + self.save() + + objects = ActiveManager() + all_objects = AllManager() + + class Meta: + abstract = True + + def delete(self, *args, **kwargs): + # Soft delete self + self.is_deleted = True + self.deleted_at = timezone.now() + self.save() + + def hard_delete(self, using=None, keep_parents=False): + super().delete(using=using, keep_parents=keep_parents) + + + +# SiteSettings model for managing site-wide settings +"""class SiteSettings(models.Model): + bank = models.CharField(max_length=100, blank=True) + support_email = models.EmailField(blank=True) + logo = models.ImageField(upload_to='settings/', blank=True, null=True) + + def __str__(self): + return "Site Settings" + + class Meta: + verbose_name = "Site Settings" + verbose_name_plural = "Site Settings" + + @classmethod + def get_solo(cls): + obj, created = cls.objects.get_or_create(id=1) + return obj + +""" diff --git a/backend/vontor_cz/settings.py b/backend/vontor_cz/settings.py new file mode 100644 index 0000000..316c223 --- /dev/null +++ b/backend/vontor_cz/settings.py @@ -0,0 +1,895 @@ +""" +Django settings for vontor_cz project. + +Generated by 'django-admin startproject' using Django 5.1.3. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" +import os +from typing import Dict, Any +from pathlib import Path + +from django.core.management.utils import get_random_secret_key +from django.db import OperationalError, connections + +from datetime import timedelta + +from dotenv import load_dotenv +load_dotenv() # Pouze načte proměnné lokálně, pokud nejsou dostupné + +#---------------- ENV VARIABLES USECASE-------------- +# v jiné app si to importneš skrz: from django.conf import settings +# a použiješ takto: settings.FRONTEND_URL + +FRONTEND_URL = os.getenv("FRONTEND_URL", "http://localhost:3000") +FRONTEND_URL_DEV = os.getenv("FRONTEND_URL_DEV", "http://localhost:5173") +print(f"FRONTEND_URL: {FRONTEND_URL}\nFRONTEND_URL_DEV: {FRONTEND_URL_DEV}\n") + +#-------------------------BASE ⚙️------------------------ + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Pavel +# from django.conf.locale.en import formats as en_formats + +DATETIME_INPUT_FORMATS = [ + "%Y-%m-%d", # '2025-07-25' + "%Y-%m-%d %H:%M", # '2025-07-25 14:30' + "%Y-%m-%d %H:%M:%S", # '2025-07-25 14:30:59' + "%Y-%m-%dT%H:%M", # '2025-07-25T14:30' + "%Y-%m-%dT%H:%M:%S", # '2025-07-25T14:30:59' +] + +LANGUAGE_CODE = 'cs' + +TIME_ZONE = 'Europe/Prague' + +USE_I18N = True + +USE_TZ = True + + + + +# SECURITY WARNING: don't run with debug turned on in production! +if os.getenv("DEBUG", "") == "True": + DEBUG = True +else: + DEBUG = False + +print(f"\nDEBUG state: {str(DEBUG)}\nDEBUG .env raw: {os.getenv('DEBUG', '')}\n") + +#-----------------------BASE END⚙️-------------------------- + +#--------------- URLS 🌐 ------------------- + +ASGI_APPLICATION = 'vontor_cz.asgi.application' #daphne +ROOT_URLCONF = 'vontor_cz.urls' +LOGIN_URL = '/admin' #nastavení Login adresy + +#----------------------------------------- + + + +#----------------------------------- LOGS ------------------------------------------- +#slouží pro tisknutí do konzole v dockeru skrz: logger.debug("content") +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "verbose", + }, + }, + "formatters": { + "verbose": { + "format": "{levelname} {asctime} {name}: {message}", + "style": "{", + }, + }, + "root": { + "handlers": ["console"], + "level": "DEBUG" if DEBUG else "INFO", + }, +} + +""" +import logging + +# Vytvoř si logger podle názvu souboru (modulu) +logger = logging.getLogger(__name__) + + +logger.debug("Ladicí zpráva – vidíš jen když je DEBUG = True") +logger.info("Informace – např. že uživatel klikl na tlačítko") +logger.warning("Varování – něco nečekaného, ale ne kritického") +logger.error("Chyba – něco se pokazilo, ale aplikace jede dál") +logger.critical("Kritická chyba – selhání systému, třeba pád služby") +""" + +#---------------------------------- END LOGS --------------------------------------- + +#-------------------------------------SECURITY 🔐------------------------------------ + +if DEBUG: + SECRET_KEY = 'pernament' +else: + SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key()) + + +SESSION_COOKIE_AGE = 86400 # one day + + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +AUTHENTICATION_BACKENDS = [ + #'vontor_cz.backend.EmailOrUsernameModelBackend', #custom backend z authentication aplikace + 'django.contrib.auth.backends.ModelBackend', +] + +#--------------------------------END SECURITY 🔐------------------------------------- + +#-------------------------------------CORS + HOSTs 🌐🔐------------------------------------ + +ALLOWED_HOSTS = ["*"] + +CSRF_TRUSTED_ORIGINS = [ + 'https://domena.cz', + "https://www.domena.cz", + "http://localhost:3000", #react docker + "http://localhost:5173" #react dev +] + +if DEBUG: + CORS_ALLOWED_ORIGINS = [ + "http://localhost:5173", + "http://localhost:3000", + ] +else: + CORS_ALLOWED_ORIGINS = [ + "https://www.domena.cz", + ] + +CORS_ALLOW_CREDENTIALS = True +CORS_ALLOW_ALL_ORIGINS = False # Tohle musí být false, když používáš credentials + +print("CORS_ALLOWED_ORIGINS =", CORS_ALLOWED_ORIGINS) +print("CSRF_TRUSTED_ORIGINS =", CSRF_TRUSTED_ORIGINS) +print("ALLOWED_HOSTS =", ALLOWED_HOSTS) + + + +#--------------------------------END CORS + HOSTs 🌐🔐--------------------------------- + + +#--------------------------------------SSL 🧾------------------------------------ + +if os.getenv("SSL", "") == "True": + USE_SSL = True +else: + USE_SSL = False + + +if USE_SSL is True: + print("SSL turned on!") + SESSION_COOKIE_SECURE = True + CSRF_COOKIE_SECURE = True + SECURE_SSL_REDIRECT = True + SECURE_BROWSER_XSS_FILTER = True + SECURE_CONTENT_TYPE_NOSNIFF = True + USE_X_FORWARDED_HOST = True + SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +else: + SESSION_COOKIE_SECURE = False + CSRF_COOKIE_SECURE = False + SECURE_SSL_REDIRECT = False + SECURE_BROWSER_XSS_FILTER = False + SECURE_CONTENT_TYPE_NOSNIFF = False + USE_X_FORWARDED_HOST = False + +print(f"\nUsing SSL: {USE_SSL}\n") + +#--------------------------------END-SSL 🧾--------------------------------- + + + + + +#-------------------------------------REST FRAMEWORK 🛠️------------------------------------ + +# ⬇️ Základní lifetime konfigurace +ACCESS_TOKEN_LIFETIME = timedelta(minutes=15) +REFRESH_TOKEN_LIFETIME = timedelta(days=1) + +# ⬇️ Nastavení SIMPLE_JWT podle režimu +if DEBUG: + SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": ACCESS_TOKEN_LIFETIME, + "REFRESH_TOKEN_LIFETIME": REFRESH_TOKEN_LIFETIME, + + "AUTH_COOKIE": "access_token", + "AUTH_COOKIE_SECURE": False, # není HTTPS + "AUTH_COOKIE_HTTP_ONLY": True, + "AUTH_COOKIE_PATH": "/", + "AUTH_COOKIE_SAMESITE": "Lax", # není cross-site + + "ROTATE_REFRESH_TOKENS": True, + "BLACKLIST_AFTER_ROTATION": True, + } +else: + SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": ACCESS_TOKEN_LIFETIME, + "REFRESH_TOKEN_LIFETIME": REFRESH_TOKEN_LIFETIME, + + "AUTH_COOKIE": "access_token", + "AUTH_COOKIE_SECURE": True, # HTTPS only + "AUTH_COOKIE_HTTP_ONLY": True, + "AUTH_COOKIE_PATH": "/", + "AUTH_COOKIE_SAMESITE": "None", # potřebné pro cross-origin + + "ROTATE_REFRESH_TOKENS": True, + "BLACKLIST_AFTER_ROTATION": True, + } + + +REST_FRAMEWORK = { + "DATETIME_FORMAT": "%Y-%m-%d %H:%M", # Pavel + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'account.tokens.CookieJWTAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ), + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.AllowAny', + ), + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', + + 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], +} + +#--------------------------------END REST FRAMEWORK 🛠️------------------------------------- + + + +#-------------------------------------APPS 📦------------------------------------ +MY_CREATED_APPS = [ + 'account', +] + +INSTALLED_APPS = [ + 'daphne', #asgi bude fungovat lokálně (musí být na začátku) + + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'corsheaders', #cors + + 'django_celery_beat', #slouží k plánování úkolů pro Celery + + + #'chat.apps.GlobalChatCheck', #tohle se spusti při každé django inicializaci (migration, createmigration, runserver) + + #'authentication', + + 'storages',# Adds support for external storage services like Amazon S3 via django-storages + 'django_filters', + + 'channels' ,# django channels + + 'rest_framework', + 'rest_framework_api_key', + + 'drf_spectacular', #rest framework, grafické zobrazení + + #Nastavení stránky + #'constance', + #'constance.backends.database', + + 'django.contrib.sitemaps', + + 'tinymce', + + + #kvůli bugum je lepší to dát na poslední místo v INSTALLED_APPS + 'django_cleanup.apps.CleanupConfig', #app která maže nepoužité soubory(media) z databáze na S3 +] + +#skládaní dohromady INSTALLED_APPS +INSTALLED_APPS = INSTALLED_APPS[:-1] + MY_CREATED_APPS + INSTALLED_APPS[-1:] + +# -------------------------------------END APPS 📦------------------------------------ + + + + + +#-------------------------------------MIDDLEWARE 🧩------------------------------------ +# Middleware is a framework of hooks into Django's request/response processing. + +MIDDLEWARE = [ + # Middleware that allows your backend to accept requests from other domains (CORS) + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + + + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + + #CUSTOM + #'tools.middleware.CustomMaxUploadSizeMiddleware', + + + 'whitenoise.middleware.WhiteNoiseMiddleware',# díky tomu funguje načítaní static files +] + +#--------------------------------END MIDDLEWARE 🧩--------------------------------- + + + + + +#-------------------------------------CACHE + CHANNELS(ws) 📡🗄️------------------------------------ + +# Caching settings for Redis (using Docker's internal network name for Redis) +if DEBUG is False: + #PRODUCTION + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.redis.RedisCache', + 'LOCATION': 'redis://redis:6379/0', # Using the service name `redis` from Docker Compose + 'OPTIONS': { + 'CLIENT_CLASS': 'django_redis.client.DefaultClient', + 'PASSWORD': os.getenv('REDIS_PASSWORD'), # Make sure to set REDIS_PASSWORD in your environment + }, + } + } + + # WebSockets Channel Layers (using Redis in production) + CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + 'hosts': [('redis', 6379)], # Use `redis` service in Docker Compose + }, + } + } + +else: + #DEVELOPMENT + # Use in-memory channel layer for development (when DEBUG is True) + CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels.layers.InMemoryChannelLayer', + } + } + + # Use in-memory cache for development (when DEBUG is True) + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + } + } + +#--------------------------------END CACHE + CHANNELS(ws) 📡🗄️--------------------------------- + +#-------------------------------------CELERY 📅------------------------------------ + +# CELERY_BROKER_URL = 'redis://localhost:6379/0' +CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL") +CELERY_RESULT_BACKEND = os.getenv("CELERY_RESULT_BACKEND") + +try: + import redis + # test connection + r = redis.Redis(host='localhost', port=6379, db=0) + r.ping() +except Exception: + CELERY_BROKER_URL = 'memory://' + +CELERY_ACCEPT_CONTENT = os.getenv("CELERY_ACCEPT_CONTENT") +CELERY_TASK_SERIALIZER = os.getenv("CELERY_TASK_SERIALIZER") +CELERY_TIMEZONE = os.getenv("CELERY_TIMEZONE") + +CELERY_BEAT_SCHEDULER = os.getenv("CELERY_BEAT_SCHEDULER") +# if DEBUG: +# CELERY_BROKER_URL = 'redis://localhost:6379/0' +# try: +# import redis +# # test connection +# r = redis.Redis(host='localhost', port=6379, db=0) +# r.ping() +# except Exception: +# CELERY_BROKER_URL = 'memory://' + +# CELERY_ACCEPT_CONTENT = ['json'] +# CELERY_TASK_SERIALIZER = 'json' +# CELERY_TIMEZONE = 'Europe/Prague' + +# CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' + + # from celery.schedules import crontab + + # CELERY_BEAT_SCHEDULE = { + # 'hard_delete_soft_deleted_monthly': { + # 'task': 'vontor_cz.tasks.hard_delete_soft_deleted_records', + # 'schedule': crontab(minute=0, hour=0, day_of_month=1), # každý první den v měsíci o půlnoci + # }, + # 'delete_old_reservations_monthly': { + # 'task': 'account.tasks.delete_old_reservations', + # 'schedule': crontab(minute=0, hour=1, day_of_month=1), # každý první den v měsíci v 1:00 ráno + # }, + # } +# else: +# # Nebo nastav dummy broker, aby se úlohy neodesílaly +# CELERY_BROKER_URL = 'memory://' # broker v paměti, pro testování bez Redis + +#-------------------------------------END CELERY 📅------------------------------------ + + +#-------------------------------------DATABASE 💾------------------------------------ + +# Nastavuje výchozí typ primárního klíče pro modely. +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# říka že se úkladá do databáze, místo do cookie +SESSION_ENGINE = 'django.contrib.sessions.backends.db' + +USE_PRODUCTION_DB = os.getenv("USE_PRODUCTION_DB", "False") == "True" + +if USE_PRODUCTION_DB is False: + # DEVELOPMENT + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Database engine + 'NAME': BASE_DIR / 'db.sqlite3', # Path to the SQLite database file + } + } +else: + #PRODUCTION + DATABASES = { + 'default': { + 'ENGINE': os.getenv('DATABASE_ENGINE'), + 'NAME': os.getenv('DATABASE_NAME'), + 'USER': os.getenv('DATABASE_USER'), + 'PASSWORD': os.getenv('DATABASE_PASSWORD'), + 'HOST': os.getenv('DATABASE_HOST', "localhost"), + 'PORT': os.getenv('DATABASE_PORT'), + } + } + +AUTH_USER_MODEL = 'account.CustomUser' #class CustomUser(AbstractUser) best practice to use AbstractUser + +#--------------------------------END DATABASE 💾--------------------------------- + +#--------------------------------------PAGE SETTINGS ------------------------------------- +CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' + +# Configuration for Constance(variables) +CONSTANCE_CONFIG = { + 'BITCOIN_WALLET': ('', 'Public BTC wallet address'), + 'SUPPORT_EMAIL': ('admin@example.com', 'Support email'), +} + +#--------------------------------------EMAIL 📧-------------------------------------- + +if DEBUG: + # DEVELOPMENT + EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # Use console backend for development + # EMAILY SE BUDOU POSÍLAT DO KONZOLE!!! +else: + # PRODUCTION + EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + +EMAIL_HOST = os.getenv("EMAIL_HOST_DEV") +EMAIL_PORT = int(os.getenv("EMAIL_PORT_DEV", 465)) +EMAIL_USE_TLS = True # ❌ Keep this OFF when using SSL +EMAIL_USE_SSL = False # ✅ Must be True for port 465 +EMAIL_HOST_USER = os.getenv("EMAIL_USER_DEV") +EMAIL_HOST_PASSWORD = os.getenv("EMAIL_USER_PASSWORD_DEV") +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +EMAIL_TIMEOUT = 10 + +print("---------EMAIL----------\nEMAIL_HOST =", os.getenv("EMAIL_HOST_DEV")) +print("EMAIL_PORT =", os.getenv("EMAIL_PORT_DEV")) +print("EMAIL_USER =", os.getenv("EMAIL_USER_DEV")) +print("EMAIL_USER_PASSWORD =", os.getenv("EMAIL_USER_PASSWORD_DEV"), "\n------------------------") + +#----------------------------------EMAIL END 📧------------------------------------- + + + + +#-------------------------------------TEMPLATES 🗂️------------------------------------ + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + "DIRS": [BASE_DIR / 'templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +#--------------------------------END TEMPLATES 🗂️--------------------------------- + + + + + + + +#-------------------------------------MEDIA + STATIC 🖼️, AWS ☁️------------------------------------ + +# nastavení složky pro globalstaticfiles (static složky django hledá samo) +STATICFILES_DIRS = [ + BASE_DIR / 'globalstaticfiles', +] + + + +if os.getenv("USE_AWS", "") == "True": + USE_AWS = True +else: + USE_AWS = False + +print(f"\n-------------- USE_AWS: {USE_AWS} --------------") + +if USE_AWS is False: + # DEVELOPMENT + + + # Development: Use local file system storage for static files + STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, + } + + # Media and Static URL for local dev + MEDIA_URL = '/media/' + MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + + STATIC_URL = '/static/' + + # Local folder for collected static files + STATIC_ROOT = BASE_DIR / 'collectedstaticfiles' + +elif USE_AWS: + # PRODUCTION + + AWS_LOCATION = "static" + + # Production: Use S3 storage + STORAGES = { + "default": { + "BACKEND" : "storages.backends.s3boto3.S3StaticStorage", + }, + + "staticfiles": { + "BACKEND" : "storages.backends.s3boto3.S3StaticStorage", + }, + } + + # Media and Static URL for AWS S3 + MEDIA_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/media/' + STATIC_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/static/' + + CSRF_TRUSTED_ORIGINS.append(STATIC_URL) + + # Static files should be collected to a local directory and then uploaded to S3 + STATIC_ROOT = BASE_DIR / 'collectedstaticfiles' + + AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID') + AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY') + AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME') + AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME', 'us-east-1') # Default to 'us-east-1' if not set + AWS_S3_SIGNATURE_VERSION = 's3v4' # Use AWS Signature Version 4 + AWS_S3_USE_SSL = True + AWS_S3_FILE_OVERWRITE = True + AWS_DEFAULT_ACL = None # Set to None to avoid setting a default ACL + + + +print(f"Static url: {STATIC_URL}\nStatic storage: {STORAGES}\n----------------------------") + +#--------------------------------END: MEDIA + STATIC 🖼️, AWS ☁️--------------------------------- + + + +#-------------------------------------TINY MCE ✍️------------------------------------ + +TINYMCE_JS_URL = 'https://cdn.tiny.cloud/1/no-api-key/tinymce/7/tinymce.min.js' + +TINYMCE_DEFAULT_CONFIG = { + "height": "320px", + "width": "960px", + "menubar": "file edit view insert format tools table help", + "plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code " + "fullscreen insertdatetime media table paste code help wordcount spellchecker", + "toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft " + "aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor " + "backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | " + "fullscreen preview save print | insertfile image media pageembed template link anchor codesample | " + "a11ycheck ltr rtl | showcomments addcomment code", + "custom_undo_redo_levels": 10, +} +TINYMCE_SPELLCHECKER = True +TINYMCE_COMPRESSOR = True + +#--------------------------------END-TINY-MCE-SECTION ✍️--------------------------------- + + + +#-------------------------------------DRF SPECTACULAR 📊------------------------------------ + +SPECTACULAR_DEFAULTS: Dict[str, Any] = { + # A regex specifying the common denominator for all operation paths. If + # SCHEMA_PATH_PREFIX is set to None, drf-spectacular will attempt to estimate + # a common prefix. Use '' to disable. + # Mainly used for tag extraction, where paths like '/api/v1/albums' with + # a SCHEMA_PATH_PREFIX regex '/api/v[0-9]' would yield the tag 'albums'. + 'SCHEMA_PATH_PREFIX': None, + + # Remove matching SCHEMA_PATH_PREFIX from operation path. Usually used in + # conjunction with appended prefixes in SERVERS. + 'SCHEMA_PATH_PREFIX_TRIM': False, + + # Insert a manual path prefix to the operation path, e.g. '/service/backend'. + # Use this for example to align paths when the API is mounted as a sub-resource + # behind a proxy and Django is not aware of that. Alternatively, prefixes can + # also specified via SERVERS, but this makes the operation path more explicit. + 'SCHEMA_PATH_PREFIX_INSERT': '', + + # Coercion of {pk} to {id} is controlled by SCHEMA_COERCE_PATH_PK. Additionally, + # some libraries (e.g. drf-nested-routers) use "_pk" suffixed path variables. + # This setting globally coerces path variables like "{user_pk}" to "{user_id}". + 'SCHEMA_COERCE_PATH_PK_SUFFIX': False, + + # Schema generation parameters to influence how components are constructed. + # Some schema features might not translate well to your target. + # Demultiplexing/modifying components might help alleviate those issues. + 'DEFAULT_GENERATOR_CLASS': 'drf_spectacular.generators.SchemaGenerator', + + # Create separate components for PATCH endpoints (without required list) + 'COMPONENT_SPLIT_PATCH': True, + + # Split components into request and response parts where appropriate + # This setting is highly recommended to achieve the most accurate API + # description, however it comes at the cost of having more components. + 'COMPONENT_SPLIT_REQUEST': True, + + # Aid client generator targets that have trouble with read-only properties. + 'COMPONENT_NO_READ_ONLY_REQUIRED': False, + + # Adds "minLength: 1" to fields that do not allow blank strings. Deactivated + # by default because serializers do not strictly enforce this on responses and + # so "minLength: 1" may not always accurately describe API behavior. + # Gets implicitly enabled by COMPONENT_SPLIT_REQUEST, because this can be + # accurately modeled when request and response components are separated. + 'ENFORCE_NON_BLANK_FIELDS': False, + + # This version string will end up the in schema header. The default OpenAPI + # version is 3.0.3, which is heavily tested. We now also support 3.1.0, + # which contains the same features and a few mandatory, but minor changes. + 'OAS_VERSION': '3.0.3', + + # Configuration for serving a schema subset with SpectacularAPIView + 'SERVE_URLCONF': None, + + # complete public schema or a subset based on the requesting user + 'SERVE_PUBLIC': True, + + # include schema endpoint into schema + 'SERVE_INCLUDE_SCHEMA': True, + + # list of authentication/permission classes for spectacular's views. + 'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny'], #account.permissions.AdminOnly + + # None will default to DRF's AUTHENTICATION_CLASSES + 'SERVE_AUTHENTICATION': None, + + # Dictionary of general configuration to pass to the SwaggerUI({ ... }) + # https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/ + # The settings are serialized with json.dumps(). If you need customized JS, use a + # string instead. The string must then contain valid JS and is passed unchanged. + 'SWAGGER_UI_SETTINGS': { + 'deepLinking': True, + }, + + # Initialize SwaggerUI with additional OAuth2 configuration. + # https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/ + 'SWAGGER_UI_OAUTH2_CONFIG': {}, + + # Dictionary of general configuration to pass to the Redoc.init({ ... }) + # https://redocly.com/docs/redoc/config/#functional-settings + # The settings are serialized with json.dumps(). If you need customized JS, use a + # string instead. The string must then contain valid JS and is passed unchanged. + 'REDOC_UI_SETTINGS': {}, + + # CDNs for swagger and redoc. You can change the version or even host your + # own depending on your requirements. For self-hosting, have a look at + # the sidecar option in the README. + 'SWAGGER_UI_DIST': 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest', + 'SWAGGER_UI_FAVICON_HREF': 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/favicon-32x32.png', + 'REDOC_DIST': 'https://cdn.jsdelivr.net/npm/redoc@latest', + + # Append OpenAPI objects to path and components in addition to the generated objects + 'APPEND_PATHS': {}, + 'APPEND_COMPONENTS': {}, + + + # Postprocessing functions that run at the end of schema generation. + # must satisfy interface result = hook(generator, request, public, result) + 'POSTPROCESSING_HOOKS': [ + 'drf_spectacular.hooks.postprocess_schema_enums' + ], + + # Preprocessing functions that run before schema generation. + # must satisfy interface result = hook(endpoints=result) where result + # is a list of Tuples (path, path_regex, method, callback). + # Example: 'drf_spectacular.hooks.preprocess_exclude_path_format' + 'PREPROCESSING_HOOKS': [], + + # Determines how operations should be sorted. If you intend to do sorting with a + # PREPROCESSING_HOOKS, be sure to disable this setting. If configured, the sorting + # is applied after the PREPROCESSING_HOOKS. Accepts either + # True (drf-spectacular's alpha-sorter), False, or a callable for sort's key arg. + 'SORT_OPERATIONS': True, + + # enum name overrides. dict with keys "YourEnum" and their choice values "field.choices" + # e.g. {'SomeEnum': ['A', 'B'], 'OtherEnum': 'import.path.to.choices'} + 'ENUM_NAME_OVERRIDES': {}, + + # Adds "blank" and "null" enum choices where appropriate. disable on client generation issues + 'ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE': True, + + # Add/Append a list of (``choice value`` - choice name) to the enum description string. + 'ENUM_GENERATE_CHOICE_DESCRIPTION': True, + + # Optional suffix for generated enum. + # e.g. {'ENUM_SUFFIX': "Type"} would produce an enum name 'StatusType'. + 'ENUM_SUFFIX': 'Enum', + + # function that returns a list of all classes that should be excluded from doc string extraction + 'GET_LIB_DOC_EXCLUDES': 'drf_spectacular.plumbing.get_lib_doc_excludes', + + # Function that returns a mocked request for view processing. For CLI usage + # original_request will be None. + # interface: request = build_mock_request(method, path, view, original_request, **kwargs) + 'GET_MOCK_REQUEST': 'drf_spectacular.plumbing.build_mock_request', + + # Camelize names like "operationId" and path parameter names + # Camelization of the operation schema itself requires the addition of + # 'drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields' + # to POSTPROCESSING_HOOKS. Please note that the hook depends on + # ``djangorestframework_camel_case``, while CAMELIZE_NAMES itself does not. + 'CAMELIZE_NAMES': False, + + # Changes the location of the action/method on the generated OperationId. For example, + # "POST": "group_person_list", "group_person_create" + # "PRE": "list_group_person", "create_group_person" + 'OPERATION_ID_METHOD_POSITION': 'POST', + + # Determines if and how free-form 'additionalProperties' should be emitted in the schema. Some + # code generator targets are sensitive to this. None disables generic 'additionalProperties'. + # allowed values are 'dict', 'bool', None + 'GENERIC_ADDITIONAL_PROPERTIES': 'dict', + + # Path converter schema overrides (e.g. ). Can be used to either modify default + # behavior or provide a schema for custom converters registered with register_converter(...). + # Takes converter labels as keys and either basic python types, OpenApiType, or raw schemas + # as values. Example: {'aint': OpenApiTypes.INT, 'bint': str, 'cint': {'type': ...}} + 'PATH_CONVERTER_OVERRIDES': {}, + + # Determines whether operation parameters should be sorted alphanumerically or just in + # the order they arrived. Accepts either True, False, or a callable for sort's key arg. + 'SORT_OPERATION_PARAMETERS': True, + + # @extend_schema allows to specify status codes besides 200. This functionality is usually used + # to describe error responses, which rarely make use of list mechanics. Therefore, we suppress + # listing (pagination and filtering) on non-2XX status codes by default. Toggle this to enable + # list responses with ListSerializers/many=True irrespective of the status code. + 'ENABLE_LIST_MECHANICS_ON_NON_2XX': False, + + # This setting allows you to deviate from the default manager by accessing a different model + # property. We use "objects" by default for compatibility reasons. Using "_default_manager" + # will likely fix most issues, though you are free to choose any name. + "DEFAULT_QUERY_MANAGER": 'objects', + + # Controls which authentication methods are exposed in the schema. If not None, will hide + # authentication classes that are not contained in the whitelist. Use full import paths + # like ['rest_framework.authentication.TokenAuthentication', ...]. + # Empty list ([]) will hide all authentication methods. The default None will show all. + 'AUTHENTICATION_WHITELIST': None, + # Controls which parsers are exposed in the schema. Works analog to AUTHENTICATION_WHITELIST. + # List of allowed parsers or None to allow all. + 'PARSER_WHITELIST': None, + # Controls which renderers are exposed in the schema. Works analog to AUTHENTICATION_WHITELIST. + # rest_framework.renderers.BrowsableAPIRenderer is ignored by default if whitelist is None + 'RENDERER_WHITELIST': None, + + # Option for turning off error and warn messages + 'DISABLE_ERRORS_AND_WARNINGS': False, + + # Runs exemplary schema generation and emits warnings as part of "./manage.py check --deploy" + 'ENABLE_DJANGO_DEPLOY_CHECK': True, + + # General schema metadata. Refer to spec for valid inputs + # https://spec.openapis.org/oas/v3.0.3#openapi-object + 'TITLE': 'e-Tržnice API', + 'DESCRIPTION': 'This is the API documentation for e-Tržnice.', + 'TOS': None, + # Optional: MAY contain "name", "url", "email" + 'CONTACT': {}, + # Optional: MUST contain "name", MAY contain URL + + 'LICENSE': {}, + # Statically set schema version. May also be an empty string. When used together with + # view versioning, will become '0.0.0 (v2)' for 'v2' versioned requests. + # Set VERSION to None if only the request version should be rendered. + 'VERSION': '1.0.0', + # Optional list of servers. + # Each entry MUST contain "url", MAY contain "description", "variables" + # e.g. [{'url': 'https://example.com/v1', 'description': 'Text'}, ...] + 'SERVERS': [], + # Tags defined in the global scope + 'TAGS': [], + # Optional: List of OpenAPI 3.1 webhooks. Each entry should be an import path to an + # OpenApiWebhook instance. + 'WEBHOOKS': [], + # Optional: MUST contain 'url', may contain "description" + 'EXTERNAL_DOCS': {}, + + # Arbitrary specification extensions attached to the schema's info object. + # https://swagger.io/specification/#specification-extensions + 'EXTENSIONS_INFO': {}, + + # Arbitrary specification extensions attached to the schema's root object. + # https://swagger.io/specification/#specification-extensions + 'EXTENSIONS_ROOT': {}, + + # Oauth2 related settings. used for example by django-oauth2-toolkit. + # https://spec.openapis.org/oas/v3.0.3#oauth-flows-object + 'OAUTH2_FLOWS': [], + 'OAUTH2_AUTHORIZATION_URL': None, + 'OAUTH2_TOKEN_URL': None, + 'OAUTH2_REFRESH_URL': None, + 'OAUTH2_SCOPES': None, +} diff --git a/backend/vontor_cz/urls.py b/backend/vontor_cz/urls.py new file mode 100644 index 0000000..4130a41 --- /dev/null +++ b/backend/vontor_cz/urls.py @@ -0,0 +1,39 @@ +""" +URL configuration for vontor_cz project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include + +from drf_spectacular.views import ( + SpectacularAPIView, + SpectacularSwaggerView, + SpectacularRedocView, +) + +urlpatterns = [ + #rest framework, map of api + path("api/schema/", SpectacularAPIView.as_view(), name="schema"), + path("swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"), + path("redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"), + + + path('admin/', admin.site.urls), + path('api/account/', include('account.urls')), + + path('api/stripe/', include('thirdparty.stripe.urls')), + path('api/trading212/', include('thirdparty.trading212.urls')), + +] diff --git a/backend/vontor_cz/wsgi.py b/backend/vontor_cz/wsgi.py new file mode 100644 index 0000000..b3e9b8a --- /dev/null +++ b/backend/vontor_cz/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for vontor_cz project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'vontor_cz.settings') + +application = get_wsgi_application() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ab1fe8e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +version: "3.9" +services: + backend: + env_file: + - ./backend/.env + build: ./backend + ports: + - "8000:8000" + volumes: + - ./backend:/app + depends_on: + - redis + command: daphne -b 0.0.0.0 -p 8000 backend.asgi:application + + frontend: + env_file: + - ./frontend/.env + build: ./frontend + ports: + - "5173:5173" + volumes: + - ./frontend:/app + command: npm run dev + + redis: + image: redis:alpine + ports: + - "6379:6379" + + db: + env_file: + - ./backend/.env + image: postgres:16 + environment: + POSTGRES_DB: mydb + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..7aee7c1 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,11 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . + +EXPOSE 5173 +CMD ["npm", "run", "dev"] diff --git a/frontend/REACT.md b/frontend/REACT.md new file mode 100644 index 0000000..fa83597 --- /dev/null +++ b/frontend/REACT.md @@ -0,0 +1,113 @@ +# Vontor CZ + +Welcome to **Vontor CZ**! + +## frontend Folder Overview + +The `frontend` folder contains all code and assets for the client-side React application. Its structure typically includes: + +- **src/** + Tady se ukladají věci, které uživateli se nepředavají přímo spíš takové stavební kostky. + - **api/** + TypeScript/JS soubory které se starají o API a o JWT tokeny. + Čistě pracují s backendem + - **context/** + Kontext si načte data které mu předáš a můžeš si je předávat mezi komponenty rychleji. + - **hooks/** + Pracuje s API a formátují to do výstupu který potřebujeme. + + - **components/** + Konktrétní komponenty které se vykreslují na stránce. + + Už využívají už hooky a contexty pro vykreslení informaci bez složite logiky (ať je komponenta hezky čistá a né moc obsáhla). + + - **features/** + Nejsou to celé stránky, ale hotové komponenty. + + Obsahuje všechny komponenty plus její hooky, API, state a utils potřebné pro jednu konkrétní funkcionalitu aplikace. (použijí se jenom jednou) + + Features zajišťují modularitu a přehlednost aplikace. + + Příklad: komponenta košík, která zahrnuje API volání, state management a UI komponenty. + + --- + + - **layouts/** + Tohle je jenom komponenta, která načte další komponenty, ale používá se jako layout kde jsou například navigace footer a ostatní se opakující prvky stránky, ale hlavní obsah ještě není součastí! Ten se načte skrz v pages. + - **pages/** + Tady se jde do finále tady se vkládají samostatné komponenty a tvoří se už hlavní obsah stránky a vkládají se komponenty a tvoří se logika mezi ně. + - **routes/** + tady se ukládají routy které například zabraňuji načtení stránky nepříhlášeným uživatelům nebo jenom pro ty s určitou roli/oprávněním... tyhle route komponenty se pak využívají v + + --- + + - **assets/** + Obrázky, fonty, a ostatní statické soubory. + + + --- + + + - **App.tsx** + Root komponenta pro aplikaci, kde se nastavují routy pro jednotlivé stránky. + Pozor nemyslím ty routy ze složky routes/ ... to jsou jenom obaly pro konktrétní routy pro jednotlivé stránky. + - **main.tsx** + Vstupní bod pro načítaní aplikace (načíta se první komponenta App.jsx) + + --- + + - **utils/** + Sběrné místo pro pomocné funkce, které nejsou přímo komponenty nebo hooky, ale jsou znovupoužitelné napříč aplikací. + + --- + + - **index.css** + globální styly + - **App.css** + obsahuje stylovaní layoutu, navigace, footer, error okna atd. takové věci které zůstavjí vždy stejně + +- **public/** + Složka public obsahuje statické soubory dostupné přímo přes URL (např. index.html, favicon, obrázky), které React přímo nereenderuje ani neoptimalizuje. + +- **package.json** + něco jak requirements.txt v pythonu + +- **vite.config.js / vite.config.ts** + Vite konfigurace pro building a serving frontend aplikace. + +- **Dockerfile** + Konfigurace pro Docker + +## Getting Started :3 + +1. **Instalace balíčku (bere z package.json):** + ```sh + npm install + ``` + +3. **Start dev server:** + ```sh + npm run dev + ``` + +4. **Build pro produkci(finále):** + ```sh + npm run build + ``` + +5. **Preview production build:** + ```sh + npm run preview + ``` + +## Creating a New React Project with Vite + +If you want to start a new project: + +```sh +npm create vite@latest +# Choose 'react' or 'react-ts' for TypeScript +cd your-project +npm install +npm run dev +``` diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..d94e7de --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { globalIgnores } from 'eslint/config' + +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..e4b78ea --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..76e8993 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,3452 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@types/react-router": "^5.1.20", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-router-dom": "^7.8.1" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/axios": "^0.9.36", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.0", + "eslint": "^9.33.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.1", + "vite": "^7.1.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "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.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@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.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.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.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "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.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "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/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz", + "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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/@rolldown/pluginutils": { + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.30.tgz", + "integrity": "sha512-whXaSoNUFiyDAjkUF8OBpOm77Szdbk5lGNqFe6CbVbJFrhCCPinCbRA3NjawwlNHla1No7xvXXh+CpSxnPfUEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/axios": { + "version": "0.9.36", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.9.36.tgz", + "integrity": "sha512-NLOpedx9o+rxo/X5ChbdiX6mS1atE4WHmEEIcR9NLenRVa5HoVjAvjafwU3FPTqnZEstpoqCaW7fagqSoTDNeg==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", + "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", + "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz", + "integrity": "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.39.1", + "@typescript-eslint/type-utils": "8.39.1", + "@typescript-eslint/utils": "8.39.1", + "@typescript-eslint/visitor-keys": "8.39.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.39.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz", + "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.39.1", + "@typescript-eslint/types": "8.39.1", + "@typescript-eslint/typescript-estree": "8.39.1", + "@typescript-eslint/visitor-keys": "8.39.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.1.tgz", + "integrity": "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.39.1", + "@typescript-eslint/types": "^8.39.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.1.tgz", + "integrity": "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.1", + "@typescript-eslint/visitor-keys": "8.39.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz", + "integrity": "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz", + "integrity": "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.1", + "@typescript-eslint/typescript-estree": "8.39.1", + "@typescript-eslint/utils": "8.39.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz", + "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.1.tgz", + "integrity": "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.39.1", + "@typescript-eslint/tsconfig-utils": "8.39.1", + "@typescript-eslint/types": "8.39.1", + "@typescript-eslint/visitor-keys": "8.39.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.1.tgz", + "integrity": "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.39.1", + "@typescript-eslint/types": "8.39.1", + "@typescript-eslint/typescript-estree": "8.39.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.1.tgz", + "integrity": "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.0.tgz", + "integrity": "sha512-Jx9JfsTa05bYkS9xo0hkofp2dCmp1blrKjw9JONs5BTHOvJCgLbaPSuZLGSVJW6u2qe0tc4eevY0+gSNNi0YCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.30", + "@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/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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-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/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/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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.25.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz", + "integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==", + "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": { + "caniuse-lite": "^1.0.30001733", + "electron-to-chromium": "^1.5.199", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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.30001734", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz", + "integrity": "sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A==", + "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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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": ">=7.0.0" + } + }, + "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/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "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/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/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/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.200", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.200.tgz", + "integrity": "sha512-rFCxROw7aOe4uPTfIAx+rXv9cEcGx+buAF4npnhtTqCJk5KDFRnh3+KYj7rdVh6lsFt5/aPs+Irj9rZ33WMA7w==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "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/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz", + "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.33.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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-glob/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/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/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "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/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "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/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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-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-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/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/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/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==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "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==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "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/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": ">= 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/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "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": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "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/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "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/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/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "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/react-router": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.1.tgz", + "integrity": "sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==", + "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.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.1.tgz", + "integrity": "sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "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/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.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "dev": true, + "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.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } + }, + "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/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "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/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/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/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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.39.1.tgz", + "integrity": "sha512-GDUv6/NDYngUlNvwaHM1RamYftxf782IyEDbdj3SeaIHHv8fNQVRC++fITT7kUJV/5rIA/tkoRSSskt6osEfqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.39.1", + "@typescript-eslint/parser": "8.39.1", + "@typescript-eslint/typescript-estree": "8.39.1", + "@typescript-eslint/utils": "8.39.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "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/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/vite": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.2.tgz", + "integrity": "sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "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.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..e66c53a --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,32 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@types/react-router": "^5.1.20", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-router-dom": "^7.8.1" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/axios": "^0.9.36", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.0", + "eslint": "^9.33.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.1", + "vite": "^7.1.2" + } +} diff --git a/frontend/public/PUBLIC.md b/frontend/public/PUBLIC.md new file mode 100644 index 0000000..9fea55b --- /dev/null +++ b/frontend/public/PUBLIC.md @@ -0,0 +1,4 @@ + +# Anything you import in JS/CSS → src/assets/ + +# Anything you reference directly in HTML → public/ something like: \ No newline at end of file diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/App.css b/frontend/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/frontend/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/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..9db5a2d --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,10 @@ +import { useState } from 'react' +import './App.css' + +function App() { + return ( + /* */ + ) +} + +export default App \ No newline at end of file diff --git a/frontend/src/api/axios.ts b/frontend/src/api/axios.ts new file mode 100644 index 0000000..f7cd6be --- /dev/null +++ b/frontend/src/api/axios.ts @@ -0,0 +1,202 @@ +import axios from "axios"; + +const API_URL: string = `${import.meta.env.VITE_BACKEND_URL}/api`; + +// Axios instance, můžeme používat místo globálního axios +const axios_instance = axios.create({ + baseURL: API_URL, + withCredentials: true, // potřebné pro cookies +}); +axios_instance.defaults.xsrfCookieName = "csrftoken"; +axios_instance.defaults.xsrfHeaderName = "X-CSRFToken"; + +export default axios_instance; + +// 🔐 Axios response interceptor: automatická obnova při 401 +axios_instance.interceptors.request.use((config) => { + const getCookie = (name: string): string | null => { + let cookieValue: string | null = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let cookie of cookies) { + cookie = cookie.trim(); + if (cookie.startsWith(name + "=")) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + }; + + const csrfToken = getCookie("csrftoken"); + if (csrfToken && config.method && ["post", "put", "patch", "delete"].includes(config.method)) { + if (!config.headers) config.headers = {}; + config.headers["X-CSRFToken"] = csrfToken; + } + + return config; +}); + +// Přidej globální response interceptor pro redirect na login při 401 s detail hláškou +axios_instance.interceptors.response.use( + (response) => response, + (error) => { + if ( + error.response && + error.response.status === 401 && + error.response.data && + error.response.data.detail === "Nebyly zadány přihlašovací údaje." + ) { + window.location.href = "/login"; + } + return Promise.reject(error); + } +); + +// 🔄 Obnova access tokenu pomocí refresh cookie +export const refreshAccessToken = async (): Promise<{ access: string; refresh: string } | null> => { + try { + const res = await axios_instance.post(`/account/token/refresh/`); + return res.data as { access: string; refresh: string }; + } catch (err) { + console.error("Token refresh failed", err); + await logout(); + return null; + } +}; + + +// ✅ Přihlášení +export const login = async (username: string, password: string): Promise => { + await logout(); + try { + const response = await axios_instance.post(`/account/token/`, { username, password }); + return response.data; + } catch (err: any) { + if (err.response) { + // Server responded with a status code outside 2xx + console.log('Login error status:', err.response.status); + } else if (err.request) { + // Request was made but no response received + console.log('Login network error:', err.request); + } else { + // Something else happened + console.log('Login setup error:', err.message); + } + throw err; + } +}; + + +// ❌ Odhlášení s CSRF tokenem +export const logout = async (): Promise => { + try { + const getCookie = (name: string): string | null => { + let cookieValue: string | null = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let cookie of cookies) { + cookie = cookie.trim(); + if (cookie.startsWith(name + "=")) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + }; + + const csrfToken = getCookie("csrftoken"); + + const response = await axios_instance.post( + "/account/logout/", + {}, + { + headers: { + "X-CSRFToken": csrfToken, + }, + } + ); + console.log(response.data); + return response.data; // např. { detail: "Logout successful" } + } catch (err) { + console.error("Logout failed", err); + throw err; + } +}; + + +/** + * 📡 Obecný request pro API + * + * @param method - HTTP metoda (např. "get", "post", "put", "patch", "delete") + * @param endpoint - API endpoint (např. "/api/service-tickets/") + * @param data - data pro POST/PUT/DELETE requesty + * @param config - další konfigurace pro axios request + * @returns Promise - vrací data z odpovědi + */ +export const apiRequest = async ( + method: string, + endpoint: string, + data: Record = {}, + config: Record = {} +): Promise => { + const url = endpoint.startsWith("/") ? endpoint : `/${endpoint}`; + + try { + const response = await axios_instance({ + method, + url, + data: ["post", "put", "patch"].includes(method.toLowerCase()) ? data : undefined, + params: ["get", "delete"].includes(method.toLowerCase()) ? data : undefined, + ...config, + }); + + return response.data; + + } catch (err: any) { + if (err.response) { + // Server odpověděl s kódem mimo rozsah 2xx + console.error("API Error:", { + status: err.response.status, + data: err.response.data, + headers: err.response.headers, + }); + } else if (err.request) { + // Request byl odeslán, ale nedošla odpověď + console.error("No response received:", err.request); + } else { + // Něco jiného se pokazilo při sestavování requestu + console.error("Request setup error:", err.message); + } + + throw err; + } +}; + + + + + + + +// 👤 Funkce pro získání aktuálně přihlášeného uživatele +export async function getCurrentUser(): Promise { + const response = await axios_instance.get(`${API_URL}/account/user/me/`); + return response.data; // vrací data uživatele +} + +// 🔒 ✔️ Jednoduchá funkce, která kontroluje přihlášení - můžeš to upravit dle potřeby +export async function isAuthenticated(): Promise { + try { + const user = await getCurrentUser(); + return user != null; + } catch (err) { + return false; // pokud padne 401, není přihlášen + } +} + + + +export { axios_instance, API_URL }; \ No newline at end of file diff --git a/frontend/src/api/external.ts b/frontend/src/api/external.ts new file mode 100644 index 0000000..cc4face --- /dev/null +++ b/frontend/src/api/external.ts @@ -0,0 +1,26 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; + +/** + * Makes a general external API call using axios. + * + * @param url - The full URL of the external API endpoint. + * @param method - HTTP method (GET, POST, PUT, PATCH, DELETE, etc.). + * @param data - Request body data (for POST, PUT, PATCH). Optional. + * @param config - Additional Axios request config (headers, params, etc.). Optional. + * @returns Promise resolving to AxiosResponse. + * + * @example externalApiCall("https://api.example.com/data", "post", { foo: "bar" }, { headers: { Authorization: "Bearer token" } }) + */ +export async function externalApiCall( + url: string, + method: AxiosRequestConfig["method"], + data?: any, + config?: AxiosRequestConfig +): Promise> { + return axios({ + url, + method, + data, + ...config, + }); +} diff --git a/frontend/src/api/get_chocies.ts b/frontend/src/api/get_chocies.ts new file mode 100644 index 0000000..8e014e3 --- /dev/null +++ b/frontend/src/api/get_chocies.ts @@ -0,0 +1,41 @@ +import { apiRequest } from "./axios"; + +/** + * Loads enum values from an OpenAPI schema for a given path, method, and field (e.g., category). + * + * @param path - API path, e.g., "/api/service-tickets/" + * @param method - HTTP method + * @param field - field name in parameters or request + * @param schemaUrl - URL of the JSON schema, default "/api/schema/?format=json" + * @returns Promise> + */ +export async function fetchEnumFromSchemaJson( + path: string, + method: "get" | "post" | "patch" | "put", + field: string, + schemaUrl: string = "/schema/?format=json" +): Promise> { + try { + const schema = await apiRequest("get", schemaUrl); + + const methodDef = schema.paths?.[path]?.[method]; + if (!methodDef) { + throw new Error(`Method ${method.toUpperCase()} for ${path} not found in schema.`); + } + + // Search in "parameters" (e.g., GET query parameters) + const param = methodDef.parameters?.find((p: any) => p.name === field); + + if (param?.schema?.enum) { + return param.schema.enum.map((val: string) => ({ + value: val, + label: val, + })); + } + + throw new Error(`Field '${field}' does not contain enum`); + } catch (error) { + console.error("Error loading enum values:", error); + throw error; + } +} diff --git a/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff b/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff new file mode 100644 index 0000000..a8df7f1 Binary files /dev/null and b/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff differ diff --git a/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff2 b/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff2 new file mode 100644 index 0000000..83ea806 Binary files /dev/null and b/frontend/src/assets/fonts/windows-98/ms_sans_serif.woff2 differ diff --git a/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff b/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff new file mode 100644 index 0000000..44064b3 Binary files /dev/null and b/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff differ diff --git a/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff2 b/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff2 new file mode 100644 index 0000000..610c091 Binary files /dev/null and b/frontend/src/assets/fonts/windows-98/ms_sans_serif_bold.woff2 differ diff --git a/frontend/src/assets/img/cursor/Sata.png b/frontend/src/assets/img/cursor/Sata.png new file mode 100644 index 0000000..f25c11b Binary files /dev/null and b/frontend/src/assets/img/cursor/Sata.png differ diff --git a/frontend/src/assets/img/cursor/omagad.png b/frontend/src/assets/img/cursor/omagad.png new file mode 100644 index 0000000..ed99905 Binary files /dev/null and b/frontend/src/assets/img/cursor/omagad.png differ diff --git a/frontend/src/assets/img/cursor/pointing(inactive).png b/frontend/src/assets/img/cursor/pointing(inactive).png new file mode 100644 index 0000000..973def7 Binary files /dev/null and b/frontend/src/assets/img/cursor/pointing(inactive).png differ diff --git a/frontend/src/assets/img/cursor/pointing.png b/frontend/src/assets/img/cursor/pointing.png new file mode 100644 index 0000000..5470b43 Binary files /dev/null and b/frontend/src/assets/img/cursor/pointing.png differ diff --git a/frontend/src/assets/img/cursor/pointing2.png b/frontend/src/assets/img/cursor/pointing2.png new file mode 100644 index 0000000..e8d9b24 Binary files /dev/null and b/frontend/src/assets/img/cursor/pointing2.png differ diff --git a/frontend/src/assets/img/errors/403.png b/frontend/src/assets/img/errors/403.png new file mode 100644 index 0000000..46c151f Binary files /dev/null and b/frontend/src/assets/img/errors/403.png differ diff --git a/frontend/src/assets/img/errors/404.png b/frontend/src/assets/img/errors/404.png new file mode 100644 index 0000000..7c7c82c Binary files /dev/null and b/frontend/src/assets/img/errors/404.png differ diff --git a/frontend/src/assets/img/errors/500.png b/frontend/src/assets/img/errors/500.png new file mode 100644 index 0000000..945f4e5 Binary files /dev/null and b/frontend/src/assets/img/errors/500.png differ diff --git a/frontend/src/assets/img/errors/error_icon.png b/frontend/src/assets/img/errors/error_icon.png new file mode 100644 index 0000000..6b966a2 Binary files /dev/null and b/frontend/src/assets/img/errors/error_icon.png differ diff --git a/frontend/src/assets/img/job.png b/frontend/src/assets/img/job.png new file mode 100644 index 0000000..e9fe220 Binary files /dev/null and b/frontend/src/assets/img/job.png differ diff --git a/frontend/src/assets/img/svg/default-background.svg b/frontend/src/assets/img/svg/default-background.svg new file mode 100644 index 0000000..1ea0608 --- /dev/null +++ b/frontend/src/assets/img/svg/default-background.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/svg/default-chat.svg b/frontend/src/assets/img/svg/default-chat.svg new file mode 100644 index 0000000..1bed894 --- /dev/null +++ b/frontend/src/assets/img/svg/default-chat.svg @@ -0,0 +1,10 @@ + + + + + + Layer 1 + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/svg/default-pfp.svg b/frontend/src/assets/img/svg/default-pfp.svg new file mode 100644 index 0000000..a1e1201 --- /dev/null +++ b/frontend/src/assets/img/svg/default-pfp.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/svg/menu-symbol.svg b/frontend/src/assets/img/svg/menu-symbol.svg new file mode 100644 index 0000000..44b106d --- /dev/null +++ b/frontend/src/assets/img/svg/menu-symbol.svg @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/test.png b/frontend/src/assets/img/test.png new file mode 100644 index 0000000..5de558f Binary files /dev/null and b/frontend/src/assets/img/test.png differ diff --git a/frontend/src/assets/robots.txt b/frontend/src/assets/robots.txt new file mode 100644 index 0000000..066b6d6 --- /dev/null +++ b/frontend/src/assets/robots.txt @@ -0,0 +1,11 @@ +Sitemap: https://vontor.com/sitemap.xml +Disallow: /admin/ +Allow: / +Allow: /social/public/ +Allow: /social/post/ +Allow: /social/community/ +Allow: /social/main/ +Allow: /social/profile/ +Allow: /social/login/ +Allow: /social/register/ +Crawl-delay: 10 \ No newline at end of file diff --git a/frontend/src/components/Footer/footer.jsx b/frontend/src/components/Footer/footer.jsx new file mode 100644 index 0000000..353ae76 --- /dev/null +++ b/frontend/src/components/Footer/footer.jsx @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/frontend/src/components/Footer/footer.tsx b/frontend/src/components/Footer/footer.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/components/Forms/ContactMe/ContactMeForm.jsx b/frontend/src/components/Forms/ContactMe/ContactMeForm.jsx new file mode 100644 index 0000000..ef1596b --- /dev/null +++ b/frontend/src/components/Forms/ContactMe/ContactMeForm.jsx @@ -0,0 +1,99 @@ +/*TODO: Implement the contact form functionality*/ + +{% load static %} + + + +
+
+ +
+
+
+ {% csrf_token %} + {{ contactme_form }} + + +
+
+
+
+ +
+ + + +contact-me.js: + +$(document).ready(function () { + $("#contactme-form").submit(function (event) { + event.preventDefault(); // Prevent normal form submission + + $.ajax({ + url: "/submit-contactme/", // URL of the Django view + type: "POST", + data: $(this).serialize(), // Serialize form data + success: function (response) { + if (response.success) { + close_contact(); + + $("#contactme-form .success-form-alert").fadeIn(); + $("#contactme-form")[0].reset(); // Clear the form + + alert("Zpráva odeslaná!") + } + }, + error: function (response) { + alert("Zpráva nebyla odeslaná, zkontrolujte si připojení k internetu nebo naskytl u nás problém :(") + } + }); + + }); + + $("#contactme-form .success-form .close").click(function () { + $("#contactme-form .success-form-alert").fadeOut(); + }); + + var opened_contact = false; + + $(document).on("click", ".contact-me .opening", function () { + console.log("toggle mail"); + + const opening = $(".contact-me .opening"); + + + + + // Check if we're opening or closing + if (opened_contact === false) { + // Toggle rotation + opening.toggleClass('rotate-opening'); + + // Wait for the rotation to finish + setTimeout(function() { + $(".contact-me .content").addClass('content-moveup-index'); + }, 500); + + setTimeout(function() { + $(".contact-me .content")[0].offsetHeight; + + $(".contact-me .content").addClass('content-moveup'); + }, 1000); // Small delay to trigger transition + + opened_contact = true; + } else { + close_contact(); + } + }); + + function close_contact(){ + $(".contact-me .content").removeClass('content-moveup'); + + setTimeout(function() { + $(".contact-me .content").toggleClass('content-moveup-index'); + $(".contact-me .opening").toggleClass('rotate-opening'); + }, 700); + + opened_contact = false; + } +}); \ No newline at end of file diff --git a/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx b/frontend/src/components/Forms/ContactMe/ContactMeForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/components/Forms/ContactMe/contact-me.module.css b/frontend/src/components/Forms/ContactMe/contact-me.module.css new file mode 100644 index 0000000..19df71a --- /dev/null +++ b/frontend/src/components/Forms/ContactMe/contact-me.module.css @@ -0,0 +1,140 @@ +.contact-me { + margin: 5em auto; + position: relative; + + aspect-ratio: 16 / 9; + + background-color: #c8c8c8; + max-width: 100vw; +} +.contact-me + .mail-box{ + +} + +.contact-me .opening { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + + z-index: 2; + transform-origin: top; + + padding-top: 4em; + + clip-path: polygon(0 0, 100% 0, 50% 50%); + background-color: #d2d2d2; + + transition: all 1s ease; + + text-align: center; +} +.rotate-opening{ + background-color: #c8c8c8; + transform: rotateX(180deg); +} + + + +.contact-me .content { + position: relative; + height: 100%; + width: 100%; + z-index: 1; + transition: all 1s ease-out; +} +.content-moveup{ + transform: translateY(-70%); +} +.content-moveup-index { + z-index: 2 !important; +} + +.contact-me .content form{ + width: 80%; + display: flex; + gap: 1em; + flex-direction: column; + align-items: flex-start; + justify-content: center; + margin: auto; + background-color: #deefff; + padding: 1em; + border: 0.5em dashed #88d4ed; + border-radius: 0.25em; +} +.contact-me .content form div{ + width: -webkit-fill-available; + display: flex; + flex-direction: column; +} +.contact-me .content form input[type=submit]{ + margin: auto; + border: none; + background: #4ca4d5; + color: #ffffff; + padding: 1em 1.5em; + cursor: pointer; + border-radius: 1em; +} + +.contact-me .content form input[type=text], +.contact-me .content form input[type=email], +.contact-me .content form textarea{ + background-color: #bfe8ff; + border: none; + border-bottom: 0.15em solid #064c7d; + padding: 0.5em; + +} + + + +.contact-me .cover { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2; + clip-path: polygon(0 0, 50% 50%, 100% 0, 100% 100%, 0 100%); + background-color: #f0f0f0; +} +.contact-me .triangle{ + position: absolute; + bottom: 0; + right: 0; + z-index: 3; + width: 100%; + height: 100%; + clip-path: polygon(100% 0, 0 100%, 100% 100%); + background-color: rgb(255 255 255); +} + +@keyframes shake { + 0% { transform: translateX(0); } + 25% { transform: translateX(-2px) rotate(-8deg); } + 50% { transform: translateX(2px) rotate(4deg); } + 75% { transform: translateX(-1px) rotate(-2deg); } + 100% { transform: translateX(0); } +} + + +.contact-me .opening i { + color: #797979; + font-size: 5em; + display: inline-block; + animation: 0.4s ease-in-out 2s infinite normal none running shake; + animation-delay: 2s; + animation-iteration-count: infinite; +} + + + +@media only screen and (max-width: 990px){ + .contact-me{ + aspect-ratio: unset; + margin-top: 7ch; + } +} diff --git a/frontend/src/components/Forms/ContactMe/readme.png b/frontend/src/components/Forms/ContactMe/readme.png new file mode 100644 index 0000000..b3a6ab7 Binary files /dev/null and b/frontend/src/components/Forms/ContactMe/readme.png differ diff --git a/frontend/src/components/navbar/navbar.jsx b/frontend/src/components/navbar/navbar.jsx new file mode 100644 index 0000000..3f3bce4 --- /dev/null +++ b/frontend/src/components/navbar/navbar.jsx @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/src/components/navbar/navbar.tsx b/frontend/src/components/navbar/navbar.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/features/ads/Drone/Drone.jsx b/frontend/src/features/ads/Drone/Drone.jsx new file mode 100644 index 0000000..1361c52 --- /dev/null +++ b/frontend/src/features/ads/Drone/Drone.jsx @@ -0,0 +1,83 @@ +{% load static %} +
+ + + +
+
+

Letecké snímky dronem

+
+ +
+
+

Opravnění

+ + + A1, A2, A3 a průkaz na vysílačku! + + Mohu garantovat bezpečný provoz dronu i ve složitějších podmínkách. Mám také možnost žádat o povolení k letu v blízkosti letišť! + +
+
+

Cena

+ + Nabízím letecké záběry dronem
za cenu 3 000 Kč. + + Pokud se nacházíte v Ostravě, doprava je zdarma. Pro oblasti mimo Ostravu účtuji 10 Kč/km. + + Cena se může odvíjet ještě podle složitosti získaní povolení.* +
+
+

Výstup

+ + Rád Vám připravím jednoduchý sestřih videa, který můžete rychle použít, nebo Vám mohu poskytnout samotné záběry k vlastní editaci.
+ +
+
+
+ V případě zájmu mě neváhejte
kontaktovat! +
+
+ +
+ + + +drone.js: + +$(document).ready(function () { + function setVideoDroneQuality() { + $sourceElement = $("#video-source"); + + const videoSources = { + fullHD: 'static/home/video/drone-background-video-1080p.mp4', // For desktops (1920x1080) + hd: 'static/home/video/drone-background-video-720p.mp4', // For tablets/smaller screens (1280x720) + lowRes: 'static/home/video/drone-background-video-480p.mp4' // For mobile devices or low performance (854x480) + }; + + const screenWidth = $(window).width(); // Get screen width + + // Determine the appropriate video source + if (screenWidth >= 1920) { + $sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.fullHD); + } else if (screenWidth >= 1280) { + $sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.hd); + } else { + $sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.lowRes); + } + + // Reload the video + $('#drone-video')[0].load(); + + console.log("video set!"); + + } + + setTimeout(1000); + + setVideoDroneQuality(); + //$("#debug-drone").click(setVideoDroneQuality); +}); diff --git a/frontend/src/features/ads/Drone/drone.module.css b/frontend/src/features/ads/Drone/drone.module.css new file mode 100644 index 0000000..9f44e4c --- /dev/null +++ b/frontend/src/features/ads/Drone/drone.module.css @@ -0,0 +1,103 @@ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap'); + + + + +.drone{ + margin-top: -4em; + font-style: normal; + + width: 100%; + position: relative; + color: white; +} + + +.drone .video-background { + height: 100%; + width: 100%; + position: absolute; + object-fit: cover; + z-index: -1; + + clip-path: polygon(0 3%, 15% 0, 30% 7%, 42% 3%, 61% 1%, 82% 5%, 100% 1%, 100% 94%, 82% 100%, 65% 96%, 47% 99%, 30% 90%, 14% 98%, 0 94%); +} + + +.drone article{ + padding: 5em; + + display: flex; + + border-radius: 2em; + padding: 3em; + gap: 2em; + + position: relative; + + align-items: center; + flex-direction: column; + justify-content: space-evenly; +} +.drone article header h1{ + font-size: 4em; + + font-weight: 300; +} +.drone article header{ + flex: 1; +} +.drone article main{ + width: 90%; + display: flex; + font-size: 1em; + /* width: 60%; */ + flex: 2; + flex-direction: row; + + font-weight: 400; + + gap: 2em; + /* flex-wrap: wrap; */ + justify-content: space-evenly; +} +.drone a{ + color: white; +} +.drone article div{ + display: flex; + flex: 1; + font-size: 1.25em; + margin-top: 1em; + margin-bottom: 1em; + flex-direction: column; + align-items: center; + font-weight: 400; +} + + +@media only screen and (max-width: 990px) { + .drone article header h1{ + font-size: 2.3em; + + font-weight: 200; + } + .drone article header{ + text-align: center; + } + + .drone article main{ + flex-direction: column; + font-size: 1em; + } + .drone article{ + height: auto; + } + .drone article div{ + margin: 2em; + text-align: center; + } + .drone video{ + display: none; + } +} \ No newline at end of file diff --git a/frontend/src/features/ads/Drone/readme.png b/frontend/src/features/ads/Drone/readme.png new file mode 100644 index 0000000..8bf3fb0 Binary files /dev/null and b/frontend/src/features/ads/Drone/readme.png differ diff --git a/frontend/src/features/ads/Portfolio/Portfolio.jsx b/frontend/src/features/ads/Portfolio/Portfolio.jsx new file mode 100644 index 0000000..e73faf3 --- /dev/null +++ b/frontend/src/features/ads/Portfolio/Portfolio.jsx @@ -0,0 +1,50 @@ +{% load static %} +
+
+

Portfolio

+
+ +
+ +
+
+ davo1.cz logo +
+
+
+
+
+
+ Perlica logo +
+
+
+
+
+
+ Epinger2 logo +
+
+
+
+
+ +
+ + + +portfolio.js: + +$(document).ready(function () { + var doorOpen= false; + + $(".door").click(function(){ + doorOpen = !doorOpen;//převrátí hodnotu + + if ($(".door").hasClass('door-open')){ + $(".door").removeClass('door-open'); + }else{ + $(".door").addClass('door-open'); + } + }); +}); \ No newline at end of file diff --git a/frontend/src/features/ads/Portfolio/Portfolio.module.css b/frontend/src/features/ads/Portfolio/Portfolio.module.css new file mode 100644 index 0000000..3a1055e --- /dev/null +++ b/frontend/src/features/ads/Portfolio/Portfolio.module.css @@ -0,0 +1,155 @@ +.portfolio { + margin: auto; + margin-top: 10em; + width: 80%; + display: flex; + flex-wrap: wrap; + align-content: center; + color: white; + position: relative; +} + +.portfolio div .door { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + bottom: 0; + left: 0; + + height: 100%; + width: 100%; + background-color: #c2a67d; + + border-radius: 1em; + + transform-origin: bottom; + transition: transform 0.5s ease-in-out; + + z-index: 3; + +} + +@keyframes shake { + 0% { transform: translateX(0); } + 25% { transform: translateX(-2px) rotate(-8deg); } + 50% { transform: translateX(2px) rotate(4deg); } + 75% { transform: translateX(-1px) rotate(-2deg); } + 100% { transform: translateX(0); } +} + +.door i{ + color: #5e5747; + font-size: 5em; + display: inline-block; + animation: shake 0.4s ease-in-out infinite; + animation-delay: 2s; + animation-iteration-count: infinite; +} + +.portfolio .door-open{ + transform: rotateX(180deg); +} + +.portfolio>header { + width: fit-content; + position: absolute; + z-index: 5; + top: -4.7em; + left: 0; + padding: 1em 3em; + padding-bottom: 0; + background-color: #cdc19c; + color: #5e5747; + border-top-left-radius: 1em; + border-top-right-radius: 1em; +} + +.portfolio>header h1 { + font-size: 2.5em; + padding: 0; +} + +.portfolio>header i { + font-size: 6em; +} + +.portfolio article{ + position: relative; +} +.portfolio article::after{ + clip-path: polygon(0% 0%, 11% 12.5%, 0% 25%, 11% 37.5%, 0% 50%, 11% 62.5%, 0% 75%, 11% 87.5%, 0% 100%, 100% 100%, 84% 87.5%, 98% 75%, 86% 62.5%, 100% 50%, 86% 37.5%, 100% 25%, 93% 12.5%, 100% 0%); + content: ""; + bottom: 0; + right: -2em; + + height: 2em; + width: 6em; + transform: rotate(-45deg); + + position: absolute; + background-color: rgba(255, 255, 255, 0.5); +} +.portfolio article::before{ + clip-path: polygon(0% 0%, 11% 12.5%, 0% 25%, 11% 37.5%, 0% 50%, 11% 62.5%, 0% 75%, 11% 87.5%, 0% 100%, 100% 100%, 84% 87.5%, 98% 75%, 86% 62.5%, 100% 50%, 86% 37.5%, 100% 25%, 93% 12.5%, 100% 0%); + content: ""; + top: 0; + left: -2em; + + height: 2em; + width: 6em; + transform: rotate(-45deg); + + position: absolute; + background-color: rgba(255, 255, 255, 0.5); +} + +.portfolio article header { + display: flex; + flex-direction: column; + align-items: center; +} + + +.portfolio div { + padding: 3em; + background-color: #cdc19c; + display: flex; + justify-content: center; + flex-wrap: wrap; + + gap: 5em; + + border-radius: 1em; + border-top-left-radius: 0; +} + +.portfolio div article { + display: flex; + border-radius: 0em; + background-color: #9c885c; + width: 30%; + text-align: center; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.portfolio div article header a img { + padding: 2em 0; + width: 80%; + margin: auto; +} + + + + +@media only screen and (max-width: 990px) { + .portfolio div{ + flex-direction: column; + align-items: center; + } + .portfolio div article{ + width: 100%; + } +} \ No newline at end of file diff --git a/frontend/src/features/ads/Portfolio/readme.png b/frontend/src/features/ads/Portfolio/readme.png new file mode 100644 index 0000000..9330f14 Binary files /dev/null and b/frontend/src/features/ads/Portfolio/readme.png differ diff --git a/frontend/src/features/auth/LogOut.jsx b/frontend/src/features/auth/LogOut.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/features/auth/LoginForm.jsx b/frontend/src/features/auth/LoginForm.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..08a3ac9 --- /dev/null +++ b/frontend/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/frontend/src/layouts/AuthLayout.jsx b/frontend/src/layouts/AuthLayout.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/layouts/HomeLayout.jsx b/frontend/src/layouts/HomeLayout.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/layouts/HomeLayout.tsx b/frontend/src/layouts/HomeLayout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/layouts/LAYOUTS.md b/frontend/src/layouts/LAYOUTS.md new file mode 100644 index 0000000..e709ee3 --- /dev/null +++ b/frontend/src/layouts/LAYOUTS.md @@ -0,0 +1,69 @@ +# Layouts in React Router + +## 📌 What is a Layout? +A **layout** in React Router is just a **React component** that wraps multiple pages with shared structure or styling (e.g., header, footer, sidebar). + +Layouts usually contain: +- Global UI elements (navigation, footer, etc.) +- An `` component where nested routes will render their content + +--- + +## 📂 Folder Structure Example + +src/ +layouts/ +├── MainLayout.jsx +└── AdminLayout.jsx +pages/ +├── HomePage.jsx +├── AboutPage.jsx +└── DashboardPage.jsx + + +--- + +## 🛠 How Layouts Are Used in Routes + +### 1. Layout as a Parent Route +Use the layout component as the `element` of a **parent route** and place **pages** inside as nested routes. + +```jsx +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import MainLayout from "./layouts/MainLayout"; +import HomePage from "./pages/HomePage"; +import AboutPage from "./pages/AboutPage"; + +function App() { + return ( + + + }> + } /> + } /> + + + + ); +} + +export default App; +``` + +### 2. Inside the MainLayout.jsx + +```jsx +import { Outlet } from "react-router-dom"; + +export default function MainLayout() { + return ( + <> +
Header
+
+ +
+
Footer
+ + ); +} +``` \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/frontend/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/frontend/src/pages/home/Home.module.css b/frontend/src/pages/home/Home.module.css new file mode 100644 index 0000000..f0600ea --- /dev/null +++ b/frontend/src/pages/home/Home.module.css @@ -0,0 +1,265 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Doto:wght@100..900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Doto:wght@300&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap'); + +@import url('https://fonts.googleapis.com/css2?family=Exo:ital,wght@0,100..900;1,100..900&display=swap'); + +html{ + scroll-behavior: smooth; +} + +body{ + font-family: "Exo", serif; + + + font-optical-sizing: auto; + font-weight: 700; + font-style: normal; +} + +.wrapper { + position: relative; + width: 100%; +} + +.doto-font{ + font-family: "Doto", serif; + font-optical-sizing: auto; + font-weight: 300; + font-style: normal; + font-variation-settings: "ROND" 0; +} +.bebas-neue-regular { + font-family: "Bebas Neue", sans-serif; + font-weight: 400; + font-style: normal; +} +footer a{ + color: var(--c-text); + text-decoration: none; +} +footer a i{ + color: white; + text-decoration: none; +} +footer{ + font-family: "Roboto Mono", monospace; + + background-color: var(--c-boxes); + + margin-top: 2em; + display: flex; + + color: white; + align-items: center; + justify-content: space-evenly; +} +footer address{ + padding: 1em; + font-style: normal; +} +footer .contacts{ + font-size: 2em; + +} + +@media only screen and (max-width: 990px){ + footer{ + flex-direction: column; + padding-bottom: 1em; + padding-top: 1em; + } + } + + .introduction { + display: flex; + flex-direction: column; + color: var(--c-text); + + padding-bottom: 10em; + margin-top: 6em; + + width: 100%; + position: relative; + top:0; + + /* gap: 4em;*/ +} +.introduction h1{ + font-size: 2em; +} + +.introduction article { + /*background-color: cadetblue;*/ + + padding: 2em; + border-radius: 1em; +} + +.introduction article header {} + +.introduction article:nth-child(1) { + width: 100%; + /* transform: rotate(5deg); */ + align-self: center; + text-align: center; + font-size: 2em; +} +/* +.introduction article:nth-child(2) { + width: 50%; + transform: rotate(3deg); + align-self: flex-end; +} + +.introduction article:nth-child(3) { + width: 50%; + transform: rotate(-2deg); + align-self: flex-start; +}*/ + + + + +.animation-introduction{ + position: absolute; + width: 100%; + height: 100%; + top: 0; + z-index: -2; +} + +.animation-introduction ul{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + /*overflow: hidden; ZAPNOUT KDYŽ NECHCEŠ ANIMACI PŘECHÁZET DO OSTATNÍCH DIVŮ*/ +} + +.animation-introduction ul li{ + position: absolute; + display: block; + list-style: none; + width: 20px; + height: 20px; + background: rgba(255, 255, 255, 35%); + animation: animate 4s linear infinite; + bottom: -150px; + +} + +.animation-introduction ul li:nth-child(1){ + left: 25%; + width: 80px; + height: 80px; + animation-delay: 0s; +} + + +.animation-introduction ul li:nth-child(2){ + left: 10%; + width: 20px; + height: 20px; + animation-delay: 2s; + animation-duration: 12s; +} + +.animation-introduction ul li:nth-child(3){ + left: 70%; + width: 20px; + height: 20px; + animation-delay: 4s; +} + +.animation-introduction ul li:nth-child(4){ + left: 40%; + width: 60px; + height: 60px; + animation-delay: 0s; + animation-duration: 18s; +} + +.animation-introduction ul li:nth-child(5){ + left: 65%; + width: 20px; + height: 20px; + animation-delay: 0s; +} + +.animation-introduction ul li:nth-child(6){ + left: 75%; + width: 110px; + height: 110px; + animation-delay: 3s; +} + +.animation-introduction ul li:nth-child(7){ + left: 35%; + width: 150px; + height: 150px; + animation-delay: 7s; +} + +.animation-introduction ul li:nth-child(8){ + left: 50%; + width: 25px; + height: 25px; + animation-delay: 15s; + animation-duration: 45s; +} + +.animation-introduction ul li:nth-child(9){ + left: 20%; + width: 15px; + height: 15px; + animation-delay: 2s; + animation-duration: 35s; +} + +.animation-introduction ul li:nth-child(10){ + left: 85%; + width: 150px; + height: 150px; + animation-delay: 0s; + animation-duration: 11s; +} + + + +@keyframes animate { + + 0%{ + transform: translateY(0) rotate(0deg); + opacity: 1; + border-radius: 0; + } + + 100%{ + transform: translateY(-1000px) rotate(720deg); + opacity: 0; + border-radius: 50%; + } + +} + + +@media only screen and (max-width: 990px) { + .animation-introduction ul li:nth-child(6){ + left: 67%; + } + .animation-introduction ul li:nth-child(10) { + left: 60%; + } + .introduction { + margin: 0; + top: 0; + } + + .introduction article { + width: auto !important; + transform: none !important; + align-self: none !important; + } +} \ No newline at end of file diff --git a/frontend/src/pages/home/HomeNav.module.css b/frontend/src/pages/home/HomeNav.module.css new file mode 100644 index 0000000..a65eb83 --- /dev/null +++ b/frontend/src/pages/home/HomeNav.module.css @@ -0,0 +1,142 @@ +nav{ + padding: 1.1em; + + font-family: "Roboto Mono", monospace; + + position: -webkit-sticky; + position: sticky; + top: 0; /* required */ + + transition: top 1s ease-in-out, border-radius 1s ease-in-out; + + + + z-index: 5; + padding-left: 2em; + padding-right: 2em; + width: max-content; + + background: var(--c-boxes); + /*background: -moz-linear-gradient(117deg, rgba(34,34,34,1) 0%, rgba(59,54,54,1) 100%); + background: -webkit-linear-gradient(117deg, rgba(34,34,34,1) 0%, rgba(59,54,54,1) 100%); + background: linear-gradient(117deg, rgba(34,34,34,1) 0%, rgba(59,54,54,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#222222",endColorstr="#3b3636",GradientType=1);*/ + + color: #fff; + text-align: center; + + margin: auto; + + border-radius: 2em; +} +nav.isSticky-nav{ + border-top-left-radius: 0; + border-top-right-radius: 0; +} +nav ul #nav-logo{ + border-right: 0.2em solid var(--c-lines); +} +nav ul #nav-logo span{ + line-height: 0.75; + font-size: 1.5em; +} +nav a{ + color: #fff; + transition: color 1s; + + position: relative; + text-decoration: none; +} + +nav a:hover{ + color: #fff; +} + +nav a::before { + content: ""; + position: absolute; + display: block; + width: 100%; + height: 2px; + bottom: 0; + left: 0; + background-color: #fff; + transform: scaleX(0); + transition: transform 0.3s ease; +} +nav a:hover::before { + transform: scaleX(1); +} + + +nav ul { + list-style: none; + padding: 0; +} + +nav ul li { + display: inline; + padding: 0 3em; +} + +nav ul li a { + text-decoration: none; +} +#toggle-nav{ + display: none; + + -webkit-transition: transform 0.5s ease; + -moz-transition: transform 0.5s ease; + -o-transition: transform 0.5s ease; + -ms-transition: transform 0.5s ease; + transition: transform 0.5s ease; +} +.toggle-nav-rotated { + transform: rotate(360deg); +} +.nav-open{ + max-height: 20em; +} +@media only screen and (max-width: 990px){ + #toggle-nav{ + margin-top: 0.25em; + margin-left: 0.75em; + position: absolute; + left: 0; + display: block; + font-size: 2em; + } + nav{ + width: 100%; + padding: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 1em; + border-bottom-right-radius: 1em; + overflow: hidden; + } + nav ul { + margin-top: 1em; + gap: 2em; + display: flex; + flex-direction: column; + + -webkit-transition: max-height 1s ease; + -moz-transition: max-height 1s ease; + -o-transition: max-height 1s ease; + -ms-transition: max-height 1s ease; + transition: max-height 1s ease; + + max-height: 2em; + } + nav ul:last-child{ + padding-bottom: 1em; + } + nav ul #nav-logo { + margin: auto; + padding-bottom: 0.5em; + margin-bottom: -1em; + border-bottom: 0.2em solid var(--c-lines); + border-right: none; + } + } \ No newline at end of file diff --git a/frontend/src/pages/home/home.jsx b/frontend/src/pages/home/home.jsx new file mode 100644 index 0000000..812fa62 --- /dev/null +++ b/frontend/src/pages/home/home.jsx @@ -0,0 +1,42 @@ +import React from "react"; +import styles from "./Home.module.css"; + +export default function Home() { + return ( +
+

Vítejte na hlavní stránce

+

Toto je obsah jen pro home page.

+
+ ); +} + + +$(document).ready(function () { + + $("body").click(function(event){ + var randomId = "spark-" + Math.floor(Math.random() * 100000); + var $spark = $("
").addClass("spark-cursor").attr("id", randomId); + $("body").append($spark); + + // Nastavení pozice + $spark.css({ + "top": event.pageY + "px", + "left": event.pageX + "px", + "filter": "hue-rotate(" + Math.random() * 360 + "deg)" + }); + + for (let index = 0; index < 8; index++) { + let $span = $(""); + $span.css("transform", 'rotate(' + (index * 45) +"deg)" ); + $spark.append($span); + } + + setTimeout(() => { + $spark.find("span").addClass("animate"); + }, 10); + + setTimeout(function(){ + $("#" + randomId).remove(); + }, 1000); + }); +}); \ No newline at end of file diff --git a/frontend/src/pages/home/introduction.css b/frontend/src/pages/home/introduction.css new file mode 100644 index 0000000..f023809 --- /dev/null +++ b/frontend/src/pages/home/introduction.css @@ -0,0 +1,192 @@ +.introduction { + display: flex; + flex-direction: column; + color: var(--c-text); + + padding-bottom: 10em; + margin-top: 6em; + + width: 100%; + position: relative; + top:0; + + /* gap: 4em;*/ +} +.introduction h1{ + font-size: 2em; +} + +.introduction article { + /*background-color: cadetblue;*/ + + padding: 2em; + border-radius: 1em; +} + +.introduction article header {} + +.introduction article:nth-child(1) { + width: 100%; + /* transform: rotate(5deg); */ + align-self: center; + text-align: center; + font-size: 2em; +} +/* +.introduction article:nth-child(2) { + width: 50%; + transform: rotate(3deg); + align-self: flex-end; +} + +.introduction article:nth-child(3) { + width: 50%; + transform: rotate(-2deg); + align-self: flex-start; +}*/ + + + + +.animation-introduction{ + position: absolute; + width: 100%; + height: 100%; + top: 0; + z-index: -2; +} + +.animation-introduction ul{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + /*overflow: hidden; ZAPNOUT KDYŽ NECHCEŠ ANIMACI PŘECHÁZET DO OSTATNÍCH DIVŮ*/ +} + +.animation-introduction ul li{ + position: absolute; + display: block; + list-style: none; + width: 20px; + height: 20px; + background: rgba(255, 255, 255, 35%); + animation: animate 4s linear infinite; + bottom: -150px; + +} + +.animation-introduction ul li:nth-child(1){ + left: 25%; + width: 80px; + height: 80px; + animation-delay: 0s; +} + + +.animation-introduction ul li:nth-child(2){ + left: 10%; + width: 20px; + height: 20px; + animation-delay: 2s; + animation-duration: 12s; +} + +.animation-introduction ul li:nth-child(3){ + left: 70%; + width: 20px; + height: 20px; + animation-delay: 4s; +} + +.animation-introduction ul li:nth-child(4){ + left: 40%; + width: 60px; + height: 60px; + animation-delay: 0s; + animation-duration: 18s; +} + +.animation-introduction ul li:nth-child(5){ + left: 65%; + width: 20px; + height: 20px; + animation-delay: 0s; +} + +.animation-introduction ul li:nth-child(6){ + left: 75%; + width: 110px; + height: 110px; + animation-delay: 3s; +} + +.animation-introduction ul li:nth-child(7){ + left: 35%; + width: 150px; + height: 150px; + animation-delay: 7s; +} + +.animation-introduction ul li:nth-child(8){ + left: 50%; + width: 25px; + height: 25px; + animation-delay: 15s; + animation-duration: 45s; +} + +.animation-introduction ul li:nth-child(9){ + left: 20%; + width: 15px; + height: 15px; + animation-delay: 2s; + animation-duration: 35s; +} + +.animation-introduction ul li:nth-child(10){ + left: 85%; + width: 150px; + height: 150px; + animation-delay: 0s; + animation-duration: 11s; +} + + + +@keyframes animate { + + 0%{ + transform: translateY(0) rotate(0deg); + opacity: 1; + border-radius: 0; + } + + 100%{ + transform: translateY(-1000px) rotate(720deg); + opacity: 0; + border-radius: 50%; + } + +} + + +@media only screen and (max-width: 990px) { + .animation-introduction ul li:nth-child(6){ + left: 67%; + } + .animation-introduction ul li:nth-child(10) { + left: 60%; + } + .introduction { + margin: 0; + top: 0; + } + + .introduction article { + width: auto !important; + transform: none !important; + align-self: none !important; + } +} \ No newline at end of file diff --git a/frontend/src/pages/home/jquery-3.7.1.js b/frontend/src/pages/home/jquery-3.7.1.js new file mode 100644 index 0000000..798cc8b --- /dev/null +++ b/frontend/src/pages/home/jquery-3.7.1.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 stickyOffset; + //console.log("sticky: " + isSticky); + + $stickyElm.toggleClass('isSticky-nav', isSticky); + }); + + $('#toggle-nav').click(function () { + $('nav ul').toggleClass('nav-open'); + $('#toggle-nav').toggleClass('toggle-nav-rotated'); + }); +}); diff --git a/frontend/src/pages/home/reset.module.css b/frontend/src/pages/home/reset.module.css new file mode 100644 index 0000000..7468b5c --- /dev/null +++ b/frontend/src/pages/home/reset.module.css @@ -0,0 +1,76 @@ +/*https://www.joshwcomeau.com/css/custom-css-reset/*/ + + +/* 1. Use a more-intuitive box-sizing model */ +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* 2. Remove default margin */ +* { + margin: 0; +} + +body { + /* 3. Add accessible line-height */ + line-height: 1.5; + /* 4. Improve text rendering */ + -webkit-font-smoothing: antialiased; +} +ul, li{ + padding: 0; +} + +/* 5. Improve media defaults */ +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} + +/* 6. Inherit fonts for form controls */ +input, +button, +textarea, +select { + font: inherit; +} + +/* 7. Avoid text overflows */ +p, +h1, +h2, +h3, +h4, +h5, +h6 { + padding-bottom: 0.5ch; + overflow-wrap: break-word; +} + +/* 8. Improve line wrapping */ +p { + text-wrap: pretty; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + text-wrap: balance; +} + +/* + 9. Create a root stacking context + */ +#root, +#__next { + isolation: isolate; +} \ No newline at end of file diff --git a/frontend/src/routes/AuthenticatedRoute.tsx b/frontend/src/routes/AuthenticatedRoute.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/routes/ROUTES.md b/frontend/src/routes/ROUTES.md new file mode 100644 index 0000000..1dc1e4f --- /dev/null +++ b/frontend/src/routes/ROUTES.md @@ -0,0 +1,71 @@ +# Routes Folder + +This folder contains the route definitions and components used to manage routing in the React application. It includes public and private routes, as well as nested layouts. + +## File Structure +routes/ +├── PrivateRoute.jsx +├── AppRoutes.jsx +└── index.js + + +### `PrivateRoute.jsx` + +`PrivateRoute` is a wrapper component that restricts access to certain routes based on the user's authentication status. Only logged-in users can access routes wrapped inside `PrivateRoute`. + +#### Example Usage + +```jsx +import { Navigate, Outlet } from "react-router-dom"; +import { useAuth } from "../auth"; // custom hook to get auth status + +const PrivateRoute = () => { + const { isLoggedIn } = useAuth(); + + return isLoggedIn ? : ; +}; + +export default PrivateRoute; +``` + +` ` allows nested routes to be rendered inside the PrivateRoute. + +### AppRoutes.jsx + +This file contains all the route definitions example of the app. It can use layouts from the layouts folder to wrap sections of the app. + +Example Usage +```jsx +import { Routes, Route } from "react-router-dom"; +import PrivateRoute from "./PrivateRoute"; + +// Layouts +import MainLayout from "../layouts/MainLayout"; +import AuthLayout from "../layouts/AuthLayout"; + +// Pages +import Dashboard from "../pages/Dashboard"; +import Profile from "../pages/Profile"; +import Login from "../pages/Login"; + +const AppRoutes = () => { + return ( + + {/* Public Routes */} + }> + } /> + + + {/* Private Routes */} + }> + }> + } /> + } /> + + + + ); +}; + +export default AppRoutes; +``` \ No newline at end of file diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..227a6c6 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "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/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..f85a399 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "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/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/frontend/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()], +})