diff --git a/games/static/base.css b/games/static/base.css index 7977f0f..43e7a90 100644 --- a/games/static/base.css +++ b/games/static/base.css @@ -1,5 +1,113 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(63 131 248 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(63 131 248 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + /* -! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com */ /* @@ -442,7 +550,7 @@ video { /* Make elements with the HTML hidden attribute stay hidden by default */ -[hidden] { +[hidden]:where(:not([hidden="until-found"])) { display: none; } @@ -1104,114 +1212,6 @@ input:checked + .toggle-bg { border-color: #1C64F2; } -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(63 131 248 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(63 131 248 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - .container { width: 100%; } @@ -1258,6 +1258,10 @@ input:checked + .toggle-bg { border-width: 0; } +.pointer-events-none { + pointer-events: none; +} + .visible { visibility: visible; } @@ -1290,6 +1294,11 @@ input:checked + .toggle-bg { inset: 0px; } +.inset-y-0 { + top: 0px; + bottom: 0px; +} + .bottom-0 { bottom: 0px; } @@ -1318,6 +1327,10 @@ input:checked + .toggle-bg { right: 0.75rem; } +.start-0 { + inset-inline-start: 0px; +} + .top-0 { top: 0px; } @@ -1418,6 +1431,10 @@ input:checked + .toggle-bg { margin-inline-start: 0.625rem; } +.mt-1 { + margin-top: 0.25rem; +} + .mt-2 { margin-top: 0.5rem; } @@ -1535,6 +1552,10 @@ input:checked + .toggle-bg { width: 16rem; } +.w-80 { + width: 20rem; +} + .w-full { width: 100%; } @@ -1965,6 +1986,18 @@ input:checked + .toggle-bg { padding-bottom: 1rem; } +.pb-4 { + padding-bottom: 1rem; +} + +.ps-10 { + padding-inline-start: 2.5rem; +} + +.ps-3 { + padding-inline-start: 0.75rem; +} + .pt-2 { padding-top: 0.5rem; } @@ -2607,6 +2640,11 @@ textarea:disabled:is(.dark *) { z-index: 10; } +.focus\:border-blue-500:focus { + --tw-border-opacity: 1; + border-color: rgb(63 131 248 / var(--tw-border-opacity)); +} + .focus\:text-blue-700:focus { --tw-text-opacity: 1; color: rgb(26 86 219 / var(--tw-text-opacity)); @@ -2634,6 +2672,11 @@ textarea:disabled:is(.dark *) { --tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity)); } +.focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(63 131 248 / var(--tw-ring-opacity)); +} + .focus\:ring-blue-700:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(26 86 219 / var(--tw-ring-opacity)); @@ -2875,6 +2918,16 @@ textarea:disabled:is(.dark *) { color: rgb(255 255 255 / var(--tw-text-opacity)); } +.dark\:placeholder-gray-400:is(.dark *)::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); +} + +.dark\:placeholder-gray-400:is(.dark *)::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); +} + .odd\:dark\:bg-gray-900:is(.dark *):nth-child(odd) { --tw-bg-opacity: 1; background-color: rgb(17 24 39 / var(--tw-bg-opacity)); @@ -2945,6 +2998,11 @@ textarea:disabled:is(.dark *) { color: rgb(255 255 255 / var(--tw-text-opacity)); } +.dark\:focus\:border-blue-500:focus:is(.dark *) { + --tw-border-opacity: 1; + border-color: rgb(63 131 248 / var(--tw-border-opacity)); +} + .dark\:focus\:text-white:focus:is(.dark *) { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); diff --git a/games/templates/cotton/search_field.html b/games/templates/cotton/search_field.html new file mode 100644 index 0000000..804c67c --- /dev/null +++ b/games/templates/cotton/search_field.html @@ -0,0 +1,12 @@ + +
+ +
+
+ +
+ +
+
\ No newline at end of file diff --git a/games/urls.py b/games/urls.py index edd5def..946b64d 100644 --- a/games/urls.py +++ b/games/urls.py @@ -116,6 +116,7 @@ urlpatterns = [ name="list_sessions_end_session", ), path("session/list", session.list_sessions, name="list_sessions"), + path("session/search", session.search_sessions, name="search_sessions"), path("stats/", general.stats_alltime, name="stats_alltime"), path( "stats/", diff --git a/games/views/session.py b/games/views/session.py index d1dd66c..bb827f1 100644 --- a/games/views/session.py +++ b/games/views/session.py @@ -8,7 +8,15 @@ from django.template.loader import render_to_string from django.urls import reverse from django.utils import timezone -from common.components import A, Button, Div, Icon, LinkedNameWithPlatformIcon, Popover +from common.components import ( + A, + Button, + Div, + Form, + Icon, + LinkedNameWithPlatformIcon, + Popover, +) from common.time import ( dateformat, durationformat, @@ -24,11 +32,14 @@ from games.views.general import use_custom_redirect @login_required -def list_sessions(request: HttpRequest) -> HttpResponse: +def list_sessions(request: HttpRequest, search_string: str = "") -> HttpResponse: context: dict[Any, Any] = {} page_number = request.GET.get("page", 1) limit = request.GET.get("limit", 10) sessions = Session.objects.order_by("-timestamp_start") + search_string = request.GET.get("search_string", search_string) + if search_string != "": + sessions = sessions.filter(purchase__edition__name__icontains=search_string) last_session = sessions.latest() page_obj = None if int(limit) != 0: @@ -49,37 +60,49 @@ def list_sessions(request: HttpRequest) -> HttpResponse: "data": { "header_action": Div( children=[ - A( - url="add_session", - children=Button( - icon=True, - size="xs", - children=[Icon("play"), "LOG"], - ), + Form( + children=[ + render_to_string( + "cotton/search_field.html", {"id": "search_string"} + ) + ] ), - A( - url=reverse( - "list_sessions_start_session_from_session", - args=[last_session.pk], - ), - children=Popover( - popover_content=last_session.purchase.edition.name, - children=[ - Button( + Div( + children=[ + A( + url="add_session", + children=Button( icon=True, - color="gray", size="xs", + children=[Icon("play"), "LOG"], + ), + ), + A( + url=reverse( + "list_sessions_start_session_from_session", + args=[last_session.pk], + ), + children=Popover( + popover_content=last_session.purchase.edition.name, children=[ - Icon("play"), - truncate( - f"{last_session.purchase.edition.name}" - ), + Button( + icon=True, + color="gray", + size="xs", + children=[ + Icon("play"), + truncate( + f"{last_session.purchase.edition.name}" + ), + ], + ) ], - ) - ], - ), + ), + ), + ] ), ], + attributes=[("class", "flex justify-between")], ), "columns": [ "Name", @@ -150,6 +173,11 @@ def list_sessions(request: HttpRequest) -> HttpResponse: return render(request, "list_purchases.html", context) +@login_required +def search_sessions(request: HttpRequest) -> HttpResponse: + return list_sessions(request, search_string=request.GET.get("search_string", "")) + + @login_required def add_session(request: HttpRequest, purchase_id: int = 0) -> HttpResponse: context = {}