refactor: use browseURL helper and simplify filter bar templates

This commit is contained in:
2026-06-06 16:53:16 +02:00
parent 9cb3e8fe27
commit 03e741c561

View File

@@ -1,6 +1,28 @@
{{define "filter_bar"}} {{define "filter_bar"}}
{{$selectedGenreIDs := .Genres}} {{$selectedGenreIDs := .Genres}}
{{$selectedCount := len $selectedGenreIDs}} {{$selectedCount := len $selectedGenreIDs}}
{{$statusOptions := list
(dict "Value" "" "Label" "Any Status")
(dict "Value" "airing" "Label" "Airing")
(dict "Value" "complete" "Label" "Complete")
(dict "Value" "upcoming" "Label" "Upcoming")
}}
{{$typeOptions := list
(dict "Value" "" "Label" "Any Type")
(dict "Value" "tv" "Label" "TV")
(dict "Value" "movie" "Label" "Movie")
(dict "Value" "ova" "Label" "OVA")
(dict "Value" "special" "Label" "Special")
(dict "Value" "ona" "Label" "ONA")
}}
{{$sortOptions := list
(dict "Value" "" "Label" "Default")
(dict "Value" "popularity" "Label" "Popularity")
(dict "Value" "score" "Label" "Score")
(dict "Value" "title" "Label" "Title")
(dict "Value" "start_date" "Label" "Start Date")
(dict "Value" "episodes" "Label" "Episodes")
}}
<div class="flex flex-wrap items-center gap-3" hx-boost="true" hx-target="#browse-content" hx-swap="outerHTML" hx-push-url="true"> <div class="flex flex-wrap items-center gap-3" hx-boost="true" hx-target="#browse-content" hx-swap="outerHTML" hx-push-url="true">
<div class="min-w-50 flex-1"> <div class="min-w-50 flex-1">
<form action="/browse" method="GET" id="browse-search-form" hx-get="/browse" hx-trigger="submit, input changed delay:350ms from:#search, search from:#search" hx-sync="this:replace"> <form action="/browse" method="GET" id="browse-search-form" hx-get="/browse" hx-trigger="submit, input changed delay:350ms from:#search, search from:#search" hx-sync="this:replace">
@@ -60,9 +82,9 @@
<input type="hidden" name="sfw" value="{{.SFW}}" data-sfw-value> <input type="hidden" name="sfw" value="{{.SFW}}" data-sfw-value>
{{range $g := .Genres}}<input type="hidden" name="genres" value="{{$g}}">{{end}} {{range $g := .Genres}}<input type="hidden" name="genres" value="{{$g}}">{{end}}
<label class="flex cursor-pointer items-center gap-2"> <label class="flex cursor-pointer items-center gap-2">
<input id="filter-sfw" type="checkbox" class="sr-only" {{if .SFW}}checked{{end}} onchange="this.form.querySelector('[data-sfw-value]').value = this.checked; const box = this.nextElementSibling; const icon = box.querySelector('svg'); icon.classList.toggle('hidden', !this.checked)"> <input id="filter-sfw" type="checkbox" class="sr-only" data-checkbox-visual data-sfw-checkbox {{if .SFW}}checked{{end}}>
<div class="flex h-4 w-4 items-center justify-center bg-white ring-1 ring-black/15 transition-colors"> <div class="flex h-5 w-5 items-center justify-center border-2 border-white/45 bg-transparent transition-colors">
<svg class="{{if not .SFW}}hidden {{end}}h-3 w-3 text-black" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M20 6 9 17l-5-5" /></svg> <svg class="{{if not .SFW}}hidden {{end}}h-3.5 w-3.5 text-accent" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M20 6 9 17l-5-5" /></svg>
</div> </div>
SFW SFW
</label> </label>
@@ -88,9 +110,9 @@
{{$genreID := .MalID}} {{$genreID := .MalID}}
{{$isSelected := hasGenre $genreID $selectedGenreIDs}} {{$isSelected := hasGenre $genreID $selectedGenreIDs}}
<label class="flex cursor-pointer items-center gap-3 px-2 py-1.5 text-sm text-foreground-muted hover:bg-surface-hover hover:text-foreground"> <label class="flex cursor-pointer items-center gap-3 px-2 py-1.5 text-sm text-foreground-muted hover:bg-surface-hover hover:text-foreground">
<input id="genre-{{.MalID}}" type="checkbox" class="sr-only" name="genres" value="{{.MalID}}" {{if $isSelected}}checked{{end}} onchange="const box = this.nextElementSibling; box.classList.toggle('bg-accent', this.checked); box.classList.toggle('bg-transparent', !this.checked); box.querySelector('svg').classList.toggle('hidden', !this.checked)"> <input id="genre-{{.MalID}}" type="checkbox" class="sr-only" name="genres" value="{{.MalID}}" data-checkbox-visual data-genre-visual {{if $isSelected}}checked{{end}}>
<div class="flex h-4 w-4 items-center justify-center transition-colors {{if $isSelected}}bg-accent{{else}}bg-transparent{{end}}"> <div class="flex h-5 w-5 items-center justify-center border-2 transition-colors {{if $isSelected}}border-accent bg-foreground-muted/12{{else}}border-white/45 bg-transparent{{end}}">
<svg class="{{if not $isSelected}}hidden {{end}}h-3 w-3 text-on-accent" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M20 6 9 17l-5-5" /></svg> <svg class="{{if not $isSelected}}hidden {{end}}h-3.5 w-3.5 text-accent" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M20 6 9 17l-5-5" /></svg>
</div> </div>
{{.Name}} {{.Name}}
</label> </label>
@@ -108,10 +130,9 @@
</div> </div>
<div data-content class="hidden absolute z-50 w-40 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 "> <div data-content class="hidden absolute z-50 w-40 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 ">
<div class="flex flex-col py-1"> <div class="flex flex-col py-1">
<a href="?status=&q={{.Query}}&type={{.Type}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Any Status</a> {{range $statusOptions}}
<a href="?status=airing&q={{.Query}}&type={{.Type}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Airing</a> <a href='{{browseURL $ (dict "status" .Value)}}' class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">{{.Label}}</a>
<a href="?status=complete&q={{.Query}}&type={{.Type}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Complete</a> {{end}}
<a href="?status=upcoming&q={{.Query}}&type={{.Type}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Upcoming</a>
</div> </div>
</div> </div>
</ui-dropdown> </ui-dropdown>
@@ -125,12 +146,9 @@
</div> </div>
<div data-content class="hidden absolute z-50 w-40 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 "> <div data-content class="hidden absolute z-50 w-40 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 ">
<div class="flex flex-col py-1"> <div class="flex flex-col py-1">
<a href="?type=&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Any Type</a> {{range $typeOptions}}
<a href="?type=tv&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">TV</a> <a href='{{browseURL $ (dict "type" .Value)}}' class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">{{.Label}}</a>
<a href="?type=movie&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Movie</a> {{end}}
<a href="?type=ova&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">OVA</a>
<a href="?type=special&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Special</a>
<a href="?type=ona&q={{.Query}}&status={{.Status}}&order_by={{.OrderBy}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">ONA</a>
</div> </div>
</div> </div>
</ui-dropdown> </ui-dropdown>
@@ -145,17 +163,14 @@
</div> </div>
<div data-content class="hidden absolute z-50 w-48 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 "> <div data-content class="hidden absolute z-50 w-48 bg-background-button rounded-none shadow-[var(--shadow-card)] left-0 top-full mt-2 ">
<div class="flex flex-col py-1"> <div class="flex flex-col py-1">
<a href="?order_by=&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Default</a> {{range $sortOptions}}
<a href="?order_by=popularity&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Popularity</a> <a href='{{browseURL $ (dict "order_by" .Value)}}' class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">{{.Label}}</a>
<a href="?order_by=score&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Score</a> {{end}}
<a href="?order_by=title&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Title</a>
<a href="?order_by=start_date&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Start Date</a>
<a href="?order_by=episodes&q={{.Query}}&status={{.Status}}&type={{.Type}}&sort={{.Sort}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-surface-hover text-sm text-foreground">Episodes</a>
</div> </div>
</div> </div>
</ui-dropdown> </ui-dropdown>
<a href="?sort={{if eq .Sort "asc"}}desc{{else}}asc{{end}}&q={{.Query}}&status={{.Status}}&type={{.Type}}&order_by={{.OrderBy}}&sfw={{.SFW}}{{if .Studio}}&studio={{.Studio}}{{end}}{{ if .Genres }}&{{ genresParams .Genres }}{{ end }}" class="!rounded-none flex h-9 w-9 items-center justify-center bg-background-button text-foreground-muted hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent"> <a href='{{browseURL . (dict "sort" (nextSort .Sort))}}' class="!rounded-none flex h-9 w-9 items-center justify-center bg-background-button text-foreground-muted hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">
{{if eq .Sort "asc"}} {{if eq .Sort "asc"}}
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5M5 12l7-7 7 7" /></svg> <svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5M5 12l7-7 7 7" /></svg>
{{else}} {{else}}