put the music library location in the url

/music?path=<rel> replaces the music:cwd channel. Each panel reads the param
itself through useMusicCwd(), so MusicBrowser, MusicDetail and FavoritesView
no longer tell each other where they are, and every drill-in is a <Link>:
library rows, folder rows, album/artist cards, both "up" affordances, the
favorites rows, and the dock's now-playing tile. Track rows stay buttons —
they play, which is a mutation.

A query param rather than a nested route because the location is only one of
the things this screen holds (the lyrics split and the favorites view are the
others), and a splat has to be a route's last segment.

MusicPlayerHost is mounted outside <Routes> and used to write the channel and
then navigate('/music') to make the write visible — the audit's only
navigate-with-a-side-effect. That collapses to one <Link>.

music:resync (a refresh signal) and music:favorites (a view of one panel) stay
channels, deliberately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 12:08:04 +00:00
co-authored by Claude Opus 5
parent 374140d3a6
commit aef8619c6c
8 changed files with 164 additions and 122 deletions
@@ -4,7 +4,9 @@ import { useDashboardState } from 'state/useDashboardState';
import { defaultLayout } from './defaultLayout';
// /music uses the Workspace/Panel system (like /chat): two vertical panels — the library browser
// (music-browser) and the content/detail (music-detail) — coordinating via the 'music:cwd' channel.
// (music-browser) and the content/detail (music-detail). They do not coordinate with each other; both
// read `?path=` off the URL. No route pair and no guard: the bare /music is the library root, a real
// state, and an unknown path gets an empty listing rather than a rewritten address.
export const MusicScreen = () => {
const workspace = useDashboardState<LayoutNode>('screens/music', defaultLayout);