Reveal full-screen player controls on hover and balance their layout
ci / ts / ts (packages + web) (push) Canceled after 14s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Sonnet 5.5 committed 2026-11-04 01:51:12 +03:00
1 parent f7ffa5d742
commit 0458cbc46c
2 files changed
+53 -14

No files matched your search

+42 -3
View File
@@ -77,12 +77,46 @@
pointer-events: none; pointer-events: none;
} }
/* Кнопки на обложке видны только при наведении / фокусе (на тач-экранах — всегда). */
.shade,
.round,
.controls,
.moreWrap {
opacity: 0;
transition: opacity 0.18s, background 0.12s;
}
.card:hover .shade,
.card:hover .round,
.card:hover .controls,
.card:hover .moreWrap,
.card:focus-within .shade,
.card:focus-within .round,
.card:focus-within .controls,
.card:focus-within .moreWrap,
.cardOpen .shade,
.cardOpen .round,
.cardOpen .controls,
.cardOpen .moreWrap {
opacity: 1;
}
@media (hover: none) {
.shade,
.round,
.controls,
.moreWrap {
opacity: 1;
}
}
.round { .round {
position: absolute; position: absolute;
flex: none;
display: grid; display: grid;
place-items: center; place-items: center;
width: 48px; width: 52px;
height: 48px; height: 52px;
border-radius: 50%; border-radius: 50%;
background: rgba(20, 20, 20, 0.82); background: rgba(20, 20, 20, 0.82);
color: #fff; color: #fff;
@@ -101,6 +135,11 @@
color: #ffe600; color: #ffe600;
} }
.topLeft {
top: 16px;
left: 16px;
}
.topRight { .topRight {
top: 16px; top: 16px;
right: 16px; right: 16px;
@@ -154,7 +193,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 12px; gap: 20px;
pointer-events: none; pointer-events: none;
} }
+11 -11
View File
@@ -60,12 +60,21 @@ export function FullPlayer({ onClose, onQueue, share }: { onClose: () => void; o
<Icon src={chevronDownIcon} size={26} /> <Icon src={chevronDownIcon} size={26} />
</button> </button>
<div className={s.stage}> <div className={s.stage}>
<div className={s.card}> <div className={cx(s.card, menu && s.cardOpen)}>
<Cover album={track.album} size="100%" className={s.cover} /> <Cover album={track.album} size="100%" className={s.cover} />
<div className={s.shade} aria-hidden /> <div className={s.shade} aria-hidden />
<button type="button" className={cx(s.round, s.topRight)} aria-label={t('player.queue')} onClick={onQueue}> <button type="button" className={cx(s.round, s.topRight)} aria-label={t('player.queue')} onClick={onQueue}>
<Icon src={queueIcon} size={22} /> <Icon src={queueIcon} size={22} />
</button> </button>
<button
type="button"
className={cx(s.round, s.topLeft, st.repeat !== 'off' && s.accent)}
aria-label={t(`player.repeat_${st.repeat}`)}
disabled={locked}
onClick={() => player.cycleRepeat()}
>
<Icon src={st.repeat === 'one' ? repeatOneIcon : repeatIcon} size={20} />
</button>
<div className={s.controls}> <div className={s.controls}>
<button type="button" className={s.round} aria-label={t('player.prev')} disabled={locked} onClick={() => player.prev()}> <button type="button" className={s.round} aria-label={t('player.prev')} disabled={locked} onClick={() => player.prev()}>
<Icon src={prevIcon} size={22} /> <Icon src={prevIcon} size={22} />
@@ -83,19 +92,10 @@ export function FullPlayer({ onClose, onQueue, share }: { onClose: () => void; o
<button type="button" className={s.round} aria-label={t('player.next')} disabled={locked} onClick={() => player.next()}> <button type="button" className={s.round} aria-label={t('player.next')} disabled={locked} onClick={() => player.next()}>
<Icon src={nextIcon} size={22} /> <Icon src={nextIcon} size={22} />
</button> </button>
<button
type="button"
className={cx(s.round, st.repeat !== 'off' && s.accent)}
aria-label={t(`player.repeat_${st.repeat}`)}
disabled={locked}
onClick={() => player.cycleRepeat()}
>
<Icon src={st.repeat === 'one' ? repeatOneIcon : repeatIcon} size={20} />
</button>
</div> </div>
<div className={s.moreWrap}> <div className={s.moreWrap}>
<button type="button" className={s.round} aria-label={t('player.more')} aria-expanded={menu} onClick={() => setMenu((v) => !v)}> <button type="button" className={s.round} aria-label={t('player.more')} aria-expanded={menu} onClick={() => setMenu((v) => !v)}>
<Icon src={moreIcon} size={22} /> <Icon src={moreIcon} size={26} />
</button> </button>
{menu && ( {menu && (
<div className={s.menu}> <div className={s.menu}>