Reveal full-screen player controls on hover and balance their layout
ci / ts / ts (packages + web) (push) Canceled after 14s
ci / ts / ts (packages + web) (push) Canceled after 14s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7ffa5d742
commit
0458cbc46c
2 files changed
+54
-15
No files matched your search
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
Reference in new issue
Block a user