mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
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>
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
} from '/@/renderer/store/settings.store';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||
import { PlaybackType, PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
interface CenterControlsProps {
|
||||
@@ -253,7 +254,13 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
||||
</div>
|
||||
<div className={styles.sliderContainer}>
|
||||
<div className={styles.sliderValueWrapper}>
|
||||
<Text fw={600} isMuted isNoSelect size="xs">
|
||||
<Text
|
||||
className={PlaybackSelectors.elapsedTime}
|
||||
fw={600}
|
||||
isMuted
|
||||
isNoSelect
|
||||
size="xs"
|
||||
>
|
||||
{formattedTime}
|
||||
</Text>
|
||||
</div>
|
||||
@@ -281,7 +288,13 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.sliderValueWrapper}>
|
||||
<Text fw={600} isMuted isNoSelect size="xs">
|
||||
<Text
|
||||
className={PlaybackSelectors.totalDuration}
|
||||
fw={600}
|
||||
isMuted
|
||||
isNoSelect
|
||||
size="xs"
|
||||
>
|
||||
{duration}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,7 @@ import { Image } from '/@/shared/components/image/image';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
export const LeftControls = () => {
|
||||
@@ -104,7 +105,10 @@ export const LeftControls = () => {
|
||||
openDelay={500}
|
||||
>
|
||||
<Image
|
||||
className={styles.playerbarImage}
|
||||
className={clsx(
|
||||
styles.playerbarImage,
|
||||
PlaybackSelectors.playerCoverArt,
|
||||
)}
|
||||
loading="eager"
|
||||
src={currentSong?.imageUrl ?? ''}
|
||||
/>
|
||||
@@ -139,6 +143,7 @@ export const LeftControls = () => {
|
||||
<div className={styles.lineItem} onClick={stopPropagation}>
|
||||
<Group align="center" gap="xs" wrap="nowrap">
|
||||
<Text
|
||||
className={PlaybackSelectors.songTitle}
|
||||
component={Link}
|
||||
fw={500}
|
||||
isLink
|
||||
@@ -164,7 +169,11 @@ export const LeftControls = () => {
|
||||
</Group>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.lineItem, styles.secondary)}
|
||||
className={clsx(
|
||||
styles.lineItem,
|
||||
styles.secondary,
|
||||
PlaybackSelectors.songArtist,
|
||||
)}
|
||||
onClick={stopPropagation}
|
||||
>
|
||||
{artists?.map((artist, index) => (
|
||||
@@ -190,7 +199,11 @@ export const LeftControls = () => {
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.lineItem, styles.secondary)}
|
||||
className={clsx(
|
||||
styles.lineItem,
|
||||
styles.secondary,
|
||||
PlaybackSelectors.songAlbum,
|
||||
)}
|
||||
onClick={stopPropagation}
|
||||
>
|
||||
<Text
|
||||
|
||||
@@ -6,6 +6,7 @@ import styles from './player-button.module.css';
|
||||
|
||||
import { ActionIcon, ActionIconProps } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Tooltip, TooltipProps } from '/@/shared/components/tooltip/tooltip';
|
||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||
|
||||
interface PlayerButtonProps extends Omit<ActionIconProps, 'icon' | 'variant'> {
|
||||
icon: ReactNode;
|
||||
@@ -62,9 +63,13 @@ interface PlayButtonProps extends Omit<ActionIconProps, 'icon' | 'variant'> {
|
||||
|
||||
export const PlayButton = forwardRef<HTMLButtonElement, PlayButtonProps>(
|
||||
({ isPaused, onClick, ...props }: PlayButtonProps, ref) => {
|
||||
const playerStateClass = isPaused
|
||||
? PlaybackSelectors.playerStatePaused
|
||||
: PlaybackSelectors.playerStatePlaying;
|
||||
|
||||
return (
|
||||
<ActionIcon
|
||||
className={styles.main}
|
||||
className={clsx(styles.main, playerStateClass)}
|
||||
icon={isPaused ? 'mediaPlay' : 'mediaPause'}
|
||||
iconProps={{
|
||||
size: 'lg',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import clsx from 'clsx';
|
||||
import { MouseEvent, useCallback } from 'react';
|
||||
|
||||
import styles from './playerbar.module.css';
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
usePlaybackType,
|
||||
useSettingsStore,
|
||||
} from '/@/renderer/store/settings.store';
|
||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||
import { PlaybackType } from '/@/shared/types/types';
|
||||
|
||||
export const Playerbar = () => {
|
||||
@@ -56,7 +58,7 @@ export const Playerbar = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.container}
|
||||
className={clsx(styles.container, PlaybackSelectors.mediaPlayer)}
|
||||
onClick={playerbarOpenDrawer ? handleToggleFullScreenPlayer : undefined}
|
||||
>
|
||||
<div className={styles.controlsGrid}>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Defines the selectors used to identify playback-related elements in the UI.
|
||||
// Can be used by browser extensions for accessing meta data around currently playing media.
|
||||
|
||||
export const PlaybackSelectors = {
|
||||
elapsedTime: 'elapsed-time',
|
||||
mediaPlayer: 'media-player',
|
||||
playerCoverArt: 'player-cover-art',
|
||||
playerStatePaused: 'player-state-paused',
|
||||
playerStatePlaying: 'player-state-playing',
|
||||
songAlbum: 'song-album',
|
||||
songArtist: 'song-artist',
|
||||
songTitle: 'song-title',
|
||||
totalDuration: 'total-duration',
|
||||
} as const;
|
||||
Reference in New Issue
Block a user