feat(reader): glass chrome — translucent bars, custom slider, slide-away hide

Modernize the reader chrome bars without touching the drawer system:

- Bars become theme-tinted glass: 70% bg-primary translucency over
  the edge-to-edge page, 18px backdrop blur + saturation, hairline
  translucent borders, soft directional shadows (single .reader-glass
  class owns the effect; replaces solid opaque backgrounds and the
  tailwind backdrop-blur that would override it).
- Chrome hide/show now slides the bars off-screen (translateY) in
  addition to the opacity fade, via .chrome-hidden on #reader-chrome.
- Theme-aware hover pills (translucent currentColor tint) replace
  hard-coded gray-700 hovers; focus-visible rings added.
- Progress slider gets a custom thin rounded track with a floating
  white thumb (webkit + gecko), replacing native range styling.
- Separators and the fit-mode select match the glass language
  (.reader-sep, .reader-select).
This commit is contained in:
2026-08-14 15:16:05 -04:00
parent 612f888683
commit 14d1a158a0
4 changed files with 117 additions and 20 deletions
+10 -11
View File
@@ -139,9 +139,9 @@ templ Reader(user User, metadata ReaderMetadata, progress ReadingProgress, bookm
}
templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
<div id="reader-chrome" class="transition-opacity duration-300" :class="chromeVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'">
<div id="reader-chrome" class="transition-opacity duration-300" :class="chromeVisible ? 'opacity-100' : 'chrome-hidden opacity-0 pointer-events-none'">
<!-- Top bar -->
<div id="reader-topbar" class="fixed top-0 left-0 right-0 backdrop-blur border-b z-40 pt-[env(safe-area-inset-top)]" style="background-color: var(--bg-primary);">
<div id="reader-topbar" class="fixed top-0 left-0 right-0 border-b z-40 pt-[env(safe-area-inset-top)] reader-glass">
<div class="flex items-center justify-between px-3 py-2 sm:px-4">
<a id="reader-back" href={ "/media/" + metadata.MediaItemID } class="text-base sm:text-lg hover:underline">
Back
@@ -155,7 +155,7 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
</div>
</div>
<!-- Bottom bar -->
<div id="reader-bottombar" class="fixed bottom-0 left-0 right-0 backdrop-blur border-t z-40 pb-[env(safe-area-inset-bottom)]" style="background-color: var(--bg-primary);">
<div id="reader-bottombar" class="fixed bottom-0 left-0 right-0 border-t z-40 pb-[env(safe-area-inset-bottom)] reader-glass">
<!-- Reflowable row -->
<div x-show="!isFixedLayout" class="flex items-center px-1.5 py-1.5 gap-0.5 sm:px-2 sm:py-2 sm:gap-1">
<button @click="goLeft()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700" title="Go Left" aria-label="Go left">
@@ -179,7 +179,7 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
<path d="M 9 6 L 15 12 L 9 18"></path>
</svg>
</button>
<div class="w-px h-6 bg-gray-600 mx-1"></div>
<div class="w-px h-6 mx-1 reader-sep"></div>
<div id="progress-display" @click="cycleProgressMode()" :title="progressTooltip()" class="text-sm min-w-[4rem] max-w-[5rem] sm:max-w-none text-center cursor-pointer truncate whitespace-nowrap overflow-hidden">
<span class="hidden sm:inline" x-text="progressLabel"></span><span x-text="progressMain">
if progress.FormatGroup == "reflowable" {
@@ -193,7 +193,7 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
}
</span>
</div>
<div class="w-px h-6 bg-gray-600 mx-1"></div>
<div class="w-px h-6 mx-1 reader-sep"></div>
<button @click="toggleTOC()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700" title="Table of Contents (t)">📖</button>
</div>
<!-- Fixed-layout row (comics, PDFs, manga) -->
@@ -217,12 +217,11 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
<path d="M 9 6 L 15 12 L 9 18"></path>
</svg>
</button>
<div class="w-px h-6 bg-gray-600 mx-1 shrink-0"></div>
<div class="w-px h-6 mx-1 shrink-0 reader-sep"></div>
<!-- Fit mode -->
<select
@change="applyFitMode($event.target.value)"
class="text-xs px-1.5 py-1 rounded-lg bg-transparent border shrink-0"
style="border-color: var(--border);"
class="reader-select text-xs px-1.5 py-1 rounded-lg shrink-0"
title="Fit mode"
aria-label="Fit mode"
>
@@ -256,14 +255,14 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
<button :class="interactionMode === 'pan' ? 'active' : ''" @click="setInteractionMode('pan')" title="Pan: drag anywhere to move">Pan</button>
<button :class="interactionMode === 'text' ? 'active' : ''" @click="setInteractionMode('text')" title="Text: selection only, never pan (Shift overrides)">Text</button>
</div>
<div class="w-px h-6 bg-gray-600 mx-1 shrink-0"></div>
<div class="w-px h-6 mx-1 shrink-0 reader-sep"></div>
<!-- Double page spread -->
<button @click="toggleSpread()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700 shrink-0" :class="doublePageSpread ? 'bg-blue-600 hover:bg-blue-700' : ''" title="Double Page Spread" aria-label="Toggle double page spread">
<svg class="reader-icon" width="20" height="20" aria-hidden="true">
<path d="M 3 5 h 6 v 14 h -6 z M 15 5 h 6 v 14 h -6 z"></path>
</svg>
</button>
<div class="w-px h-6 bg-gray-600 mx-1 shrink-0"></div>
<div class="w-px h-6 mx-1 shrink-0 reader-sep"></div>
<div id="progress-display-fx" @click="cycleProgressMode()" :title="progressTooltip()" class="text-sm min-w-[3.5rem] text-center cursor-pointer truncate whitespace-nowrap overflow-hidden shrink-0">
<span x-text="progressMain">
if progress.FormatGroup == "reflowable" {
@@ -273,7 +272,7 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
}
</span>
</div>
<div class="w-px h-6 bg-gray-600 mx-1 shrink-0"></div>
<div class="w-px h-6 mx-1 shrink-0 reader-sep"></div>
<button @click="toggleTOC()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700 shrink-0" title="Table of Contents (t)">📖</button>
</div>
</div>