diff --git a/src/renderer/components/virtual-table/cells/row-index-cell.tsx b/src/renderer/components/virtual-table/cells/row-index-cell.tsx
new file mode 100644
index 00000000..32721b0a
--- /dev/null
+++ b/src/renderer/components/virtual-table/cells/row-index-cell.tsx
@@ -0,0 +1,19 @@
+import type { ICellRendererParams } from '@ag-grid-community/core';
+import { Text } from '/@/renderer/components/text';
+import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
+
+export const RowIndexCell = ({ value }: ICellRendererParams) => {
+ return (
+
+
+ {value}
+
+
+ );
+};
diff --git a/src/renderer/components/virtual-table/hooks/use-current-song-row-styles.ts b/src/renderer/components/virtual-table/hooks/use-current-song-row-styles.ts
index 1ad467f2..04631427 100644
--- a/src/renderer/components/virtual-table/hooks/use-current-song-row-styles.ts
+++ b/src/renderer/components/virtual-table/hooks/use-current-song-row-styles.ts
@@ -1,7 +1,8 @@
import { RowClassRules, RowNode } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-import { MutableRefObject, useEffect, useMemo } from 'react';
+import { MutableRefObject, useEffect, useMemo, useRef } from 'react';
import { Song } from '/@/renderer/api/types';
+import { useAppFocus } from '/@/renderer/hooks';
import { useCurrentSong, usePlayerStore } from '/@/renderer/store';
interface UseCurrentSongRowStylesProps {
@@ -10,17 +11,43 @@ interface UseCurrentSongRowStylesProps {
export const useCurrentSongRowStyles = ({ tableRef }: UseCurrentSongRowStylesProps) => {
const currentSong = useCurrentSong();
+ const isFocused = useAppFocus();
+ const isFocusedRef = useRef(isFocused);
+
+ useEffect(() => {
+ // Redraw rows if the app focus changes
+ if (isFocusedRef.current !== isFocused) {
+ isFocusedRef.current = isFocused;
+ if (tableRef?.current) {
+ const { api, columnApi } = tableRef?.current || {};
+ if (api == null || columnApi == null) {
+ return;
+ }
+
+ const currentNode = currentSong?.id ? api.getRowNode(currentSong.id) : undefined;
+
+ const rowNodes = [currentNode].filter((e) => e !== undefined) as RowNode[];
+
+ if (rowNodes) {
+ api.redrawRows({ rowNodes });
+ }
+ }
+ }
+ }, [currentSong?.id, isFocused, tableRef]);
const rowClassRules = useMemo | undefined>(() => {
return {
'current-song': (params) => {
- return params?.data?.id === currentSong?.id;
+ return (
+ params?.data?.id === currentSong?.id &&
+ params?.data?.albumId === currentSong?.albumId
+ );
},
};
- }, [currentSong?.id]);
+ }, [currentSong?.albumId, currentSong?.id]);
- // Redraw song rows when current song changes
useEffect(() => {
+ // Redraw song rows when current song changes
const unsubSongChange = usePlayerStore.subscribe(
(state) => state.current.song,
(song, previousSong) => {
@@ -46,8 +73,35 @@ export const useCurrentSongRowStyles = ({ tableRef }: UseCurrentSongRowStylesPro
{ equalityFn: (a, b) => a?.id === b?.id },
);
+ // Redraw song rows when the status changes
+ const unsubStatusChange = usePlayerStore.subscribe(
+ (state) => state.current.song,
+ (song, previousSong) => {
+ if (tableRef?.current) {
+ const { api, columnApi } = tableRef?.current || {};
+ if (api == null || columnApi == null) {
+ return;
+ }
+
+ const currentNode = song?.id ? api.getRowNode(song.id) : undefined;
+
+ const previousNode = previousSong?.id
+ ? api.getRowNode(previousSong?.id)
+ : undefined;
+
+ const rowNodes = [currentNode, previousNode].filter(
+ (e) => e !== undefined,
+ ) as RowNode[];
+
+ api.redrawRows({ rowNodes });
+ }
+ },
+ { equalityFn: (a, b) => a?.id === b?.id },
+ );
+
return () => {
unsubSongChange();
+ unsubStatusChange();
};
}, [tableRef]);
diff --git a/src/renderer/components/virtual-table/index.tsx b/src/renderer/components/virtual-table/index.tsx
index f59ec520..9ff51992 100644
--- a/src/renderer/components/virtual-table/index.tsx
+++ b/src/renderer/components/virtual-table/index.tsx
@@ -19,6 +19,7 @@ import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import formatDuration from 'format-duration';
import { AnimatePresence } from 'framer-motion';
+import isElectron from 'is-electron';
import { generatePath } from 'react-router';
import styled from 'styled-components';
import { AlbumArtistCell } from '/@/renderer/components/virtual-table/cells/album-artist-cell';
@@ -29,7 +30,11 @@ import { GenreCell } from '/@/renderer/components/virtual-table/cells/genre-cell
import { GenericTableHeader } from '/@/renderer/components/virtual-table/headers/generic-table-header';
import { AppRoute } from '/@/renderer/router/routes';
import { PersistedTableColumn } from '/@/renderer/store/settings.store';
-import { TableColumn, TablePagination as TablePaginationType } from '/@/renderer/types';
+import {
+ PlayerStatus,
+ TableColumn,
+ TablePagination as TablePaginationType,
+} from '/@/renderer/types';
import { FavoriteCell } from '/@/renderer/components/virtual-table/cells/favorite-cell';
import { RatingCell } from '/@/renderer/components/virtual-table/cells/rating-cell';
import { TablePagination } from '/@/renderer/components/virtual-table/table-pagination';
@@ -37,6 +42,7 @@ import { ActionsCell } from '/@/renderer/components/virtual-table/cells/actions-
import { TitleCell } from '/@/renderer/components/virtual-table/cells/title-cell';
import { useFixedTableHeader } from '/@/renderer/components/virtual-table/hooks/use-fixed-table-header';
import { NoteCell } from '/@/renderer/components/virtual-table/cells/note-cell';
+import { RowIndexCell } from '/@/renderer/components/virtual-table/cells/row-index-cell';
export * from './table-config-dropdown';
export * from './table-pagination';
@@ -260,7 +266,16 @@ const tableColumns: { [key: string]: ColDef } = {
width: 80,
},
rowIndex: {
- cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'right' }),
+ cellClass: 'row-index',
+ cellClassRules: {
+ focused: (params) => {
+ return isElectron() && params.context?.isFocused;
+ },
+ playing: (params) => {
+ return params.context?.status === PlayerStatus.PLAYING;
+ },
+ },
+ cellRenderer: RowIndexCell,
colId: TableColumn.ROW_INDEX,
headerComponent: (params: IHeaderParams) =>
GenericTableHeader(params, { position: 'right', preset: 'rowIndex' }),
@@ -311,7 +326,29 @@ const tableColumns: { [key: string]: ColDef } = {
width: 250,
},
trackNumber: {
- cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'center' }),
+ cellClass: 'track-number',
+ cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'right' }),
+ colId: TableColumn.TRACK_NUMBER,
+ field: 'trackNumber',
+ headerComponent: (params: IHeaderParams) =>
+ GenericTableHeader(params, { position: 'center' }),
+ headerName: 'Track',
+ suppressSizeToFit: true,
+ valueGetter: (params: ValueGetterParams) =>
+ params.data ? params.data.trackNumber : undefined,
+ width: 80,
+ },
+ trackNumberDetail: {
+ cellClass: 'row-index',
+ cellClassRules: {
+ focused: (params) => {
+ return isElectron() && params.context?.isFocused;
+ },
+ playing: (params) => {
+ return params.context?.status === PlayerStatus.PLAYING;
+ },
+ },
+ cellRenderer: RowIndexCell,
colId: TableColumn.TRACK_NUMBER,
field: 'trackNumber',
headerComponent: (params: IHeaderParams) =>
@@ -354,10 +391,19 @@ export const getColumnDef = (column: TableColumn) => {
return tableColumns[column as keyof typeof tableColumns];
};
-export const getColumnDefs = (columns: PersistedTableColumn[], useWidth?: boolean) => {
+export const getColumnDefs = (
+ columns: PersistedTableColumn[],
+ useWidth?: boolean,
+ type?: 'albumDetail',
+) => {
const columnDefs: ColDef[] = [];
for (const column of columns) {
- const presetColumn = tableColumns[column.column as keyof typeof tableColumns];
+ let presetColumn = tableColumns[column.column as keyof typeof tableColumns];
+
+ if (type === 'albumDetail' && column.column === TableColumn.TRACK_NUMBER) {
+ presetColumn = tableColumns['trackNumberDetail' as keyof typeof tableColumns];
+ }
+
if (presetColumn) {
columnDefs.push({
...presetColumn,
diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx
index f232298b..2d363032 100644
--- a/src/renderer/features/albums/components/album-detail-content.tsx
+++ b/src/renderer/features/albums/components/album-detail-content.tsx
@@ -31,9 +31,9 @@ import {
import { usePlayQueueAdd } from '/@/renderer/features/player';
import { PlayButton, useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay';
-import { useContainerQuery } from '/@/renderer/hooks';
+import { useAppFocus, useContainerQuery } from '/@/renderer/hooks';
import { AppRoute } from '/@/renderer/router/routes';
-import { useCurrentServer } from '/@/renderer/store';
+import { useCurrentServer, useCurrentStatus } from '/@/renderer/store';
import {
usePlayButtonBehavior,
useSettingsStoreActions,
@@ -70,8 +70,13 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
const handlePlayQueueAdd = usePlayQueueAdd();
const tableConfig = useTableSettings('albumDetail');
const { setTable } = useSettingsStoreActions();
+ const status = useCurrentStatus();
+ const isFocused = useAppFocus();
- const columnDefs = useMemo(() => getColumnDefs(tableConfig.columns), [tableConfig.columns]);
+ const columnDefs = useMemo(
+ () => getColumnDefs(tableConfig.columns, false, 'albumDetail'),
+ [tableConfig.columns],
+ );
const getRowHeight = useCallback(
(params: RowHeightParams) => {
@@ -396,7 +401,9 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
autoFitColumns={tableConfig.autoFit}
columnDefs={columnDefs}
context={{
+ isFocused,
onCellContextMenu,
+ status,
}}
enableCellChangeFlash={false}
fullWidthCellRenderer={FullWidthDiscCell}
diff --git a/src/renderer/features/now-playing/components/play-queue.tsx b/src/renderer/features/now-playing/components/play-queue.tsx
index 62253305..d1df1b5d 100644
--- a/src/renderer/features/now-playing/components/play-queue.tsx
+++ b/src/renderer/features/now-playing/components/play-queue.tsx
@@ -11,6 +11,7 @@ import '@ag-grid-community/styles/ag-theme-alpine.css';
import {
useAppStoreActions,
useCurrentSong,
+ useCurrentStatus,
useDefaultQueue,
usePlayerControls,
usePreviousSong,
@@ -34,6 +35,7 @@ import { LibraryItem, QueueSong } from '/@/renderer/api/types';
import { useHandleTableContextMenu } from '/@/renderer/features/context-menu';
import { QUEUE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid';
+import { useAppFocus } from '/@/renderer/hooks';
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
const remote = isElectron() ? window.electron.remote : null;
@@ -49,6 +51,7 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref) => {
const { reorderQueue, setCurrentTrack } = useQueueControls();
const currentSong = useCurrentSong();
const previousSong = usePreviousSong();
+ const status = useCurrentStatus();
const { setSettings } = useSettingsStoreActions();
const { setAppStore } = useAppStoreActions();
const tableConfig = useTableSettings(type);
@@ -56,6 +59,7 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref) => {
const playerType = usePlayerType();
const { play } = usePlayerControls();
const volume = useVolume();
+ const isFocused = useAppFocus();
useEffect(() => {
if (tableRef.current) {
@@ -204,7 +208,7 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref) => {
}
}
}
- }, [currentSong, previousSong, tableConfig.followCurrentSong]);
+ }, [currentSong, previousSong, tableConfig.followCurrentSong, status, isFocused]);
const onCellContextMenu = useHandleTableContextMenu(LibraryItem.SONG, QUEUE_CONTEXT_MENU_ITEMS);
@@ -219,7 +223,9 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref) => {
autoFitColumns={tableConfig.autoFit}
columnDefs={columnDefs}
context={{
+ isFocused,
onCellContextMenu,
+ status,
}}
deselectOnClickOutside={type === 'fullScreen'}
getRowId={(data) => data.data.uniqueId}
diff --git a/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx b/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx
index f1020241..7365d886 100644
--- a/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx
+++ b/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx
@@ -22,7 +22,7 @@ import {
SortOrder,
} from '/@/renderer/api/types';
import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid';
-import { getColumnDefs, TablePagination, VirtualTable } from '/@/renderer/components/virtual-table';
+import { TablePagination, VirtualTable, getColumnDefs } from '/@/renderer/components/virtual-table';
import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
import { useHandleTableContextMenu } from '/@/renderer/features/context-menu';
import {
@@ -34,6 +34,7 @@ import { usePlaylistDetail } from '/@/renderer/features/playlists/queries/playli
import { usePlaylistSongList } from '/@/renderer/features/playlists/queries/playlist-song-list-query';
import {
useCurrentServer,
+ useCurrentStatus,
usePlaylistDetailStore,
usePlaylistDetailTablePagination,
useSetPlaylistDetailTable,
@@ -41,6 +42,7 @@ import {
} from '/@/renderer/store';
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
import { ListDisplayType } from '/@/renderer/types';
+import { useAppFocus } from '/@/renderer/hooks';
interface PlaylistDetailContentProps {
tableRef: MutableRefObject;
@@ -49,6 +51,8 @@ interface PlaylistDetailContentProps {
export const PlaylistDetailSongListContent = ({ tableRef }: PlaylistDetailContentProps) => {
const { playlistId } = useParams() as { playlistId: string };
const queryClient = useQueryClient();
+ const status = useCurrentStatus();
+ const isFocused = useAppFocus();
const server = useCurrentServer();
const page = usePlaylistDetailStore();
const filters: Partial = useMemo(() => {
@@ -236,6 +240,11 @@ export const PlaylistDetailSongListContent = ({ tableRef }: PlaylistDetailConten
alwaysShowHorizontalScroll
autoFitColumns={page.table.autoFit}
columnDefs={columnDefs}
+ context={{
+ isFocused,
+ onCellContextMenu: handleContextMenu,
+ status,
+ }}
getRowId={(data) => data.data.uniqueId}
infiniteInitialRowCount={checkPlaylistList.data?.totalRecordCount || 100}
pagination={isPaginationEnabled}
diff --git a/src/renderer/features/songs/components/song-list-table-view.tsx b/src/renderer/features/songs/components/song-list-table-view.tsx
index 36ad27b4..06de099d 100644
--- a/src/renderer/features/songs/components/song-list-table-view.tsx
+++ b/src/renderer/features/songs/components/song-list-table-view.tsx
@@ -8,7 +8,8 @@ import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/ho
import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
import { useListContext } from '/@/renderer/context/list-context';
import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { useCurrentServer, usePlayButtonBehavior } from '/@/renderer/store';
+import { useAppFocus } from '/@/renderer/hooks';
+import { useCurrentServer, useCurrentStatus, usePlayButtonBehavior } from '/@/renderer/store';
interface SongListTableViewProps {
itemCount?: number;
@@ -18,6 +19,8 @@ interface SongListTableViewProps {
export const SongListTableView = ({ tableRef, itemCount }: SongListTableViewProps) => {
const server = useCurrentServer();
const { pageKey, id, handlePlay, customFilters } = useListContext();
+ const isFocused = useAppFocus();
+ const status = useCurrentStatus();
const { rowClassRules } = useCurrentSongRowStyles({ tableRef });
@@ -46,6 +49,11 @@ export const SongListTableView = ({ tableRef, itemCount }: SongListTableViewProp
key={`table-${tableProps.rowHeight}-${server?.id}`}
ref={tableRef}
{...tableProps}
+ context={{
+ ...tableProps.context,
+ isFocused,
+ status,
+ }}
rowClassRules={rowClassRules}
onRowDoubleClicked={handleRowDoubleClick}
/>
diff --git a/src/renderer/hooks/index.ts b/src/renderer/hooks/index.ts
index e0f836c1..82dd033a 100644
--- a/src/renderer/hooks/index.ts
+++ b/src/renderer/hooks/index.ts
@@ -4,3 +4,4 @@ export * from './use-should-pad-titlebar';
export * from './use-container-query';
export * from './use-fast-average-color';
export * from './use-hide-scrollbar';
+export * from './use-app-focus';
diff --git a/src/renderer/hooks/use-app-focus.ts b/src/renderer/hooks/use-app-focus.ts
new file mode 100644
index 00000000..72e163f8
--- /dev/null
+++ b/src/renderer/hooks/use-app-focus.ts
@@ -0,0 +1,22 @@
+// From https://learnersbucket.com/examples/interview/usehasfocus-hook-in-react/
+
+import { useState, useEffect } from 'react';
+
+export const useAppFocus = () => {
+ const [focus, setFocus] = useState(document.hasFocus());
+
+ useEffect(() => {
+ const onFocus = () => setFocus(true);
+ const onBlur = () => setFocus(false);
+
+ window.addEventListener('focus', onFocus);
+ window.addEventListener('blur', onBlur);
+
+ return () => {
+ window.removeEventListener('focus', onFocus);
+ window.removeEventListener('blur', onBlur);
+ };
+ }, []);
+
+ return focus;
+};
diff --git a/src/renderer/media/play-static.svg b/src/renderer/media/play-static.svg
new file mode 100644
index 00000000..acee2363
--- /dev/null
+++ b/src/renderer/media/play-static.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/src/renderer/media/play.svg b/src/renderer/media/play.svg
new file mode 100644
index 00000000..f1808b5d
--- /dev/null
+++ b/src/renderer/media/play.svg
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts
index 60ebda84..b1650afa 100644
--- a/src/renderer/store/settings.store.ts
+++ b/src/renderer/store/settings.store.ts
@@ -344,6 +344,10 @@ const initialState: SettingsState = {
fullScreen: {
autoFit: true,
columns: [
+ {
+ column: TableColumn.ROW_INDEX,
+ width: 80,
+ },
{
column: TableColumn.TITLE_COMBINED,
width: 500,
@@ -365,7 +369,7 @@ const initialState: SettingsState = {
columns: [
{
column: TableColumn.ROW_INDEX,
- width: 50,
+ width: 80,
},
{
column: TableColumn.TITLE,
diff --git a/src/renderer/themes/default.scss b/src/renderer/themes/default.scss
index c8c64b5f..709e0606 100644
--- a/src/renderer/themes/default.scss
+++ b/src/renderer/themes/default.scss
@@ -101,6 +101,8 @@
--card-poster-bg-hover: transparent;
--card-poster-radius: 3px;
--background-noise: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIj48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iLjc1IiBzdGl0Y2hUaWxlcz0ic3RpdGNoIi8+PGZlQ29sb3JNYXRyaXggdHlwZT0ic2F0dXJhdGUiIHZhbHVlcz0iMCIvPjwvZmlsdGVyPjxwYXRoIGZpbHRlcj0idXJsKCNhKSIgb3BhY2l0eT0iLjA1IiBkPSJNMCAwaDMwMHYzMDBIMHoiLz48L3N2Zz4=');
+ --current-song-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2aWV3Qm94PSIxMDAgMTMwIDU3IDgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxyZWN0IHg9IjEwMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iMjAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMDZweCAxNDBweDsiLz4KICA8cmVjdCB4PSIxMTUiIHk9IjEzMCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjYwIiBzdHlsZT0iZmlsbDogcmdiKDIxNiwgMjE2LCAyMTYpOyBzdHJva2U6IHJnYigwLCAwLCAwKTsgdHJhbnNmb3JtLW9yaWdpbjogMTIxcHggMTYwcHg7Ii8+CiAgPHJlY3QgeD0iMTMwIiB5PSIxMzAiIHdpZHRoPSIxMiIgaGVpZ2h0PSI4MCIgc3R5bGU9ImZpbGw6IHJnYigyMTYsIDIxNiwgMjE2KTsgc3Ryb2tlOiByZ2IoMCwgMCwgMCk7IHRyYW5zZm9ybS1vcmlnaW46IDEzNnB4IDE3MHB4OyIvPgogIDxyZWN0IHg9IjE0NSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iNDUiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxNTFweCAxNTIuNXB4OyIvPgo8L3N2Zz4=');
+ --current-song-image-animated: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2aWV3Qm94PSIxMDAgMTMwIDU3IDgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxyZWN0IHg9IjEwMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMDZweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjgwOzE1OzgwIiBiZWdpbj0iMC4xcyIgZHVyPSIwLjk1cyIga2V5VGltZXM9IjA7IDAuNDczNjg7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQyIDAgMC41OCAxOyAwLjQyIDAgMC41OCAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjExNSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMjFweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjI1OzgwOzI1IiBiZWdpbj0iMC4xcyIgZHVyPSIwLjk1cyIga2V5VGltZXM9IjA7IDAuNDQ0NDQ7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQ1IDAgMC41NSAxOyAwLjQ1IDAgMC41NSAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjEzMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMzZweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjgwOzEwOzgwIiBiZWdpbj0iMC4xcyIgZHVyPSIwLjg1cyIga2V5VGltZXM9IjA7IDAuNDIxMDU7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjY1IDAgMC4zNSAxOyAwLjY1IDAgMC4zNSAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjE0NSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxNTFweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjMwOzgwOzMwIiBiZWdpbj0iMC4xcyIgZHVyPSIxLjA1cyIga2V5VGltZXM9IjA7IDAuMzE1Nzk7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQyIDAgMC41OCAxOyAwLjQyIDAgMC41OCAxIi8+CiAgPC9yZWN0Pgo8L3N2Zz4=');
--bg-header-overlay: linear-gradient(transparent 0%, rgba(0, 0, 0, 50%) 100%),
var(--background-noise);
--bg-subheader-overlay: linear-gradient(180deg, rgba(0, 0, 0, 5%) 0%, var(--main-bg) 100%),
@@ -184,8 +186,40 @@
}
.current-song {
+ background: var(--table-row-hover-bg);
+
.current-song-child {
color: var(--primary-color) !important;
}
}
+
+ .current-song > .row-index.playing .current-song-index {
+ display: none;
+ }
+
+ .current-song > .row-index.playing.focused ::before {
+ content: ' ';
+ display: block;
+ height: 1rem;
+ width: 1rem;
+ background-color: var(--primary-color);
+ -webkit-mask-image: var(--current-song-image-animated);
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ transform: rotate(180deg);
+ mask-image: var(--current-song-image-animated);
+ }
+
+ .current-song > .row-index.playing ::before {
+ content: ' ';
+ display: block;
+ height: 1rem;
+ width: 1rem;
+ background-color: var(--primary-color);
+ -webkit-mask-image: var(--current-song-image);
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ transform: rotate(180deg);
+ mask-image: var(--current-song-image);
+ }
}