mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
remove ag-grid
This commit is contained in:
@@ -60,11 +60,6 @@
|
|||||||
"postversion": "node ./scripts/update-app-stream.mjs"
|
"postversion": "node ./scripts/update-app-stream.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ag-grid-community/client-side-row-model": "^28.2.1",
|
|
||||||
"@ag-grid-community/core": "^28.2.1",
|
|
||||||
"@ag-grid-community/infinite-row-model": "^28.2.1",
|
|
||||||
"@ag-grid-community/react": "^28.2.1",
|
|
||||||
"@ag-grid-community/styles": "^28.2.1",
|
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "1.7.7",
|
"@atlaskit/pragmatic-drag-and-drop": "1.7.7",
|
||||||
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.2",
|
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.2",
|
||||||
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
||||||
|
|||||||
Generated
-53
@@ -8,21 +8,6 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ag-grid-community/client-side-row-model':
|
|
||||||
specifier: ^28.2.1
|
|
||||||
version: 28.2.1
|
|
||||||
'@ag-grid-community/core':
|
|
||||||
specifier: ^28.2.1
|
|
||||||
version: 28.2.1
|
|
||||||
'@ag-grid-community/infinite-row-model':
|
|
||||||
specifier: ^28.2.1
|
|
||||||
version: 28.2.1
|
|
||||||
'@ag-grid-community/react':
|
|
||||||
specifier: ^28.2.1
|
|
||||||
version: 28.2.1(@ag-grid-community/core@28.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
|
||||||
'@ag-grid-community/styles':
|
|
||||||
specifier: ^28.2.1
|
|
||||||
version: 28.2.1
|
|
||||||
'@atlaskit/pragmatic-drag-and-drop':
|
'@atlaskit/pragmatic-drag-and-drop':
|
||||||
specifier: 1.7.7
|
specifier: 1.7.7
|
||||||
version: 1.7.7
|
version: 1.7.7
|
||||||
@@ -369,25 +354,6 @@ packages:
|
|||||||
7zip-bin@5.2.0:
|
7zip-bin@5.2.0:
|
||||||
resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==}
|
resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==}
|
||||||
|
|
||||||
'@ag-grid-community/client-side-row-model@28.2.1':
|
|
||||||
resolution: {integrity: sha512-JLLNVNAtSbVjg/h0+JqNxbRGzHR9xl3YHO4kVt8Bu0UO1XQLfGLT8wkzqQTcEOiq0pEfFTee7/BGT3oHOQfUQg==}
|
|
||||||
|
|
||||||
'@ag-grid-community/core@28.2.1':
|
|
||||||
resolution: {integrity: sha512-qGhqZhY8KbPlr3cJBVkNjGKu+cOyFc8IGvPcvlm0pjNC9cdxO/ct9Sa1Dg+k3ACCEroMEt1apBvnoOgurpvewQ==}
|
|
||||||
|
|
||||||
'@ag-grid-community/infinite-row-model@28.2.1':
|
|
||||||
resolution: {integrity: sha512-jvEvVNQ/USlQjGW0LbryR4/I1ZSgOBPn4tg45KWm3+R0jmDSfetI20D5t3UaSQHY6ZQMDVYxR3xSkorPFI3Vng==}
|
|
||||||
|
|
||||||
'@ag-grid-community/react@28.2.1':
|
|
||||||
resolution: {integrity: sha512-VWtiBMhvDKp//lIa2Ovzv+/gcQj6wnZDhngyPW5e97Sl+sIs6/UngHSTbbmhIb+wWUCIKmSRL1+R05PNnKjFTA==}
|
|
||||||
peerDependencies:
|
|
||||||
'@ag-grid-community/core': ~28.2.1
|
|
||||||
react: ^16.3.0 || ^17.0.0 || ^18.0.0
|
|
||||||
react-dom: ^16.3.0 || ^17.0.0 || ^18.0.0
|
|
||||||
|
|
||||||
'@ag-grid-community/styles@28.2.1':
|
|
||||||
resolution: {integrity: sha512-dy3Z46zTnzrwJOnH+tFvIvY9g/8qIi+b7XmbQlmATBr9zcNMk0wqWH1/9sNHs1fFW6m3Csvu4ctyzdr9mSw1YA==}
|
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
'@ampproject/remapping@2.3.0':
|
||||||
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@@ -6088,25 +6054,6 @@ snapshots:
|
|||||||
|
|
||||||
7zip-bin@5.2.0: {}
|
7zip-bin@5.2.0: {}
|
||||||
|
|
||||||
'@ag-grid-community/client-side-row-model@28.2.1':
|
|
||||||
dependencies:
|
|
||||||
'@ag-grid-community/core': 28.2.1
|
|
||||||
|
|
||||||
'@ag-grid-community/core@28.2.1': {}
|
|
||||||
|
|
||||||
'@ag-grid-community/infinite-row-model@28.2.1':
|
|
||||||
dependencies:
|
|
||||||
'@ag-grid-community/core': 28.2.1
|
|
||||||
|
|
||||||
'@ag-grid-community/react@28.2.1(@ag-grid-community/core@28.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
|
||||||
dependencies:
|
|
||||||
'@ag-grid-community/core': 28.2.1
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 19.1.0
|
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
|
||||||
|
|
||||||
'@ag-grid-community/styles@28.2.1': {}
|
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
'@ampproject/remapping@2.3.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/gen-mapping': 0.3.12
|
'@jridgewell/gen-mapping': 0.3.12
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
|
|
||||||
import { ModuleRegistry } from '@ag-grid-community/core';
|
|
||||||
import { InfiniteRowModelModule } from '@ag-grid-community/infinite-row-model';
|
|
||||||
import { MantineProvider } from '@mantine/core';
|
import { MantineProvider } from '@mantine/core';
|
||||||
import '@mantine/core/styles.css';
|
import '@mantine/core/styles.css';
|
||||||
import '@mantine/dates/styles.css';
|
import '@mantine/dates/styles.css';
|
||||||
@@ -11,7 +8,6 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||||||
|
|
||||||
import '/@/shared/styles/global.css';
|
import '/@/shared/styles/global.css';
|
||||||
|
|
||||||
import '@ag-grid-community/styles/ag-grid.css';
|
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
|
|
||||||
import i18n from '/@/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
@@ -27,8 +23,6 @@ import { sanitizeCss } from '/@/renderer/utils/sanitize';
|
|||||||
import { WebAudio } from '/@/shared/types/types';
|
import { WebAudio } from '/@/shared/types/types';
|
||||||
import '/styles/overlayscrollbars.css';
|
import '/styles/overlayscrollbars.css';
|
||||||
|
|
||||||
ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]);
|
|
||||||
|
|
||||||
const ipc = isElectron() ? window.api.ipc : null;
|
const ipc = isElectron() ? window.api.ipc : null;
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { forwardRef, Ref, useCallback, useMemo } from 'react';
|
import { forwardRef, Ref, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { generatePath, useParams } from 'react-router';
|
import { generatePath, Link, useParams } from 'react-router';
|
||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
|
||||||
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
|
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
|
||||||
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
||||||
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
||||||
import { useContainerQuery } from '/@/renderer/hooks';
|
import { useContainerQuery } from '/@/renderer/hooks';
|
||||||
import { useSongChange } from '/@/renderer/hooks/use-song-change';
|
|
||||||
import { queryClient } from '/@/renderer/lib/react-query';
|
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils';
|
import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils';
|
||||||
@@ -20,7 +16,7 @@ import { Pill } from '/@/shared/components/pill/pill';
|
|||||||
import { Rating } from '/@/shared/components/rating/rating';
|
import { Rating } from '/@/shared/components/rating/rating';
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { AlbumDetailResponse, LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
interface AlbumDetailHeaderProps {
|
interface AlbumDetailHeaderProps {
|
||||||
background: {
|
background: {
|
||||||
@@ -52,36 +48,6 @@ export const AlbumDetailHeader = forwardRef(
|
|||||||
? t('page.albumDetail.released', { postProcess: 'sentenceCase' })
|
? t('page.albumDetail.released', { postProcess: 'sentenceCase' })
|
||||||
: '♫';
|
: '♫';
|
||||||
|
|
||||||
const songIds = useMemo(() => {
|
|
||||||
return new Set(detailQuery.data?.songs?.map((song) => song.id));
|
|
||||||
}, [detailQuery.data?.songs]);
|
|
||||||
|
|
||||||
const handleSongChange = useCallback(
|
|
||||||
(id: string) => {
|
|
||||||
if (songIds.has(id)) {
|
|
||||||
const queryKey = queryKeys.albums.detail(server?.id, { id: albumId });
|
|
||||||
queryClient.setQueryData<AlbumDetailResponse | undefined>(
|
|
||||||
queryKey,
|
|
||||||
(previous) => {
|
|
||||||
if (!previous) return undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...previous,
|
|
||||||
playCount: previous.playCount ? previous.playCount + 1 : 1,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[albumId, server?.id, songIds],
|
|
||||||
);
|
|
||||||
|
|
||||||
useSongChange((ids, event) => {
|
|
||||||
if (event.event === 'play') {
|
|
||||||
handleSongChange(ids[0]);
|
|
||||||
}
|
|
||||||
}, detailQuery.data !== undefined);
|
|
||||||
|
|
||||||
const releaseTypes = useMemo(
|
const releaseTypes = useMemo(
|
||||||
() =>
|
() =>
|
||||||
normalizeReleaseTypes(detailQuery.data?.releaseTypes ?? [], t).map((type) => ({
|
normalizeReleaseTypes(detailQuery.data?.releaseTypes ?? [], t).map((type) => ({
|
||||||
@@ -139,8 +105,9 @@ export const AlbumDetailHeader = forwardRef(
|
|||||||
updateRatingMutation.mutate({
|
updateRatingMutation.mutate({
|
||||||
apiClientProps: { serverId: detailQuery.data._serverId },
|
apiClientProps: { serverId: detailQuery.data._serverId },
|
||||||
query: {
|
query: {
|
||||||
item: [detailQuery.data],
|
id: [detailQuery.data.id],
|
||||||
rating,
|
rating,
|
||||||
|
type: LibraryItem.ALBUM,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
@@ -17,7 +15,6 @@ import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
|||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
const AlbumDetailRoute = () => {
|
const AlbumDetailRoute = () => {
|
||||||
const tableRef = useRef<AgGridReactType | null>(null);
|
|
||||||
const scrollAreaRef = useRef<HTMLDivElement>(null);
|
const scrollAreaRef = useRef<HTMLDivElement>(null);
|
||||||
const headerRef = useRef<HTMLDivElement>(null);
|
const headerRef = useRef<HTMLDivElement>(null);
|
||||||
const { albumBackground, albumBackgroundBlur } = useGeneralSettings();
|
const { albumBackground, albumBackgroundBlur } = useGeneralSettings();
|
||||||
@@ -74,7 +71,7 @@ const AlbumDetailRoute = () => {
|
|||||||
}}
|
}}
|
||||||
ref={headerRef}
|
ref={headerRef}
|
||||||
/>
|
/>
|
||||||
<AlbumDetailContent background={background} tableRef={tableRef} />
|
<AlbumDetailContent background={background} />
|
||||||
</NativeScrollArea>
|
</NativeScrollArea>
|
||||||
</AnimatedPage>
|
</AnimatedPage>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { RowDoubleClickedEvent } from '@ag-grid-community/core';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Suspense, useMemo } from 'react';
|
import { Suspense, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -32,7 +31,6 @@ import {
|
|||||||
AlbumArtist,
|
AlbumArtist,
|
||||||
AlbumListSort,
|
AlbumListSort,
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
QueueSong,
|
|
||||||
ServerType,
|
ServerType,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
@@ -194,10 +192,6 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRowDoubleClick = (e: RowDoubleClickedEvent<QueueSong>) => {
|
|
||||||
if (!e.data || !topSongsQuery?.data) return;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createFavoriteMutation = useCreateFavorite({});
|
const createFavoriteMutation = useCreateFavorite({});
|
||||||
const deleteFavoriteMutation = useDeleteFavorite({});
|
const deleteFavoriteMutation = useDeleteFavorite({});
|
||||||
|
|
||||||
@@ -268,7 +262,6 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||||||
icon="ellipsisHorizontal"
|
icon="ellipsisHorizontal"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (!detailQuery?.data) return;
|
if (!detailQuery?.data) return;
|
||||||
// handleGeneralContextMenu(e, [detailQuery.data!]);
|
|
||||||
}}
|
}}
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
|
||||||
|
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||||
import { ListContext } from '/@/renderer/context/list-context';
|
import { ListContext } from '/@/renderer/context/list-context';
|
||||||
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
|
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
|
||||||
import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header';
|
import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header';
|
||||||
@@ -12,7 +11,7 @@ import { useCurrentServer } from '/@/renderer/store/auth.store';
|
|||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
const AlbumArtistDetailTopSongsListRoute = () => {
|
const AlbumArtistDetailTopSongsListRoute = () => {
|
||||||
const tableRef = useRef<AgGridReactType | null>(null);
|
const tableRef = useRef<ItemListHandle | null>(null);
|
||||||
const { albumArtistId, artistId } = useParams() as {
|
const { albumArtistId, artistId } = useParams() as {
|
||||||
albumArtistId?: string;
|
albumArtistId?: string;
|
||||||
artistId?: string;
|
artistId?: string;
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||||
import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
|
import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
|
||||||
import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
|
import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
|
||||||
import { Flex } from '/@/shared/components/flex/flex';
|
import { Flex } from '/@/shared/components/flex/flex';
|
||||||
import { Song } from '/@/shared/types/domain-types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
export const DrawerPlayQueue = () => {
|
export const DrawerPlayQueue = () => {
|
||||||
const queueRef = useRef<null | { grid: AgGridReactType<Song> }>(null);
|
const queueRef = useRef<ItemListHandle | null>(null);
|
||||||
const [search, setSearch] = useState<string | undefined>(undefined);
|
const [search, setSearch] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -23,11 +22,11 @@ export const DrawerPlayQueue = () => {
|
|||||||
handleSearch={setSearch}
|
handleSearch={setSearch}
|
||||||
searchTerm={search}
|
searchTerm={search}
|
||||||
tableRef={queueRef}
|
tableRef={queueRef}
|
||||||
type="sideQueue"
|
type={ItemListKey.SIDE_QUEUE}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Flex bg="var(--theme-colors-background)" h="100%" mb="0.6rem">
|
<Flex bg="var(--theme-colors-background)" h="100%" mb="0.6rem">
|
||||||
<PlayQueue ref={queueRef} searchTerm={search} listKey="sideQueue" />
|
<PlayQueue listKey={ItemListKey.SIDE_QUEUE} ref={queueRef} searchTerm={search} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { MutableRefObject } from 'react';
|
import { MutableRefObject } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
|
||||||
|
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||||
import { PageHeader } from '/@/renderer/components/page-header/page-header';
|
import { PageHeader } from '/@/renderer/components/page-header/page-header';
|
||||||
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
||||||
import { PlaylistDetailSongListHeaderFilters } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header-filters';
|
import { PlaylistDetailSongListHeaderFilters } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header-filters';
|
||||||
@@ -20,10 +19,9 @@ import { Play } from '/@/shared/types/types';
|
|||||||
|
|
||||||
interface PlaylistDetailHeaderProps {
|
interface PlaylistDetailHeaderProps {
|
||||||
handlePlay: (playType: Play) => void;
|
handlePlay: (playType: Play) => void;
|
||||||
|
|
||||||
handleToggleShowQueryBuilder: () => void;
|
handleToggleShowQueryBuilder: () => void;
|
||||||
itemCount?: number;
|
itemCount?: number;
|
||||||
tableRef: MutableRefObject<AgGridReactType | null>;
|
tableRef: MutableRefObject<ItemListHandle | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PlaylistDetailSongListHeader = ({
|
export const PlaylistDetailSongListHeader = ({
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { closeAllModals, openModal } from '@mantine/modals';
|
import { closeAllModals, openModal } from '@mantine/modals';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
@@ -7,6 +5,7 @@ import { useMemo, useRef, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { generatePath, useNavigate, useParams } from 'react-router';
|
import { generatePath, useNavigate, useParams } from 'react-router';
|
||||||
|
|
||||||
|
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||||
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
||||||
import { PlaylistDetailSongListHeader } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header';
|
import { PlaylistDetailSongListHeader } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header';
|
||||||
import { PlaylistQueryBuilder } from '/@/renderer/features/playlists/components/playlist-query-builder';
|
import { PlaylistQueryBuilder } from '/@/renderer/features/playlists/components/playlist-query-builder';
|
||||||
@@ -16,7 +15,6 @@ import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/dele
|
|||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store';
|
import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store';
|
||||||
import { searchSongs } from '/@/renderer/utils/search-songs';
|
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { Box } from '/@/shared/components/box/box';
|
import { Box } from '/@/shared/components/box/box';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
@@ -28,7 +26,7 @@ import { Play } from '/@/shared/types/types';
|
|||||||
const PlaylistDetailSongListRoute = () => {
|
const PlaylistDetailSongListRoute = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const tableRef = useRef<AgGridReactType | null>(null);
|
const tableRef = useRef<ItemListHandle | null>(null);
|
||||||
const { playlistId } = useParams() as { playlistId: string };
|
const { playlistId } = useParams() as { playlistId: string };
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { RowDoubleClickedEvent } from '@ag-grid-community/core';
|
|
||||||
import { AgGridReact } from '@ag-grid-community/react';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
|
|
||||||
|
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||||
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
|
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
|
||||||
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
@@ -16,7 +15,7 @@ export type SimilarSongsListProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListProps) => {
|
export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListProps) => {
|
||||||
const tableRef = useRef<AgGridReact<Song> | null>(null);
|
const tableRef = useRef<ItemListHandle | null>(null);
|
||||||
// const tableConfig = useTableSettings(fullScreen ? 'fullScreen' : 'songs');
|
// const tableConfig = useTableSettings(fullScreen ? 'fullScreen' : 'songs');
|
||||||
|
|
||||||
const songQuery = useQuery(
|
const songQuery = useQuery(
|
||||||
@@ -40,16 +39,6 @@ export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListPr
|
|||||||
|
|
||||||
// const onCellContextMenu = useHandleTableContextMenu(LibraryItem.SONG, SONG_CONTEXT_MENU_ITEMS);
|
// const onCellContextMenu = useHandleTableContextMenu(LibraryItem.SONG, SONG_CONTEXT_MENU_ITEMS);
|
||||||
|
|
||||||
const handleRowDoubleClick = (e: RowDoubleClickedEvent<Song>) => {
|
|
||||||
if (!e.data || !songQuery.data) return;
|
|
||||||
|
|
||||||
// handlePlayQueueAdd?.({
|
|
||||||
// byData: songQuery.data,
|
|
||||||
// initialSongId: e.data.id,
|
|
||||||
// playType: playButtonBehavior,
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
return songQuery.isLoading ? (
|
return songQuery.isLoading ? (
|
||||||
<Spinner container size={25} />
|
<Spinner container size={25} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { ChangeEvent, MutableRefObject, useCallback } from 'react';
|
|
||||||
|
|
||||||
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
|
|
||||||
import { useListContext } from '/@/renderer/context/list-context';
|
|
||||||
import {
|
|
||||||
UseHandleListFilterChangeProps,
|
|
||||||
useListFilterRefresh,
|
|
||||||
} from '/@/renderer/hooks/use-list-filter-refresh';
|
|
||||||
import { useListStoreActions, useListStoreByKey } from '/@/renderer/store';
|
|
||||||
import { ListDisplayType } from '/@/shared/types/types';
|
|
||||||
|
|
||||||
export type UseDisplayRefreshProps = UseHandleListFilterChangeProps & {
|
|
||||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
|
||||||
itemCount?: number;
|
|
||||||
tableRef: MutableRefObject<AgGridReactType | null>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useDisplayRefresh = <TFilter>({
|
|
||||||
gridRef,
|
|
||||||
isClientSideSort,
|
|
||||||
itemCount,
|
|
||||||
itemType,
|
|
||||||
server,
|
|
||||||
tableRef,
|
|
||||||
}: UseDisplayRefreshProps) => {
|
|
||||||
const { customFilters, handlePlay, pageKey } = useListContext();
|
|
||||||
const { display, filter } = useListStoreByKey<TFilter>({ key: pageKey });
|
|
||||||
|
|
||||||
const { handleRefreshGrid, handleRefreshTable } = useListFilterRefresh({
|
|
||||||
isClientSideSort,
|
|
||||||
itemCount,
|
|
||||||
itemType,
|
|
||||||
server,
|
|
||||||
});
|
|
||||||
const { setFilter, setTablePagination } = useListStoreActions();
|
|
||||||
|
|
||||||
const refresh = useCallback(
|
|
||||||
(filter: unknown) => {
|
|
||||||
if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) {
|
|
||||||
handleRefreshTable(tableRef, filter);
|
|
||||||
setTablePagination({ data: { currentPage: 0 }, key: pageKey });
|
|
||||||
} else {
|
|
||||||
handleRefreshGrid(gridRef, filter);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
display,
|
|
||||||
gridRef,
|
|
||||||
handleRefreshGrid,
|
|
||||||
handleRefreshTable,
|
|
||||||
pageKey,
|
|
||||||
setTablePagination,
|
|
||||||
tableRef,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
const search = useCallback(
|
|
||||||
(e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const searchTerm = e.target.value === '' ? undefined : e.target.value;
|
|
||||||
const updatedFilters = setFilter({
|
|
||||||
customFilters,
|
|
||||||
data: { searchTerm },
|
|
||||||
itemType,
|
|
||||||
key: pageKey,
|
|
||||||
});
|
|
||||||
return updatedFilters;
|
|
||||||
},
|
|
||||||
[customFilters, itemType, pageKey, setFilter],
|
|
||||||
);
|
|
||||||
|
|
||||||
return { customFilters, filter, handlePlay, refresh, search };
|
|
||||||
};
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
|
||||||
|
|
||||||
import { IDatasource } from '@ag-grid-community/core';
|
|
||||||
import { QueryKey, useQueryClient } from '@tanstack/react-query';
|
|
||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import { MutableRefObject, useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
|
||||||
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
|
|
||||||
import { BasePaginatedResponse, LibraryItem, ServerListItem } from '/@/shared/types/domain-types';
|
|
||||||
|
|
||||||
export interface UseHandleListFilterChangeProps {
|
|
||||||
isClientSideSort?: boolean;
|
|
||||||
itemCount?: number;
|
|
||||||
itemType: LibraryItem;
|
|
||||||
server: null | ServerListItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLOCK_SIZE = 500;
|
|
||||||
|
|
||||||
export const useListFilterRefresh = ({
|
|
||||||
isClientSideSort,
|
|
||||||
itemCount,
|
|
||||||
itemType,
|
|
||||||
server,
|
|
||||||
}: UseHandleListFilterChangeProps) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const queryKeyFn: ((serverId: string, query: Record<any, any>) => QueryKey) | null =
|
|
||||||
useMemo(() => {
|
|
||||||
switch (itemType) {
|
|
||||||
case LibraryItem.ALBUM:
|
|
||||||
return queryKeys.albums.list;
|
|
||||||
case LibraryItem.ALBUM_ARTIST:
|
|
||||||
return queryKeys.albumArtists.list;
|
|
||||||
case LibraryItem.ARTIST:
|
|
||||||
return queryKeys.artists.list;
|
|
||||||
case LibraryItem.GENRE:
|
|
||||||
return queryKeys.genres.list;
|
|
||||||
case LibraryItem.PLAYLIST:
|
|
||||||
return queryKeys.playlists.list;
|
|
||||||
case LibraryItem.SONG:
|
|
||||||
return queryKeys.songs.list;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, [itemType]);
|
|
||||||
|
|
||||||
const queryFn: ((args: any) => Promise<BasePaginatedResponse<any> | null | undefined>) | null =
|
|
||||||
useMemo(() => {
|
|
||||||
switch (itemType) {
|
|
||||||
case LibraryItem.ALBUM:
|
|
||||||
return api.controller.getAlbumList;
|
|
||||||
case LibraryItem.ALBUM_ARTIST:
|
|
||||||
return api.controller.getAlbumArtistList;
|
|
||||||
case LibraryItem.ARTIST:
|
|
||||||
return api.controller.getArtistList;
|
|
||||||
case LibraryItem.GENRE:
|
|
||||||
return api.controller.getGenreList;
|
|
||||||
case LibraryItem.PLAYLIST:
|
|
||||||
return api.controller.getPlaylistList;
|
|
||||||
case LibraryItem.SONG:
|
|
||||||
return api.controller.getSongList;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, [itemType]);
|
|
||||||
|
|
||||||
const handleRefreshTable = useCallback(
|
|
||||||
async (tableRef: MutableRefObject<AgGridReactType | null>, filter: any) => {
|
|
||||||
if (!tableRef || !queryKeyFn || !queryFn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataSource: IDatasource = {
|
|
||||||
getRows: async (params) => {
|
|
||||||
const limit = params.endRow - params.startRow;
|
|
||||||
const startIndex = params.startRow;
|
|
||||||
|
|
||||||
const query = { ...filter, limit, startIndex };
|
|
||||||
|
|
||||||
const queryKey = queryKeyFn(server?.id || '', query);
|
|
||||||
|
|
||||||
const results = await queryClient.fetchQuery({
|
|
||||||
queryFn: async ({ signal }) => {
|
|
||||||
return queryFn({
|
|
||||||
apiClientProps: {
|
|
||||||
serverId: server?.id || '',
|
|
||||||
signal,
|
|
||||||
},
|
|
||||||
query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
queryKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isClientSideSort && results?.items) {
|
|
||||||
const sortedResults = orderBy(
|
|
||||||
results.items,
|
|
||||||
[(item) => String(item[filter.sortBy]).toLowerCase()],
|
|
||||||
filter.sortOrder === 'DESC' ? ['desc'] : ['asc'],
|
|
||||||
);
|
|
||||||
|
|
||||||
params.successCallback(
|
|
||||||
sortedResults || [],
|
|
||||||
results?.totalRecordCount || itemCount,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results?.totalRecordCount === null) {
|
|
||||||
const hasMoreRows = results?.items?.length === BLOCK_SIZE;
|
|
||||||
const lastRowIndex = hasMoreRows
|
|
||||||
? undefined
|
|
||||||
: (filter.offset || 0) + results.items.length;
|
|
||||||
|
|
||||||
params.successCallback(
|
|
||||||
results?.items || [],
|
|
||||||
hasMoreRows ? undefined : lastRowIndex,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
params.successCallback(results?.items || [], results?.totalRecordCount || 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
rowCount: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
tableRef.current?.api.setDatasource(dataSource);
|
|
||||||
tableRef.current?.api.purgeInfiniteCache();
|
|
||||||
tableRef.current?.api.ensureIndexVisible(0, 'top');
|
|
||||||
},
|
|
||||||
[isClientSideSort, itemCount, queryClient, queryFn, queryKeyFn, server],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleRefreshGrid = useCallback(
|
|
||||||
async (gridRef: MutableRefObject<null | VirtualInfiniteGridRef>, filter: any) => {
|
|
||||||
if (!gridRef || !queryKeyFn || !queryFn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gridRef.current?.scrollTo(0);
|
|
||||||
gridRef.current?.resetLoadMoreItemsCache();
|
|
||||||
|
|
||||||
const query = { ...filter, limit: 200, startIndex: 0 };
|
|
||||||
|
|
||||||
const queryKey = queryKeyFn(server?.id || '', query);
|
|
||||||
|
|
||||||
const res = await queryClient.fetchQuery({
|
|
||||||
queryFn: async ({ signal }) => {
|
|
||||||
return queryFn({
|
|
||||||
apiClientProps: {
|
|
||||||
serverId: server?.id || '',
|
|
||||||
signal,
|
|
||||||
},
|
|
||||||
query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
queryKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res?.items) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gridRef.current?.setItemData(res.items);
|
|
||||||
},
|
|
||||||
[queryClient, queryFn, queryKeyFn, server],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleRefreshGrid,
|
|
||||||
handleRefreshTable,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import { RowNode } from '@ag-grid-community/core';
|
|
||||||
import { AgGridReact } from '@ag-grid-community/react';
|
|
||||||
import { MutableRefObject, useCallback, useEffect } from 'react';
|
|
||||||
|
|
||||||
import { useEventStore, UserEvent } from '/@/renderer/store/event.store';
|
|
||||||
import { Song } from '/@/shared/types/domain-types';
|
|
||||||
|
|
||||||
export const useSongChange = (
|
|
||||||
handler: (ids: string[], event: UserEvent) => void,
|
|
||||||
enabled: boolean,
|
|
||||||
) => {
|
|
||||||
useEffect(() => {
|
|
||||||
if (!enabled) return () => {};
|
|
||||||
|
|
||||||
const unSub = useEventStore.subscribe((state) => {
|
|
||||||
if (state.event) {
|
|
||||||
handler(state.ids, state.event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unSub();
|
|
||||||
};
|
|
||||||
}, [handler, enabled]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useTableChange = (
|
|
||||||
tableRef: MutableRefObject<AgGridReact | null>,
|
|
||||||
enabled: boolean,
|
|
||||||
) => {
|
|
||||||
const handler = useCallback(
|
|
||||||
(ids: string[], event: UserEvent) => {
|
|
||||||
const api = tableRef.current?.api;
|
|
||||||
if (!api) return;
|
|
||||||
|
|
||||||
const idSet = new Set(ids);
|
|
||||||
|
|
||||||
api.forEachNode((node: RowNode<Song>) => {
|
|
||||||
if (!node.data || !idSet.has(node.data.id)) return;
|
|
||||||
|
|
||||||
// Make sure to use setData instead of setDataValue. setDataValue
|
|
||||||
// will error if the column does not exist, whereas setData won't care
|
|
||||||
switch (event.event) {
|
|
||||||
case 'favorite': {
|
|
||||||
if (node.data.userFavorite !== event.favorite) {
|
|
||||||
node.setData({ ...node.data, userFavorite: event.favorite });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'play':
|
|
||||||
if (node.data.lastPlayedAt !== event.timestamp) {
|
|
||||||
node.setData({
|
|
||||||
...node.data,
|
|
||||||
lastPlayedAt: event.timestamp,
|
|
||||||
playCount: node.data.playCount + 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
node.data.lastPlayedAt = event.timestamp;
|
|
||||||
break;
|
|
||||||
case 'rating': {
|
|
||||||
if (node.data.userRating !== event.rating) {
|
|
||||||
node.setData({ ...node.data, userRating: event.rating });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[tableRef],
|
|
||||||
);
|
|
||||||
|
|
||||||
useSongChange(handler, enabled);
|
|
||||||
};
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
@import url('./ag-grid.css');
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -296,96 +294,4 @@ button {
|
|||||||
@mixin dark-root {
|
@mixin dark-root {
|
||||||
--theme-colors-border: rgb(255 255 255 / 10%);
|
--theme-colors-border: rgb(255 255 255 / 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-theme-alpine-dark {
|
|
||||||
--ag-font-family: var(--theme-content-font-family);
|
|
||||||
--ag-borders: none;
|
|
||||||
--ag-border-color: var(--theme-colors-border);
|
|
||||||
--ag-header-background-color: var(--theme-colors-background);
|
|
||||||
--ag-header-foreground-color: var(--theme-colors-foreground);
|
|
||||||
--ag-background-color: var(--theme-colors-background);
|
|
||||||
--ag-odd-row-background-color: var(--theme-colors-background);
|
|
||||||
--ag-foreground-color: var(--theme-colors-foreground);
|
|
||||||
--ag-cell-horizontal-padding: var(--theme-spacing-sm);
|
|
||||||
--ag-row-hover-color: lighten(var(--theme-colors-background), 5%);
|
|
||||||
--ag-selected-row-background-color: lighten(var(--theme-colors-background), 10%);
|
|
||||||
--ag-header-column-resize-handle-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-header {
|
|
||||||
width: auto;
|
|
||||||
border-bottom: 2px solid var(--theme-colors-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-ltr .ag-header-cell-resize {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-header:hover .ag-header-cell-resize {
|
|
||||||
position: absolute;
|
|
||||||
top: 25%;
|
|
||||||
width: 0.2em;
|
|
||||||
height: 50%;
|
|
||||||
border: 1px var(--theme-colors-border) solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-header-cell-label {
|
|
||||||
font-family: var(--theme-content-font-family);
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-rating,
|
|
||||||
.ag-cell-favorite {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-transparent {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-rating.visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-favorite.visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-row-hover {
|
|
||||||
.ag-cell-transparent {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-rating,
|
|
||||||
.ag-cell-favorite {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell-focus {
|
|
||||||
border: 1px var(--theme-colors-border) solid !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin dark-root {
|
|
||||||
.current-song {
|
|
||||||
.current-song-child {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--theme-colors-primary-filled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin light-root {
|
|
||||||
.current-song {
|
|
||||||
.current-song-child {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--theme-colors-primary-filled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-song > .row-index.playing .current-song-index {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user