From 31abdc03ef52c9d6592ad233349bccf2167a0f3e Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Sat, 16 May 2026 13:43:09 +0200 Subject: [PATCH] feat(hero): prev / next arrows on the Mainstage featured strip (#735) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(hero): prev / next arrows on the Mainstage featured strip Adds left and right chevron buttons over the featured-album hero so a single click flips to the previous / next album. Hitting the 8 px dot indicators was awkward and often opened the underlying album by mistake; the arrows give a generous 44 px touch target on each edge. - New `goPrev` / `goNext` callbacks wrap with modulo, restart the auto-advance timer on click (same pattern the old dot handler used). - Buttons live in a new `.hero-nav` flex wrapper with `inset: 0` and `justify-content: space-between`, so they pin to the hero's left and right edges regardless of theme padding. `pointer-events: none` on the wrapper + `auto` on the buttons keeps the rest of the hero click-through (navigate to album). - Dots are now decorative spans, not buttons — `pointer-events: none`, no hover state, no `onClick`. Clicking near a dot used to navigate to the album because the dot was too small to land on. - i18n: `previousAlbum` / `nextAlbum` keys in all 9 locales. Reported by zunoz on Discord. * docs(changelog): note Mainstage hero prev / next arrows (#735) --- CHANGELOG.md | 8 +++++ src/components/Hero.tsx | 57 +++++++++++++++++++++++++--------- src/locales/de/hero.ts | 2 ++ src/locales/en/hero.ts | 2 ++ src/locales/es/hero.ts | 2 ++ src/locales/fr/hero.ts | 2 ++ src/locales/nb/hero.ts | 2 ++ src/locales/nl/hero.ts | 2 ++ src/locales/ro/hero.ts | 2 ++ src/locales/ru/hero.ts | 2 ++ src/locales/zh/hero.ts | 2 ++ src/styles/components/hero.css | 47 +++++++++++++++++++++++----- 12 files changed, 109 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 953cf9f1..d69a42bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -202,6 +202,14 @@ Foundational work: faster reviews, narrower diffs, and a safety net under the pa * New opt-in columns **Plays**, **Last played**, and **BPM** on the Album / Playlist / Favorites tracklists, plus matching rows in the Song Info modal. Pulls Navidrome's existing `playCount` / `played` / `bpm` from the Subsonic response — no extra API calls. Genre column also added to the playlist tracklist for parity with Album + Favorites. BPM cells render `—` when Navidrome returns 0 (untagged file); Plays / Last played render `—` only when truly absent. * Defensive fix in the tracklist column hook: visible columns with no saved width on an older prefs blob now fall back to the ColDef's default width instead of collapsing the row layout. +### Mainstage hero — prev / next arrow buttons + +**By [@Psychotoxical](https://github.com/Psychotoxical), thanks to zunoz for the report on the Psysonic Discord, PR [#735](https://github.com/Psychotoxical/psysonic/pull/735)** + +* The featured-album strip on Mainstage now has **Previous** / **Next** chevron buttons on each edge of the hero. The existing 8 px dot indicators were a small target, and a near-miss often opened the underlying album instead of switching slides; the new 44 px buttons give a comfortable hit area on both desktop and touch. +* Buttons live in a new **`.hero-nav`** flex wrapper (`inset: 0`, `justify-content: space-between`, **`pointer-events: none`**); the buttons themselves opt back into **`pointer-events: auto`** so the rest of the hero stays click-through to the album page. Wrap-around (last → first / first → last) and auto-advance timer restart use the same pattern as the previous dot handler. +* The dot indicators are kept as **decorative spans** — no click handler, no hover state, **`pointer-events: none`** — so a missed click no longer navigates to the album. + ## Changed ### Backend — Cargo workspace with 5 domain crates (Rust refactor) diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index e988c6c3..74114d01 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -4,7 +4,7 @@ import type { SubsonicAlbum } from '../api/subsonicTypes'; import { songToTrack } from '../utils/playback/songToTrack'; import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Play, ListPlus } from 'lucide-react'; +import { Play, ListPlus, ChevronLeft, ChevronRight } from 'lucide-react'; import CachedImage, { useCachedUrl } from './CachedImage'; import { usePlayerStore } from '../store/playerStore'; import { useTranslation } from 'react-i18next'; @@ -224,9 +224,18 @@ export default function Hero({ albums: albumsProp }: HeroProps = {}) { }; }, [albums.length, heroInView, startTimer]); - const goTo = useCallback((idx: number) => { - setActiveIdx(idx); - startTimer(albums.length); + const goPrev = useCallback(() => { + const len = albums.length; + if (len <= 1) return; + setActiveIdx(prev => (prev - 1 + len) % len); + startTimer(len); + }, [albums.length, startTimer]); + + const goNext = useCallback(() => { + const len = albums.length; + if (len <= 1) return; + setActiveIdx(prev => (prev + 1) % len); + startTimer(len); }, [albums.length, startTimer]); const album = albums[activeIdx] ?? null; @@ -346,18 +355,38 @@ export default function Hero({ albums: albumsProp }: HeroProps = {}) { - {/* Carousel dot indicators */} + {/* Carousel navigation arrows + decorative dot indicators */} {albums.length > 1 && ( -