mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 22:45:41 +00:00
feat(folder-browser): keyboard nav, context menus, now-playing path UX
Adds full keyboard navigation (arrow keys, Enter, Ctrl+Enter for context menu) across Folder Browser columns. Context menus for all row types with keyboard-operable submenus and star-rating control via arrow keys + Enter. Now-playing path is visually emphasized and stays stable; rebuilds on hotkey re-invoke or active-path follow-along. Adaptive column layout for deep trees with right-side visibility priority. New configurable 'Open Folder Browser' keybinding. StarRating animation sync for keyboard-driven changes. All 7 locales updated.
This commit is contained in:
@@ -34,6 +34,8 @@ export default function StarRating({
|
||||
const [clearShrinkStar, setClearShrinkStar] = React.useState<number | null>(null);
|
||||
/** After clear: ignore hover so stars stay grey until pointer leaves widget or next click */
|
||||
const [suppressHoverPreview, setSuppressHoverPreview] = React.useState(false);
|
||||
const prevValueRef = React.useRef(value);
|
||||
const internalClickRef = React.useRef(false);
|
||||
|
||||
const cappedValue = Math.min(Math.max(0, value), selectCap);
|
||||
|
||||
@@ -41,6 +43,38 @@ export default function StarRating({
|
||||
if (value > 0) setSuppressHoverPreview(false);
|
||||
}, [value]);
|
||||
|
||||
// Keep keyboard-driven changes visually in sync with mouse click effects.
|
||||
React.useEffect(() => {
|
||||
const prev = prevValueRef.current;
|
||||
const next = value;
|
||||
prevValueRef.current = value;
|
||||
|
||||
if (internalClickRef.current) {
|
||||
internalClickRef.current = false;
|
||||
return;
|
||||
}
|
||||
if (prev === next) return;
|
||||
|
||||
setPulseStar(null);
|
||||
setClearShrinkStar(null);
|
||||
|
||||
if (next > prev) {
|
||||
const star = Math.max(1, Math.min(selectCap, next));
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => setPulseStar(star));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (next < prev) {
|
||||
const star = Math.max(1, Math.min(selectCap, prev));
|
||||
if (next === 0) setSuppressHoverPreview(true);
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => setClearShrinkStar(star));
|
||||
});
|
||||
}
|
||||
}, [value, selectCap]);
|
||||
|
||||
const effectiveHover = suppressHoverPreview ? 0 : Math.min(hover, selectCap);
|
||||
const filled = (n: number) => (effectiveHover || cappedValue) >= n;
|
||||
|
||||
@@ -49,6 +83,7 @@ export default function StarRating({
|
||||
setSuppressHoverPreview(false);
|
||||
|
||||
const next = cappedValue === n ? 0 : n;
|
||||
internalClickRef.current = true;
|
||||
onChange(next);
|
||||
setHover(0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user