From 99a868a6bef83e06c54c77a23abf11bff5b2b797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gremaud?= Date: Thu, 17 Sep 2026 00:37:28 +0200 Subject: [PATCH] feat: switch to spa --- polylan_submitter/.gitignore | 2 +- polylan_submitter/market/views.py | 2 +- polylan_submitter/polylan_submitter/api.py | 13 +++- polylan_submitter/polylan_submitter/urls.py | 31 ++------ polylan_submitter/public/favicon.ico | Bin 0 -> 14388 bytes polylan_submitter/public/vite.svg | 1 - polylan_submitter/src/Home.vue | 43 ++++++------ polylan_submitter/src/OpusMagnum.vue | 7 +- polylan_submitter/src/Submissions.vue | 62 +++++++++++----- polylan_submitter/src/SubmissionsSelect.vue | 65 ++++++++++++----- polylan_submitter/src/api/index.ts | 4 +- polylan_submitter/src/api/sdk.gen.ts | 18 ++++- polylan_submitter/src/api/types.gen.ts | 66 ++++++++++++++++++ polylan_submitter/src/bootstrap.ts | 11 --- polylan_submitter/src/layout/AppHeader.vue | 23 +++--- polylan_submitter/src/router/index.ts | 54 ++++++++------ polylan_submitter/src/stores/pageHeader.ts | 20 ++++++ .../static_source/vite/favicon.ico | Bin 0 -> 14388 bytes polylan_submitter/submissions/api.py | 32 +++++++++ polylan_submitter/submissions/views.py | 29 +------- polylan_submitter/templates/app.html | 1 - polylan_submitter/templates/base.html | 3 +- 22 files changed, 317 insertions(+), 170 deletions(-) create mode 100644 polylan_submitter/public/favicon.ico delete mode 100644 polylan_submitter/public/vite.svg delete mode 100644 polylan_submitter/src/bootstrap.ts create mode 100644 polylan_submitter/src/stores/pageHeader.ts create mode 100644 polylan_submitter/static_source/vite/favicon.ico diff --git a/polylan_submitter/.gitignore b/polylan_submitter/.gitignore index 0178178..5269a2a 100644 --- a/polylan_submitter/.gitignore +++ b/polylan_submitter/.gitignore @@ -15,7 +15,7 @@ dist-ssr # Vite build output (generated locally via `pnpm build`, served by whitenoise) static_source/vite/assets static_source/vite/manifest.json -static_source/vite/vite.svg +static_source/vite/icon.png tsconfig.tsbuildinfo # vue-tsc emits a compiled copy of vite.config.ts here (tsconfig.node.json, diff --git a/polylan_submitter/market/views.py b/polylan_submitter/market/views.py index 5744326..9c9b58e 100644 --- a/polylan_submitter/market/views.py +++ b/polylan_submitter/market/views.py @@ -8,4 +8,4 @@ from events.models import Event @login_required def market_home(request: HttpRequest, event_path: str): get_object_or_404(Event, path=event_path) - return render(request, "app.html", {"bootstrap": {}}) + return render(request, "app.html") diff --git a/polylan_submitter/polylan_submitter/api.py b/polylan_submitter/polylan_submitter/api.py index dfc13de..9ff1725 100644 --- a/polylan_submitter/polylan_submitter/api.py +++ b/polylan_submitter/polylan_submitter/api.py @@ -1,4 +1,4 @@ -from ninja import NinjaAPI +from ninja import NinjaAPI, Schema from django.conf import settings from django.core.cache import cache from django.http import HttpRequest @@ -62,6 +62,17 @@ def health_check(request): return {"status": "healthy", "service": "polylan-submitter-api"} +class ConfigOut(Schema): + market_enabled: bool + + +# Site-wide config the SPA needs but that isn't tied to any one event +# (e.g. whether to render the market card at all on the home page). +@api.get("/config", response=ConfigOut) +def get_config(request): + return {"market_enabled": settings.MARKET_ENABLED} + + # Cache management endpoint @api.post("/cache/clear") def clear_cache(request: HttpRequest, event_path: str | None = None): diff --git a/polylan_submitter/polylan_submitter/urls.py b/polylan_submitter/polylan_submitter/urls.py index 3ee8be4..b6c56c9 100644 --- a/polylan_submitter/polylan_submitter/urls.py +++ b/polylan_submitter/polylan_submitter/urls.py @@ -44,44 +44,21 @@ def home(request: HttpRequest): @login_required def event_home(request: HttpRequest, event_path: str): get_object_or_404(Event, path=event_path) - - return render( - request, - "app.html", - { - "bootstrap": { - "marketEnabled": settings.MARKET_ENABLED, - }, - }, - ) + return render(request, "app.html") @login_required @require_game_enabled(OPUS_MAGNUM_APP_ID) def opus_magnum_home(request: HttpRequest, event_path: str): - from opus_magnum.models import SteamCollection - - event = get_object_or_404(Event, path=event_path) - collection = SteamCollection.objects.filter(is_active=True, event=event).last() - - return render( - request, - "app.html", - { - "bootstrap": { - "collectionTitle": collection.title if collection else "", - "collectionUrl": collection.url if collection else "", - "collectionDescription": collection.description if collection else "", - }, - }, - ) + get_object_or_404(Event, path=event_path) + return render(request, "app.html") @login_required @require_game_enabled(NOITA_APP_ID) def noita_home(request: HttpRequest, event_path: str): get_object_or_404(Event, path=event_path) - return render(request, "app.html", {"bootstrap": {}}) + return render(request, "app.html") urlpatterns = [ diff --git a/polylan_submitter/public/favicon.ico b/polylan_submitter/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..22052abb327b6a8d1315371433c552bb74ca5d05 GIT binary patch literal 14388 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