From bf38a286cd7930d60fc23361f8bd0a2b6653f21a Mon Sep 17 00:00:00 2001 From: kilyabin <65072190+kilyabin@users.noreply.github.com> Date: Sun, 12 Apr 2026 13:26:27 +0400 Subject: [PATCH] feat(nav): merge Random Mix & Albums into Build a Mix hub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces two sidebar entries (Random Mix, Random Albums) with a single 'Build a Mix' item (Wand2 icon) at /random. Landing page shows two cards — Mix by Tracks and Mix by Albums — with glow-on-hover. Old routes updated throughout. All 7 locales updated. --- src/App.tsx | 6 ++- src/components/Sidebar.tsx | 9 ++-- src/locales/de.ts | 8 +++ src/locales/en.ts | 8 +++ src/locales/fr.ts | 8 +++ src/locales/nb.ts | 8 +++ src/locales/nl.ts | 8 +++ src/locales/ru.ts | 8 +++ src/locales/zh.ts | 8 +++ src/pages/Home.tsx | 2 +- src/pages/RandomLanding.tsx | 52 ++++++++++++++++++++ src/store/sidebarStore.ts | 3 +- src/styles/components.css | 98 +++++++++++++++++++++++++++++++++++++ 13 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 src/pages/RandomLanding.tsx diff --git a/src/App.tsx b/src/App.tsx index 00c08c38..e975b0bb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,6 +21,7 @@ import ArtistDetail from './pages/ArtistDetail'; import NewReleases from './pages/NewReleases'; import Favorites from './pages/Favorites'; import RandomMix from './pages/RandomMix'; +import RandomLanding from './pages/RandomLanding'; import Settings from './pages/Settings'; import Login from './pages/Login'; import AlbumDetail from './pages/AlbumDetail'; @@ -347,13 +348,14 @@ function AppShell() { } /> } /> - } /> + } /> + } /> } /> } /> } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 05100a73..0f805079 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -8,9 +8,9 @@ import { useSidebarStore } from '../store/sidebarStore'; import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { - Disc3, Users, Music4, Radio, Settings, Heart, BarChart3, Shuffle, - PanelLeftClose, PanelLeft, HelpCircle, Dices, AudioLines, HardDriveDownload, Tags, ListMusic, Cast, - ChevronDown, Check, Music2, TrendingUp, FolderOpen, X, + Disc3, Users, Music4, Radio, Settings, Heart, BarChart3, + PanelLeftClose, PanelLeft, HelpCircle, AudioLines, HardDriveDownload, Tags, ListMusic, Cast, + ChevronDown, Check, Music2, TrendingUp, FolderOpen, X, Wand2, } from 'lucide-react'; import PsysonicLogo from './PsysonicLogo'; import PSmallLogo from './PSmallLogo'; @@ -21,10 +21,9 @@ export const ALL_NAV_ITEMS: Record loadMore('random', random, setRandom)} moreText={t('home.discoverMore')} diff --git a/src/pages/RandomLanding.tsx b/src/pages/RandomLanding.tsx new file mode 100644 index 00000000..de4370d1 --- /dev/null +++ b/src/pages/RandomLanding.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { Shuffle, Dices } from 'lucide-react'; + +interface MixCard { + icon: React.ElementType; + labelKey: string; + descKey: string; + to: string; +} + +const CARDS: MixCard[] = [ + { + icon: Shuffle, + labelKey: 'randomLanding.mixByTracks', + descKey: 'randomLanding.mixByTracksDesc', + to: '/random/mix', + }, + { + icon: Dices, + labelKey: 'randomLanding.mixByAlbums', + descKey: 'randomLanding.mixByAlbumsDesc', + to: '/random/albums', + }, +]; + +export default function RandomLanding() { + const { t } = useTranslation(); + const navigate = useNavigate(); + + return ( +
+
+ {CARDS.map(({ icon: Icon, labelKey, descKey, to }) => ( + + ))} +
+
+ ); +} diff --git a/src/store/sidebarStore.ts b/src/store/sidebarStore.ts index 47f7b282..0177e956 100644 --- a/src/store/sidebarStore.ts +++ b/src/store/sidebarStore.ts @@ -12,10 +12,9 @@ export const DEFAULT_SIDEBAR_ITEMS: SidebarItemConfig[] = [ { id: 'mainstage', visible: true }, { id: 'newReleases', visible: true }, { id: 'allAlbums', visible: true }, - { id: 'randomAlbums', visible: true }, + { id: 'randomPicker', visible: true }, { id: 'artists', visible: true }, { id: 'genres', visible: true }, - { id: 'randomMix', visible: true }, { id: 'favorites', visible: true }, { id: 'playlists', visible: true }, { id: 'mostPlayed', visible: true }, diff --git a/src/styles/components.css b/src/styles/components.css index 468a37ea..cbdf1a35 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -5596,6 +5596,104 @@ margin: 0.2rem 0 0; } +/* ─ Random Landing ─ */ +.random-landing { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100%; + padding: var(--space-8); + box-sizing: border-box; +} + + +.random-landing-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: clamp(var(--space-4), 2vw, var(--space-6)); + width: 100%; + max-width: min(860px, 90vw); +} + +.mix-pick-card { + position: relative; + overflow: hidden; + display: flex; + align-items: flex-end; + min-height: clamp(200px, 22vh, 320px); + padding: var(--space-6); + border-radius: 16px; + background: var(--ctp-surface0); + border: 1px solid rgba(255, 255, 255, 0.06); + cursor: pointer; + text-align: left; + transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; + color: inherit; +} + +.mix-pick-card:hover { + transform: translateY(-4px) scale(1.015); + box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35), 0 0 0 1px var(--accent), 0 0 24px -4px var(--accent); + border-color: var(--accent); +} + +.mix-pick-card-bg-icon { + position: absolute; + top: 50%; + right: -16px; + transform: translateY(-50%); + width: clamp(140px, 14vw, 200px); + height: clamp(140px, 14vw, 200px); + color: var(--text-primary); + opacity: 0.07; + pointer-events: none; + flex-shrink: 0; +} + +.mix-pick-card-content { + position: relative; + display: flex; + flex-direction: column; + gap: var(--space-2); + z-index: 1; +} + +.mix-pick-card-icon { + color: var(--accent); + margin-bottom: var(--space-1); +} + +.mix-pick-card-label { + font-family: var(--font-display); + font-size: 17px; + font-weight: 700; + color: var(--text-primary); + line-height: 1.2; +} + +.mix-pick-card-desc { + font-size: 12px; + color: var(--text-muted); + line-height: 1.45; + max-width: 22ch; +} + +@media (max-width: 640px) { + .random-landing { + padding: var(--space-5) var(--space-4); + justify-content: flex-start; + } + + .random-landing-grid { + grid-template-columns: 1fr; + } + + .mix-pick-card { + min-height: 160px; + } +} + /* ─ Playlists overview header ─ */ .playlists-header { display: flex;