mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 13:00:13 +02:00
allow user to unpin list sidebar
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Suspense } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { JellyfinAlbumFilters } from '/@/renderer/features/albums/components/jellyfin-album-filters';
|
||||
import { NavidromeAlbumFilters } from '/@/renderer/features/albums/components/navidrome-album-filters';
|
||||
import { SubsonicAlbumFilters } from '/@/renderer/features/albums/components/subsonic-album-filters';
|
||||
@@ -10,8 +11,11 @@ import { JellyfinSongFilters } from '/@/renderer/features/songs/components/jelly
|
||||
import { NavidromeSongFilters } from '/@/renderer/features/songs/components/navidrome-song-filters';
|
||||
import { SubsonicSongFilters } from '/@/renderer/features/songs/components/subsonic-song-filters';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Modal } from '/@/shared/components/modal/modal';
|
||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { useDisclosure } from '/@/shared/hooks/use-disclosure';
|
||||
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
|
||||
@@ -20,9 +24,18 @@ interface ListFiltersProps {
|
||||
itemType: LibraryItem;
|
||||
}
|
||||
|
||||
export const isFilterValueSet = (value: unknown): boolean => {
|
||||
if (value === undefined || value === null) return false;
|
||||
if (typeof value === 'string' && value.trim() === '') return false;
|
||||
if (Array.isArray(value) && value.length === 0) return false;
|
||||
if (typeof value === 'object' && Object.keys(value).length === 0) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
export const ListFiltersModal = ({ isActive, itemType }: ListFiltersProps) => {
|
||||
const { t } = useTranslation();
|
||||
const server = useCurrentServer();
|
||||
const { isSidebarOpen, setIsSidebarOpen } = useListContext();
|
||||
|
||||
const serverType = server.type;
|
||||
|
||||
@@ -30,13 +43,39 @@ export const ListFiltersModal = ({ isActive, itemType }: ListFiltersProps) => {
|
||||
|
||||
const [isOpen, handlers] = useDisclosure(false);
|
||||
|
||||
const handlePin = () => {
|
||||
setIsSidebarOpen?.(!isSidebarOpen);
|
||||
};
|
||||
|
||||
const canPin = Boolean(setIsSidebarOpen);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FilterButton isActive={isActive} onClick={handlers.toggle} />
|
||||
<Modal
|
||||
handlers={handlers}
|
||||
opened={isOpen}
|
||||
title={t('common.filters', { postProcess: 'sentenceCase' })}
|
||||
size="lg"
|
||||
styles={{
|
||||
content: {
|
||||
height: '100%',
|
||||
maxHeight: '640px',
|
||||
maxWidth: 'var(--theme-content-max-width)',
|
||||
width: '100%',
|
||||
},
|
||||
}}
|
||||
title={
|
||||
<Group>
|
||||
{canPin && (
|
||||
<ActionIcon
|
||||
icon={isSidebarOpen ? 'unpin' : 'pin'}
|
||||
onClick={handlePin}
|
||||
variant="subtle"
|
||||
/>
|
||||
)}
|
||||
{t('common.filters', { postProcess: 'sentenceCase' })}
|
||||
</Group>
|
||||
}
|
||||
>
|
||||
<FilterComponent />
|
||||
</Modal>
|
||||
@@ -58,6 +97,26 @@ export const ListFilters = ({ itemType }: ListFiltersProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ListFiltersTitle = () => {
|
||||
const { t } = useTranslation();
|
||||
const { setIsSidebarOpen } = useListContext();
|
||||
|
||||
const handleUnpin = () => {
|
||||
setIsSidebarOpen?.(false);
|
||||
};
|
||||
|
||||
const canUnpin = Boolean(setIsSidebarOpen);
|
||||
|
||||
return (
|
||||
<Group justify="space-between" p="md" pb={0}>
|
||||
<Text fw={500} size="xl">
|
||||
{t('common.filters', { postProcess: 'sentenceCase' })}
|
||||
</Text>
|
||||
{canUnpin && <ActionIcon icon="unpin" onClick={handleUnpin} variant="subtle" />}
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
const FILTERS = {
|
||||
[ServerType.JELLYFIN]: {
|
||||
[LibraryItem.ALBUM]: JellyfinAlbumFilters,
|
||||
|
||||
@@ -21,10 +21,16 @@
|
||||
border-right: 1px solid var(--theme-colors-border);
|
||||
}
|
||||
|
||||
@container (min-width: $mantine-breakpoint-lg) {
|
||||
.sidebar-container {
|
||||
@container (min-width: $mantine-breakpoint-xs) {
|
||||
.container[data-sidebar-open='true'] .sidebar-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@container (min-width: $mantine-breakpoint-lg) {
|
||||
.container[data-use-breakpoint='true'] .sidebar-container {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-container {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createContext, ReactNode, useContext, useMemo, useRef } from 'react';
|
||||
|
||||
import styles from './list-with-sidebar-container.module.css';
|
||||
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { animationProps } from '/@/shared/components/animations/animation-props';
|
||||
import { Portal } from '/@/shared/components/portal/portal';
|
||||
|
||||
@@ -17,6 +18,7 @@ const ListWithSidebarContainerContext = createContext<ListWithSidebarContainerCo
|
||||
interface ListWithSidebarContainerProps {
|
||||
children: ReactNode;
|
||||
sidebarBreakpoint?: number;
|
||||
useBreakpoint?: boolean;
|
||||
}
|
||||
|
||||
interface SidebarPortalProps {
|
||||
@@ -63,9 +65,10 @@ function SidebarPortal({ children }: SidebarPortalProps) {
|
||||
|
||||
export const ListWithSidebarContainer = ({
|
||||
children,
|
||||
sidebarBreakpoint = 1200,
|
||||
useBreakpoint = false,
|
||||
}: ListWithSidebarContainerProps) => {
|
||||
const sidebarRef = useRef<HTMLDivElement>(null);
|
||||
const { isSidebarOpen = false } = useListContext();
|
||||
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
@@ -76,7 +79,11 @@ export const ListWithSidebarContainer = ({
|
||||
|
||||
return (
|
||||
<ListWithSidebarContainerContext.Provider value={contextValue}>
|
||||
<div className={styles.container} data-sidebar-breakpoint={sidebarBreakpoint}>
|
||||
<div
|
||||
className={styles.container}
|
||||
data-sidebar-open={useBreakpoint ? undefined : isSidebarOpen}
|
||||
data-use-breakpoint={useBreakpoint}
|
||||
>
|
||||
<div className={styles.sidebarContainer} ref={sidebarRef} />
|
||||
<div className={styles.contentContainer}>{children}</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user