bug fixes

This commit is contained in:
kveld9
2026-04-15 15:26:56 -03:00
parent d248a78acc
commit 03b56afc92
3 changed files with 59 additions and 104 deletions
+3 -3
View File
@@ -36,9 +36,6 @@ export default function AdvancedSearch() {
const qFromUrl = params.get('q') ?? '';
const navigate = useNavigate();
const psyDrag = useDragDrop();
const total = results
? results.artists.length + results.albums.length + results.songs.length
: 0;
const { playTrack, openContextMenu } = usePlayerStore(
useShallow(s => ({
@@ -61,6 +58,9 @@ export default function AdvancedSearch() {
const [resultType, setResultType] = useState<ResultType>('all');
const [genres, setGenres] = useState<SubsonicGenre[]>([]);
const [results, setResults] = useState<Results | null>(null);
const total = results
? results.artists.length + results.albums.length + results.songs.length
: 0;
const [loading, setLoading] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
const [genreNote, setGenreNote] = useState(false);
+24 -20
View File
@@ -472,6 +472,30 @@ export default function Favorites() {
</div>
)}
{/* Column visibility picker */}
<div className="tracklist-col-picker-wrapper" ref={pickerRef}>
<div className="tracklist-col-picker">
<button className="tracklist-col-picker-btn" onClick={e => { e.stopPropagation(); setPickerOpen(v => !v); }} data-tooltip={t('albumDetail.columns')}>
<ChevronDown size={14} />
</button>
{pickerOpen && (
<div className="tracklist-col-picker-menu">
<div className="tracklist-col-picker-label">{t('albumDetail.columns')}</div>
{FAV_COLUMNS.filter(c => !c.required).map(c => {
const label = c.i18nKey ? t(`albumDetail.${c.i18nKey}`) : c.key;
const isOn = colVisible.has(c.key);
return (
<button key={c.key} className={`tracklist-col-picker-item${isOn ? ' active' : ''}`} onClick={() => toggleColumn(c.key)}>
<span className="tracklist-col-picker-check">{isOn && <Check size={13} />}</span>
{label}
</button>
);
})}
</div>
)}
</div>
</div>
<div style={{ position: 'relative' }}>
<div className="tracklist-header tracklist-va" style={gridStyle}>
{visibleCols.map((colDef, colIndex) => {
@@ -551,26 +575,6 @@ export default function Favorites() {
);
})}
</div>
<div className="tracklist-col-picker" ref={pickerRef}>
<button className="tracklist-col-picker-btn" onClick={e => { e.stopPropagation(); setPickerOpen(v => !v); }} data-tooltip={t('albumDetail.columns')}>
<ChevronDown size={14} />
</button>
{pickerOpen && (
<div className="tracklist-col-picker-menu">
<div className="tracklist-col-picker-label">{t('albumDetail.columns')}</div>
{FAV_COLUMNS.filter(c => !c.required).map(c => {
const label = c.i18nKey ? t(`albumDetail.${c.i18nKey}`) : c.key;
const isOn = colVisible.has(c.key);
return (
<button key={c.key} className={`tracklist-col-picker-item${isOn ? ' active' : ''}`} onClick={() => toggleColumn(c.key)}>
<span className="tracklist-col-picker-check">{isOn && <Check size={13} />}</span>
{label}
</button>
);
})}
</div>
)}
</div>
</div>
{visibleSongs.map((song, i) => {
const track = songToTrack(song);
+32 -81
View File
@@ -385,11 +385,6 @@ export default function PlaylistDetail() {
const [suggestions, setSuggestions] = useState<SubsonicSong[]>([]);
const [loadingSuggestions, setLoadingSuggestions] = useState(false);
// ── Column picker portal dropdown state ────────────────────────────────────
const [pickerPos, setPickerPos] = useState<{ top: number; right: number } | null>(null);
const pickerBtnRef = useRef<HTMLButtonElement>(null);
const pickerMenuRef = useRef<HTMLDivElement>(null);
// ── Column resize/visibility ──────────────────────────────────────────────
const {
colVisible, visibleCols, gridStyle,
@@ -404,41 +399,6 @@ export default function PlaylistDetail() {
if (!contextMenuOpen) setContextMenuSongId(null);
}, [contextMenuOpen]);
// Click-outside handler for column picker portal dropdown
useEffect(() => {
if (!pickerOpen) return;
const handler = (e: MouseEvent) => {
const target = e.target as Node;
if (
pickerBtnRef.current?.contains(target) ||
pickerRef.current?.contains(target) ||
pickerMenuRef.current?.contains(target)
) {
return;
}
setPickerOpen(false);
};
document.addEventListener('mousedown', handler);
return () => document.removeEventListener('mousedown', handler);
}, [pickerOpen, setPickerOpen]);
// Update picker position on resize/scroll while open
useEffect(() => {
if (!pickerOpen) return;
const updatePos = () => {
if (pickerBtnRef.current) {
const rect = pickerBtnRef.current.getBoundingClientRect();
setPickerPos({ top: rect.bottom + 4, right: window.innerWidth - rect.right });
}
};
window.addEventListener('resize', updatePos);
window.addEventListener('scroll', updatePos, true);
return () => {
window.removeEventListener('resize', updatePos);
window.removeEventListener('scroll', updatePos, true);
};
}, [pickerOpen]);
// ── Load ─────────────────────────────────────────────────────
const lastModified = usePlaylistStore(s => (id ? s.lastModified[id] : undefined));
@@ -1432,6 +1392,38 @@ export default function PlaylistDetail() {
</div>
)}
{/* Column visibility picker */}
<div className="tracklist-col-picker-wrapper" ref={pickerRef}>
<div className="tracklist-col-picker">
<button
className="tracklist-col-picker-btn"
onClick={e => { e.stopPropagation(); setPickerOpen(v => !v); }}
data-tooltip={t('albumDetail.columns')}
>
<ChevronDown size={14} />
</button>
{pickerOpen && (
<div className="tracklist-col-picker-menu">
<div className="tracklist-col-picker-label">{t('albumDetail.columns')}</div>
{PL_COLUMNS.filter(c => !c.required).map(c => {
const label = c.i18nKey ? t(`albumDetail.${c.i18nKey}`) : c.key;
const isOn = colVisible.has(c.key);
return (
<button
key={c.key}
className={`tracklist-col-picker-item${isOn ? ' active' : ''}`}
onClick={() => toggleColumn(c.key)}
>
<span className="tracklist-col-picker-check">{isOn && <Check size={13} />}</span>
{label}
</button>
);
})}
</div>
)}
</div>
</div>
{/* Header */}
<div style={{ position: 'relative' }}>
<div className="tracklist-header tracklist-va" style={gridStyle}>
@@ -1543,47 +1535,6 @@ export default function PlaylistDetail() {
);
})}
</div>
<div className="tracklist-col-picker" ref={pickerRef}>
<button
ref={pickerBtnRef}
className="tracklist-col-picker-btn"
onClick={e => {
e.stopPropagation();
if (!pickerOpen && pickerBtnRef.current) {
const rect = pickerBtnRef.current.getBoundingClientRect();
setPickerPos({ top: rect.bottom + 4, right: window.innerWidth - rect.right });
}
setPickerOpen(v => !v);
}}
data-tooltip={t('albumDetail.columns')}
>
<ChevronDown size={14} />
</button>
{pickerOpen && pickerPos && createPortal(
<div
ref={pickerMenuRef}
className="tracklist-col-picker-menu"
style={{ position: 'fixed', top: pickerPos.top, right: pickerPos.right, zIndex: 9999 }}
>
<div className="tracklist-col-picker-label">{t('albumDetail.columns')}</div>
{PL_COLUMNS.filter(c => !c.required).map(c => {
const label = c.i18nKey ? t(`albumDetail.${c.i18nKey}`) : c.key;
const isOn = colVisible.has(c.key);
return (
<button
key={c.key}
className={`tracklist-col-picker-item${isOn ? ' active' : ''}`}
onClick={() => toggleColumn(c.key)}
>
<span className="tracklist-col-picker-check">{isOn && <Check size={13} />}</span>
{label}
</button>
);
})}
</div>,
document.body
)}
</div>
</div>
{songs.length === 0 && (