mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-06 20:10:12 +02:00
persist command palette collapsed sections to app store
This commit is contained in:
@@ -8,19 +8,30 @@ import { Paper } from '/@/shared/components/paper/paper';
|
||||
interface CollapsibleCommandGroupProps {
|
||||
children: ReactNode;
|
||||
defaultExpanded?: boolean;
|
||||
expanded?: boolean;
|
||||
heading: string;
|
||||
onToggle?: () => void;
|
||||
}
|
||||
|
||||
export function CollapsibleCommandGroup({
|
||||
children,
|
||||
defaultExpanded = true,
|
||||
expanded: controlledExpanded,
|
||||
heading,
|
||||
onToggle,
|
||||
}: CollapsibleCommandGroupProps) {
|
||||
const [expanded, setExpanded] = useState(defaultExpanded);
|
||||
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
|
||||
|
||||
const isControlled = controlledExpanded !== undefined && onToggle !== undefined;
|
||||
const expanded = isControlled ? controlledExpanded : internalExpanded;
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setExpanded((prev) => !prev);
|
||||
}, []);
|
||||
if (isControlled) {
|
||||
onToggle?.();
|
||||
} else {
|
||||
setInternalExpanded((prev) => !prev);
|
||||
}
|
||||
}, [isControlled, onToggle]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { HomeCommands } from '/@/renderer/features/search/components/home-comman
|
||||
import { LibraryCommandItem } from '/@/renderer/features/search/components/library-command-item';
|
||||
import { ServerCommands } from '/@/renderer/features/search/components/server-commands';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { useAppStore, useCurrentServer } from '/@/renderer/store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Breadcrumb } from '/@/shared/components/breadcrumb/breadcrumb';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
@@ -31,9 +31,21 @@ interface CommandPaletteProps {
|
||||
modalProps: (typeof useDisclosure)['arguments'];
|
||||
}
|
||||
|
||||
const SEARCH_SECTION_IDS = {
|
||||
albums: 'albums',
|
||||
artists: 'artists',
|
||||
tracks: 'tracks',
|
||||
} as const;
|
||||
|
||||
export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
||||
const navigate = useNavigate();
|
||||
const server = useCurrentServer();
|
||||
const searchSectionsExpanded = useAppStore(
|
||||
(state) => state.commandPaletteSearchSectionsExpanded,
|
||||
);
|
||||
const setSearchSectionExpanded = useAppStore(
|
||||
(state) => state.actions.setCommandPaletteSearchSectionExpanded,
|
||||
);
|
||||
const [value, setValue] = useState('');
|
||||
const [query, setQuery] = useState('');
|
||||
const [debouncedQuery] = useDebouncedValue(query, 400);
|
||||
@@ -148,7 +160,16 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
||||
{t('common.noResultsFromQuery', { postProcess: 'sentenceCase' })}
|
||||
</Command.Empty>
|
||||
{showAlbumGroup && (
|
||||
<CollapsibleCommandGroup heading="Albums">
|
||||
<CollapsibleCommandGroup
|
||||
expanded={searchSectionsExpanded[SEARCH_SECTION_IDS.albums] ?? true}
|
||||
heading="Albums"
|
||||
onToggle={() =>
|
||||
setSearchSectionExpanded(
|
||||
SEARCH_SECTION_IDS.albums,
|
||||
!(searchSectionsExpanded[SEARCH_SECTION_IDS.albums] ?? true),
|
||||
)
|
||||
}
|
||||
>
|
||||
{data?.albums?.map((album) => (
|
||||
<CommandItemSelectable
|
||||
key={`search-album-${album.id}`}
|
||||
@@ -182,7 +203,16 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
||||
</CollapsibleCommandGroup>
|
||||
)}
|
||||
{showArtistGroup && (
|
||||
<CollapsibleCommandGroup heading="Artists">
|
||||
<CollapsibleCommandGroup
|
||||
expanded={searchSectionsExpanded[SEARCH_SECTION_IDS.artists] ?? true}
|
||||
heading="Artists"
|
||||
onToggle={() =>
|
||||
setSearchSectionExpanded(
|
||||
SEARCH_SECTION_IDS.artists,
|
||||
!(searchSectionsExpanded[SEARCH_SECTION_IDS.artists] ?? true),
|
||||
)
|
||||
}
|
||||
>
|
||||
{data?.albumArtists.map((artist) => (
|
||||
<CommandItemSelectable
|
||||
key={`artist-${artist.id}`}
|
||||
@@ -221,7 +251,16 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
||||
</CollapsibleCommandGroup>
|
||||
)}
|
||||
{showTrackGroup && (
|
||||
<CollapsibleCommandGroup heading="Tracks">
|
||||
<CollapsibleCommandGroup
|
||||
expanded={searchSectionsExpanded[SEARCH_SECTION_IDS.tracks] ?? true}
|
||||
heading="Tracks"
|
||||
onToggle={() =>
|
||||
setSearchSectionExpanded(
|
||||
SEARCH_SECTION_IDS.tracks,
|
||||
!(searchSectionsExpanded[SEARCH_SECTION_IDS.tracks] ?? true),
|
||||
)
|
||||
}
|
||||
>
|
||||
{data?.songs.map((song) => (
|
||||
<CommandItemSelectable
|
||||
key={`artist-${song.id}`}
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface AppSlice extends AppState {
|
||||
setAppStore: (data: Partial<AppSlice>) => void;
|
||||
setArtistIdsMode: (mode: 'and' | 'or') => void;
|
||||
setArtistSelectMode: (mode: 'multi' | 'single') => void;
|
||||
setCommandPaletteSearchSectionExpanded: (sectionId: string, expanded: boolean) => void;
|
||||
setGenreIdsMode: (mode: 'and' | 'or') => void;
|
||||
setGenreSelectMode: (mode: 'multi' | 'single') => void;
|
||||
setGlobalExpanded: (value: GlobalExpandedState | null) => void;
|
||||
@@ -45,6 +46,7 @@ export interface AppState {
|
||||
artistIdsMode: 'and' | 'or';
|
||||
artistSelectMode: 'multi' | 'single';
|
||||
commandPalette: CommandPaletteProps;
|
||||
commandPaletteSearchSectionsExpanded: Record<string, boolean>;
|
||||
genreIdsMode: 'and' | 'or';
|
||||
genreSelectMode: 'multi' | 'single';
|
||||
globalExpanded: GlobalExpandedState | null;
|
||||
@@ -134,6 +136,11 @@ export const useAppStore = createWithEqualityFn<AppSlice>()(
|
||||
state.artistSelectMode = mode;
|
||||
});
|
||||
},
|
||||
setCommandPaletteSearchSectionExpanded: (sectionId, expanded) => {
|
||||
set((state) => {
|
||||
state.commandPaletteSearchSectionsExpanded[sectionId] = expanded;
|
||||
});
|
||||
},
|
||||
setGenreIdsMode: (mode) => {
|
||||
set((state) => {
|
||||
state.genreIdsMode = mode;
|
||||
@@ -206,6 +213,7 @@ export const useAppStore = createWithEqualityFn<AppSlice>()(
|
||||
});
|
||||
},
|
||||
},
|
||||
commandPaletteSearchSectionsExpanded: {},
|
||||
genreIdsMode: 'and',
|
||||
genreSelectMode: 'multi',
|
||||
globalExpanded: null,
|
||||
|
||||
Reference in New Issue
Block a user