UI cleanup, visual and keyboard navigation
This commit is contained in:
@@ -28,11 +28,11 @@ import { usePlayerState } from "./hooks/usePlayerState";
|
||||
import { DEFAULT_MANUAL_CONTROL, DEFAULT_TUNABLES } from "./lib/ambienceTunables";
|
||||
import type { AmbienceTunables, ManualControl } from "./lib/ambienceTunables";
|
||||
import type { Action, UiState } from "./lib/keyboard";
|
||||
import { browseBackActions, handleKey, initialUiState, isRootShelf } from "./lib/keyboard";
|
||||
import { browseBackActions, GROUP_ORDER, handleKey, initialUiState, isRootShelf } from "./lib/keyboard";
|
||||
import { playPop } from "./lib/pop";
|
||||
import { targetForAlbum } from "./lib/remote";
|
||||
import type { Group, Results, SongHit } from "./lib/search";
|
||||
import { groupOf, results as computeResults } from "./lib/search";
|
||||
import { categoryMatches, groupOf, results as computeResults } from "./lib/search";
|
||||
|
||||
/** How long an armed "A" waits for the digit that completes the shortcut. */
|
||||
const ASSIGN_PENDING_TIMEOUT_MS = 4000;
|
||||
@@ -101,6 +101,23 @@ export function App() {
|
||||
[library.albums, ui.search, ui.mode, ui.group, ui.category],
|
||||
);
|
||||
|
||||
// The bare root's three shelves each compute their own categories independently
|
||||
// (see BrowseView) - the keyboard handler needs the same lists, by key only, to know
|
||||
// how far Ctrl+hjkl can move within a row and which category ENTER opens.
|
||||
const rootShelves = useMemo(
|
||||
() =>
|
||||
GROUP_ORDER.map((group) =>
|
||||
categoryMatches({
|
||||
albums: library.albums,
|
||||
search: "",
|
||||
mode: "albums",
|
||||
category: null,
|
||||
group,
|
||||
}).map((entry) => entry.key),
|
||||
),
|
||||
[library.albums],
|
||||
);
|
||||
|
||||
const byId = useMemo(
|
||||
() => new Map(library.albums.map((album) => [album.id, album])),
|
||||
[library.albums],
|
||||
@@ -249,8 +266,14 @@ export function App() {
|
||||
);
|
||||
|
||||
// Held in a ref so the listener is installed once rather than on every state change.
|
||||
const latest = useRef({ ui, results, run, openAlbumTrackCount: 0 });
|
||||
latest.current = { ui, results, run, openAlbumTrackCount: openAlbum?.tracks.length ?? 0 };
|
||||
const latest = useRef({ ui, results, run, openAlbumTrackCount: 0, rootShelves });
|
||||
latest.current = {
|
||||
ui,
|
||||
results,
|
||||
run,
|
||||
openAlbumTrackCount: openAlbum?.tracks.length ?? 0,
|
||||
rootShelves,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -259,7 +282,13 @@ export function App() {
|
||||
if (target && /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)) return;
|
||||
|
||||
const current = latest.current;
|
||||
const actions = handleKey(event, current.ui, current.results, current.openAlbumTrackCount);
|
||||
const actions = handleKey(
|
||||
event,
|
||||
current.ui,
|
||||
current.results,
|
||||
current.openAlbumTrackCount,
|
||||
current.rootShelves,
|
||||
);
|
||||
if (!actions.length) return;
|
||||
event.preventDefault();
|
||||
current.run(actions);
|
||||
@@ -378,6 +407,7 @@ export function App() {
|
||||
search={ui.search}
|
||||
category={ui.category}
|
||||
selIndex={ui.selIndex}
|
||||
shelfRow={ui.shelfRow}
|
||||
currentAlbumId={state.album_id}
|
||||
gridRef={gridRef}
|
||||
onEnterGroup={onEnterGroup}
|
||||
@@ -478,7 +508,7 @@ export function App() {
|
||||
<HelpOverlay onClose={() => setUi((previous) => ({ ...previous, showHelp: false }))} />
|
||||
)}
|
||||
|
||||
{ui.page === "music" && ui.view === "browse" && state && (
|
||||
{ui.page === "music" && ui.view === "browse" && state && currentAlbum && (
|
||||
<PlayerBar
|
||||
state={state}
|
||||
album={currentAlbum}
|
||||
|
||||
Reference in New Issue
Block a user