mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
5848c621fd
New page /folders with macOS Finder-style column layout: - getMusicDirectory / getMusicIndexes / getMusicFolders Subsonic API methods - Root level uses getIndexes.view (music folder IDs are not getMusicDirectory IDs) - Columns fill available width with flex: 1, min-width: 200px - Auto-scroll to rightmost column on expand - Cancelled-flag prevents stale state on fast navigation - Clicking a track plays it in the context of the current column's tracks - FolderOpen/Folder/Music icons, accent-colored selection, ellipsis truncation - Hidden in sidebar by default (user can enable in Settings) - i18n: EN DE FR NL NB ZH RU Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
|
|
export interface SidebarItemConfig {
|
|
id: string;
|
|
visible: boolean;
|
|
}
|
|
|
|
// All configurable nav items in their default order.
|
|
// Fixed items (nowPlaying, settings, offline) are not listed here.
|
|
export const DEFAULT_SIDEBAR_ITEMS: SidebarItemConfig[] = [
|
|
{ id: 'mainstage', visible: true },
|
|
{ id: 'newReleases', visible: true },
|
|
{ id: 'allAlbums', visible: true },
|
|
{ id: 'randomAlbums', visible: true },
|
|
{ id: 'artists', visible: true },
|
|
{ id: 'genres', visible: true },
|
|
{ id: 'randomMix', visible: true },
|
|
{ id: 'favorites', visible: true },
|
|
{ id: 'playlists', visible: true },
|
|
{ id: 'mostPlayed', visible: true },
|
|
{ id: 'radio', visible: true },
|
|
{ id: 'folderBrowser', visible: false },
|
|
{ id: 'statistics', visible: true },
|
|
{ id: 'help', visible: true },
|
|
];
|
|
|
|
interface SidebarStore {
|
|
items: SidebarItemConfig[];
|
|
setItems: (items: SidebarItemConfig[]) => void;
|
|
toggleItem: (id: string) => void;
|
|
reset: () => void;
|
|
}
|
|
|
|
export const useSidebarStore = create<SidebarStore>()(
|
|
persist(
|
|
(set) => ({
|
|
items: DEFAULT_SIDEBAR_ITEMS,
|
|
|
|
setItems: (items) => set({ items }),
|
|
|
|
toggleItem: (id) => set((s) => ({
|
|
items: s.items.map(item => item.id === id ? { ...item, visible: !item.visible } : item),
|
|
})),
|
|
|
|
reset: () => set({ items: DEFAULT_SIDEBAR_ITEMS }),
|
|
}),
|
|
{
|
|
name: 'psysonic_sidebar',
|
|
onRehydrateStorage: () => (state) => {
|
|
if (!state) return;
|
|
const known = new Set(state.items.map(i => i.id));
|
|
const missing = DEFAULT_SIDEBAR_ITEMS.filter(i => !known.has(i.id));
|
|
if (missing.length > 0) {
|
|
state.items = [...state.items, ...missing];
|
|
}
|
|
},
|
|
}
|
|
)
|
|
);
|