Files
feishin/src/renderer/features/player/components/playerbar.tsx
T
Malachi Soord 8a3edb71df feat: add semantic selectors for now-playing media (#1138)
* feat: add semantic selectors for now-playing media

This change adds unique class names to the elements that display the currently playing media information. This makes it easier for extension developers to parse the DOM and understand what media is playing.

The following classes have been added:
- `media-player`: The main player container.
- `player-cover-art`: The cover art of the playing track.
- `song-title`: The title of the playing track.
- `song-artist`: The artist of the playing track.
- `song-album`: The album of the playing track.
- `player-state-playing`/`player-state-paused`: The state of the player.
- `elapsed-time`: The elapsed time of the playing track.
- `total-duration`: The total duration of the playing track.

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2025-09-23 12:44:22 -07:00

94 lines
3.4 KiB
TypeScript

import clsx from 'clsx';
import { MouseEvent, useCallback } from 'react';
import styles from './playerbar.module.css';
import { AudioPlayer } from '/@/renderer/components';
import { CenterControls } from '/@/renderer/features/player/components/center-controls';
import { LeftControls } from '/@/renderer/features/player/components/left-controls';
import { RightControls } from '/@/renderer/features/player/components/right-controls';
import { usePowerSaveBlocker } from '/@/renderer/features/player/hooks/use-power-save-blocker';
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
import { updateSong } from '/@/renderer/features/player/update-remote-song';
import {
useCurrentPlayer,
useCurrentStatus,
useFullScreenPlayerStore,
useMuted,
usePlayer1Data,
usePlayer2Data,
usePlayerControls,
useSetFullScreenPlayerStore,
useVolume,
} from '/@/renderer/store';
import {
useGeneralSettings,
usePlaybackType,
useSettingsStore,
} from '/@/renderer/store/settings.store';
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
import { PlaybackType } from '/@/shared/types/types';
export const Playerbar = () => {
const playersRef = PlayersRef;
const settings = useSettingsStore((state) => state.playback);
const { playerbarOpenDrawer } = useGeneralSettings();
const playbackType = usePlaybackType();
const volume = useVolume();
const player1 = usePlayer1Data();
const player2 = usePlayer2Data();
const status = useCurrentStatus();
const player = useCurrentPlayer();
const muted = useMuted();
const { autoNext } = usePlayerControls();
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
usePowerSaveBlocker();
const handleToggleFullScreenPlayer = (e?: KeyboardEvent | MouseEvent<HTMLDivElement>) => {
e?.stopPropagation();
setFullScreenPlayerStore({ expanded: !isFullScreenPlayerExpanded });
};
const autoNextFn = useCallback(() => {
const playerData = autoNext();
updateSong(playerData.current.song);
}, [autoNext]);
return (
<div
className={clsx(styles.container, PlaybackSelectors.mediaPlayer)}
onClick={playerbarOpenDrawer ? handleToggleFullScreenPlayer : undefined}
>
<div className={styles.controlsGrid}>
<div className={styles.leftGridItem}>
<LeftControls />
</div>
<div className={styles.centerGridItem}>
<CenterControls playersRef={playersRef} />
</div>
<div className={styles.rightGridItem}>
<RightControls />
</div>
</div>
{playbackType === PlaybackType.WEB && (
<AudioPlayer
autoNext={autoNextFn}
crossfadeDuration={settings.crossfadeDuration}
crossfadeStyle={settings.crossfadeStyle}
currentPlayer={player}
muted={muted}
playbackStyle={settings.style}
player1={player1}
player2={player2}
ref={playersRef}
status={status}
style={settings.style as any}
volume={(volume / 100) ** 2}
/>
)}
</div>
);
};