fix: improve accessibility and keyboard navigation
This commit is contained in:
@@ -144,7 +144,9 @@
|
||||
|
||||
<main class="w-full flex-1 flex flex-col h-[calc(100dvh-3.5rem)] overflow-y-auto lg:h-screen">
|
||||
<div class="flex-1 p-4 md:p-8">
|
||||
{{template "content" .}}
|
||||
{{block "page_container" .}}
|
||||
{{template "content" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
{{$displayTitle := $anime.DisplayTitle}}
|
||||
|
||||
<div class="flex w-full flex-col gap-2" data-id="{{$dataId}}">
|
||||
<a href="/anime/{{$anime.MalID}}" class="group relative flex aspect-2/3 w-full flex-col overflow-hidden bg-background-surface after:absolute after:inset-0 {{if $withActions}}after:bg-black/80 after:opacity-0 hover:after:opacity-100{{else}}after:bg-linear-to-t after:from-black/80 after:via-black/20 after:to-transparent after:opacity-80 hover:after:opacity-100{{end}} after:transition-opacity">
|
||||
<a
|
||||
href="/anime/{{$anime.MalID}}"
|
||||
class="group relative flex aspect-2/3 w-full flex-col overflow-hidden bg-background-surface outline-none ring-0 transition focus-visible:ring-1 focus-visible:ring-accent after:absolute after:inset-0 {{if $withActions}}after:bg-black/60 after:opacity-0 hover:after:opacity-100{{else}}after:bg-linear-to-t after:from-black/70 after:via-black/20 after:to-transparent after:opacity-75 hover:after:opacity-100{{end}} after:transition-opacity"
|
||||
>
|
||||
<img src="{{$imageUrl}}" alt="{{$displayTitle}}" class="h-full w-full object-cover" loading="lazy" />
|
||||
|
||||
{{if $withActions}}
|
||||
<div class="absolute inset-0 z-10 flex flex-col p-3 {{if $hasTopBadge}}pt-10{{end}} opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||
{{if not $isWatchlist}}
|
||||
<h3 class="mb-1.5 line-clamp-2 text-base font-semibold text-white">
|
||||
<h3 class="mb-1.5 line-clamp-2 text-base font-medium text-white">
|
||||
{{$displayTitle}}
|
||||
</h3>
|
||||
{{end}}
|
||||
@@ -40,7 +43,7 @@
|
||||
data-watchlist-toggle
|
||||
data-mal-id="{{$anime.MalID}}"
|
||||
data-watchlist-title="{{$anime.DisplayTitle}}"
|
||||
class="text-accent hover:text-accent/80 transition-colors focus:outline-none disabled:opacity-50 {{if $isWatchlist}}in-watchlist{{end}}"
|
||||
class="text-accent hover:text-accent/80 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:opacity-50 {{if $isWatchlist}}in-watchlist{{end}}"
|
||||
aria-label="{{if $isWatchlist}}Remove from Watchlist{{else}}Add to Watchlist{{end}}"
|
||||
>
|
||||
<svg class="size-6 watchlist-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z" /></svg>
|
||||
@@ -49,7 +52,7 @@
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="absolute bottom-0 left-0 z-10 w-full p-4">
|
||||
<h3 class="line-clamp-2 text-sm font-medium text-white {{if $compact}}mb-0{{end}}">
|
||||
<h3 class="line-clamp-2 text-sm font-normal text-white {{if $compact}}mb-0{{end}}">
|
||||
{{$displayTitle}}
|
||||
</h3>
|
||||
{{if not $compact}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{define "continue_watching"}}
|
||||
<section id="continue-watching-section" class="w-full empty:hidden">
|
||||
<h2 class="mb-3 text-lg font-normal text-foreground">Continue Watching</h2>
|
||||
<h2 class="mb-3 text-base font-normal text-foreground">Continue Watching</h2>
|
||||
|
||||
<div id="continue-watching-items" class="flex snap-x snap-mandatory gap-2 overflow-x-auto pb-4 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden lg:[-ms-overflow-style:auto] lg:[scrollbar-width:thin] lg:[scrollbar-color:var(--scrollbar-thumb)_var(--scrollbar-track)] lg:[&::-webkit-scrollbar]:block lg:[&::-webkit-scrollbar]:h-2 lg:[&::-webkit-scrollbar-track]:bg-[var(--scrollbar-track)] lg:[&::-webkit-scrollbar-track]:rounded-none lg:[&::-webkit-scrollbar-thumb]:bg-[var(--scrollbar-thumb)] lg:[&::-webkit-scrollbar-thumb]:rounded-none lg:[&::-webkit-scrollbar-thumb:hover]:bg-[var(--scrollbar-thumb-hover)]">
|
||||
{{range .}}
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
<div id="continue-watching-{{.AnimeID}}" class="continue-watching-item group relative w-70 shrink-0 snap-start space-y-2 2xl:w-lg">
|
||||
<div class="bg-background/80 relative aspect-video w-full overflow-hidden">
|
||||
<a href="/anime/{{.AnimeID}}/watch{{if .CurrentEpisode.Valid}}?ep={{.CurrentEpisode.Int64}}{{end}}" class="block h-full w-full">
|
||||
<a href="/anime/{{.AnimeID}}/watch{{if .CurrentEpisode.Valid}}?ep={{.CurrentEpisode.Int64}}{{end}}" class="block h-full w-full outline-none ring-0 transition focus-visible:ring-1 focus-visible:ring-accent">
|
||||
<img src="{{if .ImageUrl}}{{.ImageUrl}}{{else}}https://placehold.co/500x500{{end}}" alt="{{$title}}" class="h-full w-full object-cover" />
|
||||
</a>
|
||||
|
||||
<div class="absolute inset-0 z-10 flex flex-col p-3 opacity-0 transition-opacity duration-300 group-hover:opacity-100 bg-black/40 pointer-events-none">
|
||||
<div class="flex justify-end pointer-events-auto">
|
||||
<button hx-delete="/api/continue-watching/{{.AnimeID}}" hx-target="#continue-watching-{{.AnimeID}}" hx-swap="delete" class="bg-black/60 hover:bg-black/80 rounded-full p-1.5 text-white transition-colors focus:outline-none disabled:opacity-50 backdrop-blur-sm" aria-label="Remove from Continue Watching">
|
||||
<button hx-delete="/api/continue-watching/{{.AnimeID}}" hx-target="#continue-watching-{{.AnimeID}}" hx-swap="delete" class="bg-black/60 hover:bg-black/80 rounded-full p-1.5 text-white transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:opacity-50 backdrop-blur-sm" aria-label="Remove from Continue Watching">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-5"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -29,11 +29,11 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="/anime/{{.AnimeID}}/watch{{if .CurrentEpisode.Valid}}?ep={{.CurrentEpisode.Int64}}{{end}}" class="block">
|
||||
<h3 class="text-foreground truncate text-lg font-normal">
|
||||
<a href="/anime/{{.AnimeID}}/watch{{if .CurrentEpisode.Valid}}?ep={{.CurrentEpisode.Int64}}{{end}}" class="block outline-none focus-visible:ring-1 focus-visible:ring-accent">
|
||||
<h3 class="text-foreground truncate text-sm font-normal">
|
||||
{{$title}}
|
||||
</h3>
|
||||
<p class="text-foreground-muted mt-0.5 text-base">
|
||||
<p class="text-foreground-muted mt-0.5 text-xs">
|
||||
{{if .CurrentEpisode.Valid}}Episode {{.CurrentEpisode.Int64}}{{end}}
|
||||
</p>
|
||||
</a>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form action="/browse" method="GET" hx-get="/browse" hx-trigger="change" hx-target="#browse-content main" hx-select="#browse-content main" hx-swap="outerHTML" class="flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground">
|
||||
<form action="/browse" method="GET" hx-get="/browse" hx-trigger="change" hx-target="#browse-content main" hx-select="#browse-content main" hx-swap="outerHTML" class="!rounded-none flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground">
|
||||
<input type="hidden" name="q" value="{{.Query}}">
|
||||
{{if .Type}}<input type="hidden" name="type" value="{{.Type}}">{{end}}
|
||||
{{if .Status}}<input type="hidden" name="status" value="{{.Status}}">{{end}}
|
||||
@@ -31,7 +31,7 @@
|
||||
{{range $g := .Genres}}<input type="hidden" name="genres" value="{{$g}}">{{end}}
|
||||
<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)">
|
||||
<div class="flex h-4 w-4 items-center justify-center bg-white transition-colors">
|
||||
<div class="flex h-4 w-4 items-center justify-center bg-white ring-1 ring-black/15 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>
|
||||
</div>
|
||||
SFW
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
<ui-dropdown class="relative block" data-align="left" data-width="w-48">
|
||||
<div data-trigger class="cursor-pointer">
|
||||
<button class="flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground hover:bg-background-button-hover transition-colors">
|
||||
<button class="!rounded-none flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground hover:bg-background-button-hover transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">
|
||||
{{if $selectedCount}}Genres ({{$selectedCount}}){{else}}Genres{{end}}
|
||||
<svg class="h-4 w-4 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6" /></svg>
|
||||
</button>
|
||||
@@ -107,7 +107,7 @@
|
||||
<div class="flex items-center gap-1">
|
||||
<ui-dropdown class="relative block" data-align="left" data-width="w-48">
|
||||
<div data-trigger class="cursor-pointer">
|
||||
<button class="flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground hover:bg-background-button-hover transition-colors">
|
||||
<button class="!rounded-none flex items-center gap-2 bg-background-button px-3 py-2 text-sm text-foreground hover:bg-background-button-hover transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">
|
||||
Sort: {{if eq .OrderBy "popularity"}}Popularity{{else if eq .OrderBy "score"}}Score{{else if eq .OrderBy "title"}}Title{{else if eq .OrderBy "start_date"}}Start Date{{else if eq .OrderBy "episodes"}}Episodes{{else}}Default{{end}}
|
||||
<svg class="h-4 w-4 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6" /></svg>
|
||||
</button>
|
||||
@@ -124,7 +124,7 @@
|
||||
</div>
|
||||
</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 .Genres }}&{{ genresParams .Genres }}{{ end }}" class="flex h-9 w-9 items-center justify-center bg-background-button text-foreground-muted hover:text-foreground transition-colors">
|
||||
<a href="?sort={{if eq .Sort "asc"}}desc{{else}}asc{{end}}&q={{.Query}}&status={{.Status}}&type={{.Type}}&order_by={{.OrderBy}}&sfw={{.SFW}}{{ 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">
|
||||
{{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>
|
||||
{{else}}
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
{{/* Home */}}
|
||||
{{$isActive := eq $currentPath "/"}}
|
||||
<a href="/" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Home"{{end}}>
|
||||
<a href="/" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Home"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||
{{if $isActive}}
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm shadow-[0_0_8px_var(--color-accent)]"></div>
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm"></div>
|
||||
{{end}}
|
||||
<svg class="size-6 shrink-0 transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
@@ -43,9 +43,9 @@
|
||||
|
||||
{{/* Browse */}}
|
||||
{{$isActive := eq $currentPath "/browse"}}
|
||||
<a href="/browse" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Browse"{{end}}>
|
||||
<a href="/browse" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Browse"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||
{{if $isActive}}
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm shadow-[0_0_8px_var(--color-accent)]"></div>
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm"></div>
|
||||
{{end}}
|
||||
<svg class="size-6 shrink-0 transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="2" y="2" width="20" height="20" rx="0" ry="0" />
|
||||
@@ -66,9 +66,9 @@
|
||||
|
||||
{{/* Discover */}}
|
||||
{{$isActive := eq $currentPath "/discover"}}
|
||||
<a href="/discover" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Discover"{{end}}>
|
||||
<a href="/discover" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Discover"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||
{{if $isActive}}
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm shadow-[0_0_8px_var(--color-accent)]"></div>
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm"></div>
|
||||
{{end}}
|
||||
<svg class="size-6 shrink-0 transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
@@ -83,9 +83,9 @@
|
||||
|
||||
{{/* Watchlist */}}
|
||||
{{$isActive := eq $currentPath "/watchlist"}}
|
||||
<a href="/watchlist" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Watchlist"{{end}}>
|
||||
<a href="/watchlist" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Watchlist"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||
{{if $isActive}}
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm shadow-[0_0_8px_var(--color-accent)]"></div>
|
||||
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm"></div>
|
||||
{{end}}
|
||||
<svg class="size-6 shrink-0 transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M17 18.113l-3.256-2.326A2.989 2.989 0 0 0 12 15.228c-.629 0-1.232.194-1.744.559L7 18.113V4h10v14.113zM18 2H6a1 1 0 0 0-1 1v17.056c0 .209.065.412.187.581a.994.994 0 0 0 1.394.233l4.838-3.455a1 1 0 0 1 1.162 0l4.838 3.455A1 1 0 0 0 19 20.056V3a1 1 0 0 0-1-1z" />
|
||||
|
||||
Reference in New Issue
Block a user