Mobile UX: fixed bottom nav, compact header, less cramped cards

- App-shell layout (height:100dvh, only main scrolls) so the bottom nav
  is a natural flex child and never disappears regardless of browser
  chrome show/hide behaviour
- Bottom nav reduced from h-16 to h-14, icons from 20px to 18px, labels
  from 10px to 9px — slimmer bar, still readable
- Header: min-w-0 on search prevents horizontal overflow; user/sign-out
  hidden on mobile (accessible via Settings); logo shortened to "YT" on
  mobile; px-3 / h-12 on mobile instead of px-4 / h-14
- Grid card descriptions hidden on mobile (hidden sm:block) — reduces
  height cramping in the 2-column feed
- scrollToTop() utility replaces window.scrollTo so pagination still
  scrolls to top within the new scroll container

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mattias Tall
2026-05-26 12:30:23 +02:00
parent 3e63281849
commit cb05b739a8
6 changed files with 47 additions and 33 deletions

View File

@@ -6,6 +6,7 @@ import {
followDiscovery, dismissDiscovery, dismissDiscoveryVideo, refreshDiscovery,
} from "../api";
import VideoCard from "../components/VideoCard";
import { scrollToTop } from "../utils/scroll";
const PAGE_SIZE = 50;
@@ -305,7 +306,7 @@ export default function DiscoveryPage() {
</div>
<div className="flex items-center justify-center gap-3 pt-2">
<button
onClick={() => { setChannelPage(p => p - 1); window.scrollTo({ top: 0, behavior: "smooth" }); }}
onClick={() => { setChannelPage(p => p - 1); scrollToTop(); }}
disabled={channelPage === 0}
className="px-4 py-2 rounded-lg bg-zinc-800 text-zinc-300 text-sm font-medium hover:bg-zinc-700 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>
@@ -313,7 +314,7 @@ export default function DiscoveryPage() {
</button>
<span className="text-zinc-500 text-sm tabular-nums">Page {channelPage + 1}</span>
<button
onClick={() => { setChannelPage(p => p + 1); window.scrollTo({ top: 0, behavior: "smooth" }); }}
onClick={() => { setChannelPage(p => p + 1); scrollToTop(); }}
disabled={!hasNextChannelPage}
className="px-4 py-2 rounded-lg bg-zinc-800 text-zinc-300 text-sm font-medium hover:bg-zinc-700 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>
@@ -334,7 +335,7 @@ export default function DiscoveryPage() {
</div>
<div className="flex items-center justify-center gap-3 pt-2">
<button
onClick={() => { setVideoPage(p => p - 1); window.scrollTo({ top: 0, behavior: "smooth" }); }}
onClick={() => { setVideoPage(p => p - 1); scrollToTop(); }}
disabled={videoPage === 0}
className="px-4 py-2 rounded-lg bg-zinc-800 text-zinc-300 text-sm font-medium hover:bg-zinc-700 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>
@@ -342,7 +343,7 @@ export default function DiscoveryPage() {
</button>
<span className="text-zinc-500 text-sm tabular-nums">Page {videoPage + 1}</span>
<button
onClick={() => { setVideoPage(p => p + 1); window.scrollTo({ top: 0, behavior: "smooth" }); }}
onClick={() => { setVideoPage(p => p + 1); scrollToTop(); }}
disabled={!hasNextVideoPage}
className="px-4 py-2 rounded-lg bg-zinc-800 text-zinc-300 text-sm font-medium hover:bg-zinc-700 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>