import { useState, type CSSProperties } from 'react'; import { createPortal } from 'react-dom'; import { Link } from '@tanstack/react-router'; import { useTranslation } from 'react-i18next'; import { ArtistLinks, Cover } from '../entities/catalog'; import { usePlayer, usePlayerState } from '../player/context'; import { formatDuration } from '../shared/lib/format'; import { albumIcon, closeIcon, dislikeFillIcon, dislikeIcon, likeFillIcon, likeIcon, musicIcon, nextIcon, pauseIcon, playIcon, prevIcon, queueIcon, repeatIcon, repeatOneIcon, shuffleIcon, volumeIcon, volumeOffIcon, waveIcon, } from '../shared/ui/icons'; import { cx, Icon } from '../shared/ui/ui'; import s from './PlayerBar.module.css'; /** Плеер: полоса внизу (`bar`, по умолчанию) или плавающий остров (`island`) — выбор в настройках (docs/design.md). */ export function PlayerBar({ variant = 'bar' }: { variant?: 'bar' | 'island' }) { const { t } = useTranslation(); const player = usePlayer(); const st = usePlayerState(); const [queueOpen, setQueueOpen] = useState(false); const track = st.track; if (!track) { return ( ); } const react = (r: 'like' | 'dislike') => void player.react(track, track.reaction === r ? null : r).catch(() => undefined); const repeatLabel = t(`player.repeat_${st.repeat}`); const ctx = st.context; const tr = t as unknown as (k: string, o?: Record) => string; const source = !ctx ? null : ctx.type === 'wave' ? ctx.label ? t('player.source_wave_seed', { label: ctx.label }) : t('player.source_wave') : ctx.type === 'collection' ? tr(`player.source_${ctx.id === 'dislikes' ? 'dislikes' : 'likes'}`) : tr(`player.source_${ctx.type}`, { label: ctx.label ?? '' }); return ( ); } /** Очередь воспроизведения (выдвижная панель справа): что играет и что дальше, клик — перейти к треку. */ function QueueDrawer({ variant, onClose }: { variant: 'bar' | 'island'; onClose: () => void }) { const { t } = useTranslation(); const player = usePlayer(); const st = usePlayerState(); const upcoming = st.queue.slice(st.index, st.index + 40); // Портал: у плеера backdrop-filter, а он делает fixed-потомков относительными к себе. return createPortal( , document.body, ); }