From dd9d076bd23d0beb8c5a4c2cdcce99f52131b91a Mon Sep 17 00:00:00 2001 From: Brunobrno Date: Wed, 29 Oct 2025 00:58:37 +0100 Subject: [PATCH] okay --- .github/copilot-instructions.md | 3 +- backend/account/migrations/0001_initial.py | 54 ++ .../migrations/__init__.py | 0 backend/account/models.py | 47 +- backend/account/serializers.py | 11 +- backend/commerce/migrations/0001_initial.py | 2 +- backend/requirements.txt | 2 +- .../downloader/migrations/0001_initial.py | 54 -- .../downloader/migrations/__init__.py | 0 backend/thirdparty/downloader/urls.py | 13 +- backend/thirdparty/downloader/views.py | 62 +- .../thirdparty/gopay/migrations/__init__.py | 0 .../stripe/migrations/0001_initial.py | 2 +- .../trading212/migrations/__init__.py | 0 backend/vontor_cz/asgi.py | 10 +- backend/vontor_cz/urls.py | 3 + frontend/package-lock.json | 649 ++++++++++++++++-- frontend/package.json | 4 +- frontend/public/portfolio/davo1.png | Bin 0 -> 30121 bytes frontend/public/portfolio/epinger.png | Bin 0 -> 27152 bytes frontend/public/portfolio/perlica.png | Bin 0 -> 22351 bytes frontend/src/api/apps/Downloader.ts | 121 +++- .../src/components/Footer/footer.module.css | 4 + frontend/src/components/ads/Drone/Drone.tsx | 28 +- .../ads/Portfolio/Portfolio.module.css | 8 +- .../components/ads/Portfolio/Portfolio.tsx | 30 +- .../src/components/navbar/HomeNav.module.css | 166 ++++- frontend/src/components/navbar/HomeNav.tsx | 23 +- frontend/src/index.css | 11 +- frontend/src/layouts/Default.tsx | 28 + frontend/src/layouts/HomeLayout.tsx | 6 +- frontend/src/pages/downloader/Downloader.tsx | 210 +++--- frontend/vite.config.ts | 6 +- 33 files changed, 1172 insertions(+), 385 deletions(-) create mode 100644 backend/account/migrations/0001_initial.py rename backend/{advertisement => account}/migrations/__init__.py (100%) delete mode 100644 backend/thirdparty/downloader/migrations/0001_initial.py delete mode 100644 backend/thirdparty/downloader/migrations/__init__.py delete mode 100644 backend/thirdparty/gopay/migrations/__init__.py delete mode 100644 backend/thirdparty/trading212/migrations/__init__.py create mode 100644 frontend/public/portfolio/davo1.png create mode 100644 frontend/public/portfolio/epinger.png create mode 100644 frontend/public/portfolio/perlica.png create mode 100644 frontend/src/layouts/Default.tsx diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 175e089..daaf368 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -11,7 +11,7 @@ This monorepo contains a Django backend and a Vite/React frontend, orchestrated - **frontend/**: Vite + React + TypeScript app. - Organized by `src/api/`, `components/`, `features/`, `layouts/`, `pages/`, `routes/`. - Uses React Router layouts and nested routes (see `src/layouts/`, `src/routes/`). -- **docker-compose.yml**: Orchestrates backend, frontend, Redis, and Postgres for local/dev. + - Uses Tailwind CSS for styling (configured via `src/index.css` with `@import "tailwindcss";`). Prefer utility classes over custom CSS. ## Developer Workflows - **Backend** @@ -39,6 +39,7 @@ This monorepo contains a Django backend and a Vite/React frontend, orchestrated - Route definitions and guards in `src/routes/` (`ROUTES.md`). - Use TypeScript strict mode (see `tsconfig.*.json`). - Linting: ESLint config in `eslint.config.js`. + - Styling: Tailwind CSS is present. Prefer utility classes; keep minimal component-scoped CSS. Global/base styles live in `src/index.css`. Avoid inline styles and CSS-in-JS unless necessary. ### Frontend API Client (required) All frontend API calls must use the shared client at frontend/src/api/Client.ts. diff --git a/backend/account/migrations/0001_initial.py b/backend/account/migrations/0001_initial.py new file mode 100644 index 0000000..41ba5ce --- /dev/null +++ b/backend/account/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# Generated by Django 5.2.7 on 2025-10-28 22:28 + +import account.models +import django.contrib.auth.validators +import django.core.validators +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('is_deleted', models.BooleanField(default=False)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('role', models.CharField(choices=[('admin', 'Admin'), ('mod', 'Moderator'), ('regular', 'Regular')], default='regular', max_length=20)), + ('phone_number', models.CharField(blank=True, max_length=16, null=True, unique=True, validators=[django.core.validators.RegexValidator('^\\+?\\d{9,15}$', message='Zadejte platné telefonní číslo.')])), + ('email_verified', models.BooleanField(default=False)), + ('email', models.EmailField(db_index=True, max_length=254, unique=True)), + ('gdpr', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=False)), + ('create_time', models.DateTimeField(auto_now_add=True)), + ('city', models.CharField(blank=True, max_length=100, null=True)), + ('street', models.CharField(blank=True, max_length=200, null=True)), + ('postal_code', models.CharField(blank=True, max_length=5, null=True, validators=[django.core.validators.RegexValidator(code='invalid_postal_code', message='Postal code must contain exactly 5 digits.', regex='^\\d{5}$')])), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to.', related_name='customuser_set', related_query_name='customuser', to='auth.group')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='customuser_set', related_query_name='customuser', to='auth.permission')), + ], + options={ + 'abstract': False, + }, + managers=[ + ('objects', account.models.CustomUserManager()), + ('active', account.models.ActiveUserManager()), + ], + ), + ] diff --git a/backend/advertisement/migrations/__init__.py b/backend/account/migrations/__init__.py similarity index 100% rename from backend/advertisement/migrations/__init__.py rename to backend/account/migrations/__init__.py diff --git a/backend/account/models.py b/backend/account/models.py index 54e6928..a01eebe 100644 --- a/backend/account/models.py +++ b/backend/account/models.py @@ -1,6 +1,6 @@ import uuid from django.db import models -from django.contrib.auth.models import AbstractUser, Group, Permission +from django.contrib.auth.models import AbstractUser, UserManager, Group, Permission from django.core.validators import RegexValidator, MinLengthValidator, MaxValueValidator, MinValueValidator from django.conf import settings @@ -16,7 +16,13 @@ import logging logger = logging.getLogger(__name__) +class CustomUserManager(UserManager): + # Inherit get_by_natural_key and all auth behaviors + use_in_migrations = True +class ActiveUserManager(CustomUserManager): + def get_queryset(self): + return super().get_queryset().filter(is_active=True) class CustomUser(SoftDeleteModel, AbstractUser): groups = models.ManyToManyField( @@ -83,9 +89,10 @@ class CustomUser(SoftDeleteModel, AbstractUser): "email" ] - - def __str__(self): - return f"{self.email} at {self.create_time.strftime('%d-%m-%Y %H:%M:%S')}" + # Ensure default manager has get_by_natural_key + objects = CustomUserManager() + # Optional convenience manager for active users only + active = ActiveUserManager() def delete(self, *args, **kwargs): self.is_active = False @@ -93,25 +100,29 @@ class CustomUser(SoftDeleteModel, AbstractUser): return super().delete(*args, **kwargs) def save(self, *args, **kwargs): - if self.pk is None: # if newely created user - - from django.contrib.auth.models import Group - group, _ = Group.objects.get_or_create(name=self.role) - self.groups.set([group]) + is_new = self._state.adding # True if object hasn't been saved yet + # Pre-save flags for new users + if is_new: if self.is_superuser or self.role == "admin": + # ensure admin flags are consistent self.is_active = True - - if self.role == 'admin': - self.is_staff = True - self.is_superuser = True - - if self.is_superuser: - self.role = 'admin' - + self.is_staff = True + self.is_superuser = True + self.role = "admin" else: self.is_staff = False - + + # First save to obtain a primary key + super().save(*args, **kwargs) + + # Assign group after we have a PK + if is_new: + from django.contrib.auth.models import Group + group, _ = Group.objects.get_or_create(name=self.role) + # Use add/set now that PK exists + self.groups.set([group]) + return super().save(*args, **kwargs) diff --git a/backend/account/serializers.py b/backend/account/serializers.py index 1319eff..7a1ceb5 100644 --- a/backend/account/serializers.py +++ b/backend/account/serializers.py @@ -27,21 +27,16 @@ class CustomUserSerializer(serializers.ModelSerializer): "last_name", "email", "role", - "account_type", "email_verified", "phone_number", "create_time", - "var_symbol", - "bank_account", - "ICO", - "RC", "city", "street", - "PSC", - "GDPR", + "postal_code", + "gdpr", "is_active", ] - read_only_fields = ["id", "create_time", "GDPR", "username"] # <-- removed "account_type" + read_only_fields = ["id", "create_time", "gdpr", "username"] # <-- removed "account_type" def update(self, instance, validated_data): user = self.context["request"].user diff --git a/backend/commerce/migrations/0001_initial.py b/backend/commerce/migrations/0001_initial.py index 28cc9c2..97b32df 100644 --- a/backend/commerce/migrations/0001_initial.py +++ b/backend/commerce/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.7 on 2025-10-28 01:24 +# Generated by Django 5.2.7 on 2025-10-28 22:28 import django.db.models.deletion from django.db import migrations, models diff --git a/backend/requirements.txt b/backend/requirements.txt index be16d6b..97ed758 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -78,7 +78,7 @@ django-celery-beat #slouží k plánování úkolů pro Celery #opencv-python #moviepy use this better instead of pillow #moviepy -#yt-dlp +yt-dlp weasyprint #tvoření PDFek z html dokumentu + css styly diff --git a/backend/thirdparty/downloader/migrations/0001_initial.py b/backend/thirdparty/downloader/migrations/0001_initial.py deleted file mode 100644 index 16f6b26..0000000 --- a/backend/thirdparty/downloader/migrations/0001_initial.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.7 on 2025-10-28 00:14 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='DownloaderModel', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('url', models.URLField()), - ('download_time', models.DateTimeField(auto_now_add=True)), - ('status', models.CharField(max_length=50)), - ('requested_format', models.CharField(blank=True, db_index=True, max_length=100, null=True)), - ('format_id', models.CharField(blank=True, db_index=True, max_length=50, null=True)), - ('ext', models.CharField(blank=True, db_index=True, max_length=20, null=True)), - ('vcodec', models.CharField(blank=True, db_index=True, max_length=50, null=True)), - ('acodec', models.CharField(blank=True, db_index=True, max_length=50, null=True)), - ('width', models.IntegerField(blank=True, null=True)), - ('height', models.IntegerField(blank=True, null=True)), - ('fps', models.FloatField(blank=True, null=True)), - ('abr', models.FloatField(blank=True, null=True)), - ('vbr', models.FloatField(blank=True, null=True)), - ('tbr', models.FloatField(blank=True, null=True)), - ('asr', models.IntegerField(blank=True, null=True)), - ('filesize', models.BigIntegerField(blank=True, null=True)), - ('duration', models.FloatField(blank=True, null=True)), - ('title', models.CharField(blank=True, max_length=512, null=True)), - ('extractor', models.CharField(blank=True, db_index=True, max_length=100, null=True)), - ('extractor_key', models.CharField(blank=True, max_length=100, null=True)), - ('video_id', models.CharField(blank=True, db_index=True, max_length=128, null=True)), - ('webpage_url', models.URLField(blank=True, null=True)), - ('is_audio_only', models.BooleanField(db_index=True, default=False)), - ('ip_address', models.GenericIPAddressField(blank=True, null=True)), - ('user_agent', models.TextField(blank=True, null=True)), - ('error_message', models.TextField(blank=True, null=True)), - ('raw_info', models.JSONField(blank=True, null=True)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'indexes': [models.Index(fields=['download_time'], name='downloader__downloa_ef522e_idx'), models.Index(fields=['ext', 'is_audio_only'], name='downloader__ext_2aa7af_idx'), models.Index(fields=['requested_format'], name='downloader__request_f4048b_idx'), models.Index(fields=['extractor'], name='downloader__extract_b39777_idx')], - }, - ), - ] diff --git a/backend/thirdparty/downloader/migrations/__init__.py b/backend/thirdparty/downloader/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/thirdparty/downloader/urls.py b/backend/thirdparty/downloader/urls.py index 542e675..d42e04a 100644 --- a/backend/thirdparty/downloader/urls.py +++ b/backend/thirdparty/downloader/urls.py @@ -1,14 +1,13 @@ from django.urls import path -from .views import DownloaderLogView, DownloaderStatsView -from .views import DownloaderFormatsView, DownloaderFileView +from .views import DownloaderFormatsView, DownloaderFileView, DownloaderStatsView urlpatterns = [ # Probe formats for a URL (size-checked) - path("api/downloader/formats/", DownloaderFormatsView.as_view(), name="downloader-formats"), + path("formats/", DownloaderFormatsView.as_view(), name="downloader-formats"), + # Download selected format (enforces size limit) - path("api/downloader/download/", DownloaderFileView.as_view(), name="downloader-download"), + path("download/", DownloaderFileView.as_view(), name="downloader-download"), + # Aggregated statistics - path("api/downloader/stats/", DownloaderStatsView.as_view(), name="downloader-stats"), - # Legacy helper - path("api/downloader/logs/", DownloaderLogView.as_view(), name="downloader-log"), + path("stats/", DownloaderStatsView.as_view(), name="downloader-stats"), ] diff --git a/backend/thirdparty/downloader/views.py b/backend/thirdparty/downloader/views.py index 719d854..907efa7 100644 --- a/backend/thirdparty/downloader/views.py +++ b/backend/thirdparty/downloader/views.py @@ -9,6 +9,7 @@ from django.http import StreamingHttpResponse, JsonResponse from django.utils.text import slugify from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator +from django.db.utils import OperationalError, ProgrammingError # docs + schema helpers from rest_framework import serializers @@ -26,6 +27,7 @@ import math import json import tempfile from typing import Any, Dict, List, Optional, Tuple +from urllib.parse import quote as urlquote from .models import DownloaderModel from .serializers import DownloaderLogSerializer @@ -141,9 +143,30 @@ def _client_meta(request) -> Tuple[Optional[Any], Optional[str], Optional[str]]: user = getattr(request, "user", None) return user, ip, ua +# Safe logger: swallow DB errors if table is missing/not migrated yet +def _log_safely(*, info, requested_format, status: str, url: str, user, ip_address: str, user_agent: str, error_message: str | None = None): + try: + DownloaderModel.from_ydl_info( + info=info, + requested_format=requested_format, + status=status, + url=url, + user=user, + ip_address=ip_address, + user_agent=user_agent, + error_message=error_message, + ) + except (OperationalError, ProgrammingError): + # migrations not applied or table missing – ignore + pass + except Exception: + # never break the request on logging failures + pass + class DownloaderFormatsView(APIView): """Probe media URL and return available formats with estimated sizes and limit flags.""" permission_classes = [AllowAny] + authentication_classes = [] @extend_schema( tags=["downloader"], @@ -224,7 +247,7 @@ class DownloaderFormatsView(APIView): except Exception as e: # log probe error user, ip, ua = _client_meta(request) - DownloaderModel.from_ydl_info( + _log_safely( info={"webpage_url": url}, requested_format=None, status="probe_error", @@ -258,7 +281,7 @@ class DownloaderFormatsView(APIView): # Log probe user, ip, ua = _client_meta(request) - DownloaderModel.from_ydl_info( + _log_safely( info=info, requested_format=None, status="probe_ok", @@ -280,6 +303,7 @@ class DownloaderFormatsView(APIView): class DownloaderFileView(APIView): """Download selected format if under max size, then stream the file back.""" permission_classes = [AllowAny] + authentication_classes = [] @extend_schema( tags=["downloader"], @@ -288,7 +312,7 @@ class DownloaderFileView(APIView): description="Downloads with a strict max filesize guard and streams as application/octet-stream.", request=DownloadRequestSchema, responses={ - 200: OpenApiResponse(response=OpenApiTypes.BINARY, media_type="application/octet-stream"), + 200: OpenApiTypes.BINARY, # was OpenApiResponse(..., media_type="application/octet-stream") 400: OpenApiResponse(response=ErrorResponseSchema), 413: OpenApiResponse(response=ErrorResponseSchema), 500: OpenApiResponse(response=ErrorResponseSchema), @@ -334,7 +358,7 @@ class DownloaderFileView(APIView): info = ydl.extract_info(url, download=False) except Exception as e: user, ip, ua = _client_meta(request) - DownloaderModel.from_ydl_info( + _log_safely( info={"webpage_url": url}, requested_format=fmt_id, status="precheck_error", @@ -358,7 +382,7 @@ class DownloaderFileView(APIView): est_size = _estimate_size_bytes(selected, duration) if est_size is not None and est_size > max_bytes: user, ip, ua = _client_meta(request) - DownloaderModel.from_ydl_info( + _log_safely( info=selected, requested_format=fmt_id, status="blocked_by_size", @@ -400,7 +424,7 @@ class DownloaderFileView(APIView): filepath = result.get("requested_downloads", [{}])[0].get("filepath") or result.get("_filename") except Exception as e: user, ip, ua = _client_meta(request) - DownloaderModel.from_ydl_info( + _log_safely( info=selected, requested_format=fmt_id, status="download_error", @@ -425,7 +449,7 @@ class DownloaderFileView(APIView): try: selected_info = dict(selected) selected_info["filesize"] = os.path.getsize(filepath) - DownloaderModel.from_ydl_info( + _log_safely( info=selected_info, requested_format=fmt_id, status="success", @@ -451,7 +475,13 @@ class DownloaderFileView(APIView): pass resp = StreamingHttpResponse(file_generator(filepath), content_type="application/octet-stream") - resp["Content-Disposition"] = f'attachment; filename="{safe_name}"' + # Include both plain and RFC 5987 encoded filename + resp["Content-Disposition"] = ( + f'attachment; filename="{safe_name}"; filename*=UTF-8\'\'{urlquote(safe_name)}' + ) + # Expose headers so the browser can read them via XHR/fetch + resp["X-Filename"] = safe_name + resp["Access-Control-Expose-Headers"] = "Content-Disposition, X-Filename, Content-Length, Content-Type" try: resp["Content-Length"] = str(os.path.getsize(filepath)) except Exception: @@ -521,19 +551,3 @@ class DownloaderStatsView(APIView): "top_acodec": top_acodec, "audio_vs_video": audio_vs_video, }) - - -# Minimal placeholder so existing URL doesn't break; prefer using automatic logs above. -class DownloaderLogView(APIView): - permission_classes = [AllowAny] - - @extend_schema( - tags=["downloader"], - operation_id="downloader_log_helper", - summary="Deprecated helper", - description="Use /api/downloader/formats/ then /api/downloader/download/.", - responses={200: inline_serializer(name="LogHelper", fields={"detail": serializers.CharField()})}, - ) - def post(self, request): - """POST to the deprecated log helper endpoint.""" - return Response({"detail": "Use /api/downloader/formats/ then /api/downloader/download/."}, status=200) diff --git a/backend/thirdparty/gopay/migrations/__init__.py b/backend/thirdparty/gopay/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/thirdparty/stripe/migrations/0001_initial.py b/backend/thirdparty/stripe/migrations/0001_initial.py index b8d70c0..9377f3e 100644 --- a/backend/thirdparty/stripe/migrations/0001_initial.py +++ b/backend/thirdparty/stripe/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.7 on 2025-10-28 00:13 +# Generated by Django 5.2.7 on 2025-10-28 22:28 from django.db import migrations, models diff --git a/backend/thirdparty/trading212/migrations/__init__.py b/backend/thirdparty/trading212/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/vontor_cz/asgi.py b/backend/vontor_cz/asgi.py index 44ef2fb..626be7f 100644 --- a/backend/vontor_cz/asgi.py +++ b/backend/vontor_cz/asgi.py @@ -17,9 +17,9 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trznice.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), - "websocket": AuthMiddlewareStack( - URLRouter( - #myapp.routing.websocket_urlpatterns - ) - ), + # "websocket": AuthMiddlewareStack( + # URLRouter( + # #myapp.routing.websocket_urlpatterns + # ) + # ), }) diff --git a/backend/vontor_cz/urls.py b/backend/vontor_cz/urls.py index 4130a41..04bbb31 100644 --- a/backend/vontor_cz/urls.py +++ b/backend/vontor_cz/urls.py @@ -32,8 +32,11 @@ urlpatterns = [ path('admin/', admin.site.urls), path('api/account/', include('account.urls')), + #path('api/commerce/', include('commerce.urls')), + #path('api/advertisments/', include('advertisements.urls')), path('api/stripe/', include('thirdparty.stripe.urls')), path('api/trading212/', include('thirdparty.trading212.urls')), + path('api/downloader/', include('thirdparty.downloader.urls')), ] diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8e9b1a1..faebd73 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,12 +8,14 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "@tailwindcss/vite": "^4.1.16", "@types/react-router": "^5.1.20", "axios": "^1.13.0", "react": "^19.1.1", "react-dom": "^19.1.1", "react-icons": "^5.5.0", - "react-router-dom": "^7.8.1" + "react-router-dom": "^7.8.1", + "tailwindcss": "^4.1.16" }, "devDependencies": { "@eslint/js": "^9.33.0", @@ -333,7 +335,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -350,7 +351,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -367,7 +367,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -384,7 +383,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -401,7 +399,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -418,7 +415,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -435,7 +431,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -452,7 +447,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -469,7 +463,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -486,7 +479,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -503,7 +495,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -520,7 +511,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -537,7 +527,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -554,7 +543,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -571,7 +559,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -588,7 +575,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -605,7 +591,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -622,7 +607,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -639,7 +623,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -656,7 +639,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -673,7 +655,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -690,7 +671,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -707,7 +687,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -724,7 +703,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -741,7 +719,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -758,7 +735,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -992,18 +968,26 @@ "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/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1013,14 +997,12 @@ "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", @@ -1079,7 +1061,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1093,7 +1074,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1107,7 +1087,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1121,7 +1100,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1135,7 +1113,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1149,7 +1126,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1163,7 +1139,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1177,7 +1152,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1191,7 +1165,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1205,7 +1178,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1219,7 +1191,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1233,7 +1204,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1247,7 +1217,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1261,7 +1230,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1275,7 +1243,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1289,7 +1256,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1303,7 +1269,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1317,7 +1282,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1331,7 +1295,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1345,13 +1308,269 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, + "node_modules/@tailwindcss/node": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", + "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", + "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-x64": "4.1.16", + "@tailwindcss/oxide-freebsd-x64": "4.1.16", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-x64-musl": "4.1.16", + "@tailwindcss/oxide-wasm32-wasi": "4.1.16", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", + "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", + "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", + "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", + "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", + "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", + "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", + "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", + "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", + "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", + "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.7", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", + "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", + "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz", + "integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.16", + "@tailwindcss/oxide": "4.1.16", + "tailwindcss": "4.1.16" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, "node_modules/@types/axios": { "version": "0.9.36", "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.9.36.tgz", @@ -1408,7 +1627,6 @@ "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": { @@ -2060,6 +2278,15 @@ "node": ">=0.4.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2081,6 +2308,19 @@ "dev": true, "license": "ISC" }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -2130,7 +2370,6 @@ "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": { @@ -2534,7 +2773,6 @@ "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, @@ -2639,6 +2877,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -2772,6 +3016,15 @@ "dev": true, "license": "ISC" }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2863,6 +3116,255 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2896,6 +3398,15 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2974,7 +3485,6 @@ "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", @@ -3090,7 +3600,6 @@ "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": { @@ -3110,7 +3619,6 @@ "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", @@ -3285,7 +3793,6 @@ "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" @@ -3394,7 +3901,6 @@ "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" @@ -3426,11 +3932,29 @@ "node": ">=8" } }, + "node_modules/tailwindcss": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", + "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -3447,7 +3971,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -3465,7 +3988,6 @@ "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" @@ -3596,7 +4118,6 @@ "version": "7.1.12", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", @@ -3671,7 +4192,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -3689,7 +4209,6 @@ "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" diff --git a/frontend/package.json b/frontend/package.json index f9c435c..e328aec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,12 +10,14 @@ "preview": "vite preview" }, "dependencies": { + "@tailwindcss/vite": "^4.1.16", "@types/react-router": "^5.1.20", "axios": "^1.13.0", "react": "^19.1.1", "react-dom": "^19.1.1", "react-icons": "^5.5.0", - "react-router-dom": "^7.8.1" + "react-router-dom": "^7.8.1", + "tailwindcss": "^4.1.16" }, "devDependencies": { "@eslint/js": "^9.33.0", diff --git a/frontend/public/portfolio/davo1.png b/frontend/public/portfolio/davo1.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2f6541158c3035bd98feeff309404b9b245cdf GIT binary patch literal 30121 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 literal 0 HcmV?d00001 diff --git a/frontend/public/portfolio/perlica.png b/frontend/public/portfolio/perlica.png new file mode 100644 index 0000000000000000000000000000000000000000..fdfee8a12dfb01cb9780accb7be2d899545537f4 GIT binary patch literal 22351 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 F{{aiieqsOs literal 0 HcmV?d00001 diff --git a/frontend/src/api/apps/Downloader.ts b/frontend/src/api/apps/Downloader.ts index ab72e11..d1e3f55 100644 --- a/frontend/src/api/apps/Downloader.ts +++ b/frontend/src/api/apps/Downloader.ts @@ -1,57 +1,104 @@ import Client from "../Client"; -export type Choices = { - file_types: string[]; - qualities: string[]; +export type FormatOption = { + format_id: string; + ext: string | null; + vcodec: string | null; + acodec: string | null; + fps: number | null; + tbr: number | null; + abr: number | null; + vbr: number | null; + asr: number | null; + filesize: number | null; + filesize_approx: number | null; + estimated_size_bytes: number | null; + size_ok: boolean; + format_note: string | null; + resolution: string | null; // e.g. "1920x1080" + audio_only: boolean; }; -export type DownloadPayload = { - url: string; - file_type?: string; - quality?: string; +export type FormatsResponse = { + title: string | null; + duration: number | null; + extractor: string | null; + video_id: string | null; + max_size_bytes: number; + options: FormatOption[]; }; +// Probe available formats for a URL (no auth required) +export async function probeFormats(url: string): Promise { + const res = await Client.public.post("/api/downloader/formats/", { url }); + return res.data as FormatsResponse; +} + +// Download selected format as a Blob and resolve filename from headers +export async function downloadFormat(url: string, format_id: string): Promise<{ blob: Blob; filename: string }> { + const res = await Client.public.post( + "/api/downloader/download/", + { url, format_id }, + { responseType: "blob" } + ); + + // Try to parse Content-Disposition filename first, then X-Filename (exposed by backend) + const cd = res.headers?.["content-disposition"] as string | undefined; + const xfn = res.headers?.["x-filename"] as string | undefined; + const filename = + parseContentDispositionFilename(cd) || + (xfn && xfn.trim()) || + inferFilenameFromUrl(url, (res.headers?.["content-type"] as string | undefined)) || + "download.bin"; + + return { blob: res.data as Blob, filename }; +} + +// Deprecated types kept for compatibility if referenced elsewhere +export type Choices = { file_types: string[]; qualities: string[] }; export type DownloadJobResponse = { id: string; status: "pending" | "running" | "finished" | "failed"; detail?: string; download_url?: string; - progress?: number; // 0-100 + progress?: number; }; -// Fallback when choices endpoint is unavailable or models are hardcoded -const FALLBACK_CHOICES: Choices = { - file_types: ["auto", "video", "audio"], - qualities: ["best", "good", "worst"], -}; +// Helpers +function parseContentDispositionFilename(cd?: string): string | null { + if (!cd) return null; + // filename*=UTF-8''encoded or filename="plain" + const utf8Match = cd.match(/filename\*\s*=\s*UTF-8''([^;]+)/i); + if (utf8Match?.[1]) return decodeURIComponent(utf8Match[1]); + const plainMatch = cd.match(/filename\s*=\s*"([^"]+)"/i) || cd.match(/filename\s*=\s*([^;]+)/i); + return plainMatch?.[1]?.trim() || null; +} -/** - * Fetch dropdown choices from backend (adjust path to match your Django views). - * Expected response shape: - * { file_types: string[], qualities: string[] } - */ -export async function getChoices(): Promise { +function inferFilenameFromUrl(url: string, contentType?: string): string { try { - const res = await Client.auth.get("/api/downloader/choices/"); - return res.data as Choices; + const u = new URL(url); + const last = u.pathname.split("/").filter(Boolean).pop(); + if (last) return last; } catch { - return FALLBACK_CHOICES; + // ignore } + if (contentType) { + const ext = contentTypeToExt(contentType); + return `download${ext ? `.${ext}` : ""}`; + } + return "download.bin"; } -/** - * Submit a new download job (adjust path/body to your viewset). - * Example payload: { url, file_type, quality } - */ -export async function submitDownload(payload: DownloadPayload): Promise { - const res = await Client.auth.post("/api/downloader/jobs/", payload); - return res.data as DownloadJobResponse; -} - -/** - * Get job status by ID. Returns progress, status, and download_url when finished. - */ -export async function getJobStatus(id: string): Promise { - const res = await Client.auth.get(`/api/downloader/jobs/${id}/`); - return res.data as DownloadJobResponse; +function contentTypeToExt(ct: string): string | null { + const map: Record = { + "video/mp4": "mp4", + "audio/mpeg": "mp3", + "audio/mp4": "m4a", + "audio/aac": "aac", + "audio/ogg": "ogg", + "video/webm": "webm", + "audio/webm": "webm", + "application/octet-stream": "bin", + }; + return map[ct] || null; } diff --git a/frontend/src/components/Footer/footer.module.css b/frontend/src/components/Footer/footer.module.css index 0be6ec2..54d7228 100644 --- a/frontend/src/components/Footer/footer.module.css +++ b/frontend/src/components/Footer/footer.module.css @@ -6,6 +6,10 @@ footer a i{ color: white; text-decoration: none; } +footer a:hover i{ + color: var(--c-text); + text-decoration: none; +} footer{ font-family: "Roboto Mono", monospace; diff --git a/frontend/src/components/ads/Drone/Drone.tsx b/frontend/src/components/ads/Drone/Drone.tsx index eb99062..02846a8 100644 --- a/frontend/src/components/ads/Drone/Drone.tsx +++ b/frontend/src/components/ads/Drone/Drone.tsx @@ -61,46 +61,28 @@ export default function Drone() {
-

Letecké snímky dronem

+

Letecké záběry, co zaujmou

Oprávně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šť! -

+

Oprávnění A1/A2/A3 + radiostanice. Bezpečný provoz i v omezených zónách, povolení zajistím.

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í.* -

+

Paušál 3 000 Kč. Ostrava zdarma; mimo 10 Kč/km. Cena se může lišit dle 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. -

+

Krátký sestřih nebo surové záběry — podle potřeby.

diff --git a/frontend/src/components/ads/Portfolio/Portfolio.module.css b/frontend/src/components/ads/Portfolio/Portfolio.module.css index fdde5e2..ee6d871 100644 --- a/frontend/src/components/ads/Portfolio/Portfolio.module.css +++ b/frontend/src/components/ads/Portfolio/Portfolio.module.css @@ -27,8 +27,11 @@ transform-origin: bottom; transition: transform 0.5s ease-in-out; + transform: skew(-5deg); z-index: 3; + box-shadow: #000000 5px 5px 15px; + } .portfolio div span svg{ font-size: 5em; @@ -56,7 +59,7 @@ } .portfolio .door-open{ - transform: rotateX(180deg); + transform: rotateX(90deg) skew(-2deg) !important; } .portfolio>header { @@ -131,6 +134,8 @@ border-radius: 1em; border-top-left-radius: 0; + + aspect-ratio: 16 / 9; } .portfolio div article { @@ -145,7 +150,6 @@ } .portfolio div article header a img { - padding: 2em 0; width: 80%; margin: auto; } diff --git a/frontend/src/components/ads/Portfolio/Portfolio.tsx b/frontend/src/components/ads/Portfolio/Portfolio.tsx index be2589a..d9eb3b9 100644 --- a/frontend/src/components/ads/Portfolio/Portfolio.tsx +++ b/frontend/src/components/ads/Portfolio/Portfolio.tsx @@ -6,23 +6,34 @@ interface PortfolioItem { href: string src: string alt: string + // Optional per-item styling (prefer Tailwind utility classes in className/imgClassName) + className?: string + imgClassName?: string + style?: React.CSSProperties + imgStyle?: React.CSSProperties } const portfolioItems: PortfolioItem[] = [ { href: "https://davo1.cz", - src: "/home/img/portfolio/DAVO_logo_2024_bile.png", + src: "/portfolio/davo1.png", alt: "davo1.cz logo", + imgClassName: "bg-black rounded-lg p-4", + //className: "bg-white/5 rounded-lg p-4", }, { href: "https://perlica.cz", - src: "/home/img/portfolio/perlica-3.webp", + src: "/portfolio/perlica.png", alt: "Perlica logo", + imgClassName: "rounded-lg", + // imgClassName: "max-h-12", }, { href: "http://epinger2.cz", - src: "/home/img/portfolio/logo_epinger.svg", + src: "/portfolio/epinger.png", alt: "Epinger2 logo", + imgClassName: "bg-white rounded-lg", + // imgClassName: "max-h-12", }, ] @@ -51,10 +62,19 @@ export default function Portfolio() { {portfolioItems.map((item, index) => ( -
+
- {item.alt} + {item.alt}
diff --git a/frontend/src/components/navbar/HomeNav.module.css b/frontend/src/components/navbar/HomeNav.module.css index a65eb83..7ddbfa4 100644 --- a/frontend/src/components/navbar/HomeNav.module.css +++ b/frontend/src/components/navbar/HomeNav.module.css @@ -36,6 +36,10 @@ nav.isSticky-nav{ nav ul #nav-logo{ border-right: 0.2em solid var(--c-lines); } +/* Add class alias for logo used in TSX */ +.logo { + border-right: 0.2em solid var(--c-lines); +} nav ul #nav-logo span{ line-height: 0.75; font-size: 1.5em; @@ -47,10 +51,21 @@ nav a{ position: relative; text-decoration: none; } - nav a:hover{ color: #fff; } +/* Unify link/summary layout to prevent distortion */ +nav a, +nav summary { + color: #fff; + transition: color 1s; + position: relative; + text-decoration: none; + cursor: pointer; + display: inline-block; /* ensure consistent inline sizing */ + vertical-align: middle; /* align with neighbors */ + padding: 0; /* keep padding controlled by li */ +} nav a::before { content: ""; @@ -67,7 +82,125 @@ nav a::before { nav a:hover::before { transform: scaleX(1); } +nav summary:hover { + color: #fff; +} +/* underline effect shared for links and summary */ +nav a::before, +nav summary::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, +nav summary:hover::before { + transform: scaleX(1); +} + +/* Submenu support */ +.hasSubmenu { + position: relative; + vertical-align: middle; /* align with other inline items */ +} + +/* Keep details inline to avoid breaking the first row flow */ +.hasSubmenu details { + display: inline-block; + margin: 0; + padding: 0; +} + +/* Ensure "Services" and caret stay on the same line */ +.hasSubmenu details > summary { + display: inline-flex; /* horizontal layout */ + align-items: center; /* vertical alignment */ + gap: 0.5em; /* space between text and icon */ + white-space: nowrap; /* prevent wrapping */ +} + +/* Hide native disclosure icon/marker on summary */ +.hasSubmenu details > summary { + list-style: none; + outline: none; +} +.hasSubmenu details > summary::-webkit-details-marker { + display: none; +} +.hasSubmenu details > summary::marker { + content: ""; +} + +/* Reusable caret for submenu triggers */ +.caret { + transition: transform 0.2s ease-in-out; +} + +/* Rotate caret when submenu is open */ +.hasSubmenu details[open] .caret { + transform: rotate(180deg); +} + +/* Submenu box: place directly under nav with a tiny gap (no overlap) */ +.submenu { + list-style: none; + margin: 1em 0; + padding: 0.5em 0; + position: absolute; + left: 0; + top: calc(100% + 0.25em); + display: none; + background: var(--c-background-light); + border: 1px solid var(--c-lines); + border-radius: 0.75em; + min-width: max-content; + text-align: left; + z-index: 10; +} +.submenu li { + display: block; + padding: 0; +} +.submenu a { + display: inline-block; + padding: 0; /* remove padding so underline equals text width */ + margin: 0.35em 0; /* spacing without affecting underline width */ +} + +/* Show submenu when open */ +.hasSubmenu details[open] .submenu { + display: flex; + flex-direction: column; +} + +/* Hamburger toggle class (used by TSX) */ +.toggle { + display: none; + transition: transform 0.5s ease; +} +.toggleRotated { + transform: rotate(180deg); +} + +/* Bridge TSX classnames to existing rules */ +.navList { + list-style: none; + padding: 0; +} +.navList li { + display: inline; + padding: 0 3em; +} +.navList li a { + text-decoration: none; +} nav ul { list-style: none; @@ -129,6 +262,11 @@ nav ul li a { max-height: 2em; } + /* When TSX adds styles.open to the UL, expand it */ + .open { + max-height: 20em; + } + nav ul:last-child{ padding-bottom: 1em; } @@ -139,4 +277,28 @@ nav ul li a { border-bottom: 0.2em solid var(--c-lines); border-right: none; } - } \ No newline at end of file + /* Show hamburger on mobile */ + .toggle { + margin-top: 0.25em; + margin-left: 0.75em; + position: absolute; + left: 0; + display: block; + font-size: 2em; + } + + /* Submenu stacks inline under the parent item on mobile */ + .submenu { + position: static; + border: none; + border-radius: 0; + background: transparent; + padding: 0 0 0.5em 0.5em; + min-width: unset; + } + .submenu a { + display: inline-block; + padding: 0; /* keep no padding on mobile too */ + margin: 0.25em 0.5em; /* spacing via margin */ + } +} \ No newline at end of file diff --git a/frontend/src/components/navbar/HomeNav.tsx b/frontend/src/components/navbar/HomeNav.tsx index 3d9965c..1d45f04 100644 --- a/frontend/src/components/navbar/HomeNav.tsx +++ b/frontend/src/components/navbar/HomeNav.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react" import styles from "./HomeNav.module.css" -import { FaBars } from "react-icons/fa"; +import { FaBars, FaChevronDown } from "react-icons/fa"; export default function HomeNav() { const [navOpen, setNavOpen] = useState(false) @@ -9,7 +9,12 @@ export default function HomeNav() { return (