music: Music Player widget + app-wide player dock
The widget browses the /api/music/* library (search albums → tracklist) and hands a queue to an app-wide player. The player (useMusicPlayer, useGlobal-backed) and its site-wide bottom dock (MusicPlayerHost) live in the persistent DashboardLayout, so playback survives route changes. Dock has cover/title/artist, drag-scrubbing (SeekBar), volume (persisted), and prev/play/next/close. The nav Dock slides up by MUSIC_DOCK_HEIGHT while the music dock is present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useDock } from 'officerdev';
|
||||
import { useDock, MusicPlayerHost } from 'officerdev';
|
||||
import { Background } from './Background';
|
||||
import { Header } from './Header';
|
||||
import { Dock, ALL_DOCK_ITEMS, DEFAULT_DOCK_PATHS } from './Dock';
|
||||
@@ -23,6 +23,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
<MusicPlayerHost />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Link, useLocation } from 'react-router';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { useMusicPlayer, MUSIC_DOCK_HEIGHT } from 'officerdev';
|
||||
|
||||
export type DockItem = {
|
||||
label: string;
|
||||
@@ -34,6 +35,8 @@ export const Dock = ({ items, className }: DockProps) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const dockRef = useRef<HTMLDivElement | null>(null);
|
||||
const location = useLocation();
|
||||
const { current } = useMusicPlayer();
|
||||
const musicDockPresent = !!current;
|
||||
|
||||
const isActive = (to: string) => (to === '/' ? location.pathname === '/' : location.pathname.startsWith(to));
|
||||
|
||||
@@ -64,7 +67,10 @@ export const Dock = ({ items, className }: DockProps) => {
|
||||
backgroundColor: 'var(--dock-bg)',
|
||||
borderColor: 'var(--dock-border)',
|
||||
bottom: '16px',
|
||||
transform: `translateX(-50%) translateY(${visible ? '0' : 'calc(100% + 24px)'})`,
|
||||
// Slide up over the site-wide music dock when it's present so the nav dock clears it.
|
||||
transform: `translateX(-50%) translateY(${
|
||||
visible ? (musicDockPresent ? `-${MUSIC_DOCK_HEIGHT}px` : '0') : 'calc(100% + 24px)'
|
||||
})`,
|
||||
}}
|
||||
>
|
||||
{items.map((item, index) => {
|
||||
|
||||
Reference in New Issue
Block a user