diff --git a/index.css b/index.css index 10f55a7..ce1502f 100644 --- a/index.css +++ b/index.css @@ -497,7 +497,7 @@ body { max-width: 100%; height: min( calc(var(--app-vh) - var(--header-offset) - var(--shorts-chrome)), - calc((100vw - 2rem) * 16 / 9) + calc((100vw - 2rem - var(--shorts-panel-w, 0px)) * 16 / 9) ); min-height: 0; } @@ -515,6 +515,11 @@ body { .shorts-frame { --shorts-chrome: 5.5rem; } + /* Le rail est ancré au-dessus de la méta (bas) : il ne doit jamais la + chevaucher — sur un écran court il défile en interne au lieu de rogner. */ + .shorts-rail { + max-height: calc(100% - 11rem); + } } /* Embed PAYSAGE dans le cadre vertical : la boîte de l'iframe suit le16:9 @@ -572,19 +577,118 @@ body { opacity: 0; pointer-events: none; } -/* Contrôles flottants (rangée de flèches + FAB menu) : presque fondu au repos - pour laisser la vidéo respirer (ton pro), pleins dès le moindre mouvement - de souris (chromeVisible) ou survol direct. Le panneau ouvert et le FAB - ouvert ne sont jamais atténués. Le tactile ne déclenche presque pas - mousemove : sur mobile tout reste donc plein (comportement voulu). */ -.shorts-frame .shorts-ctrl, +/* --- Shorts : rail d'actions (bord DROIT de la vidéo) --------------------- */ +/* Colonne d'icônes façon Shorts : informations, flèches ↑/↓, j'aime, + s'abonner, commentaires, partager, lecture auto. TOUJOURS montée (c'est la + navigation utilisable dans tous les états, avec le FAB). Ancrage bas sur + mobile (pouce, au-dessus de la méta) puis centré verticalement au bureau + (classes du template). */ +.shorts-rail { + max-height: calc(100% - 1.5rem); + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; +} +.shorts-rail::-webkit-scrollbar { display: none; } + +.shorts-rail-btn { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + width: 2.5rem; /* 40px : cible tactile mobile */ + height: 2.5rem; + border-radius: 9999px; + color: #fff; + background: rgba(0, 0, 0, .55); + box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .5); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + transition: opacity .25s ease, background .15s ease, transform .15s ease; +} +.shorts-rail-btn:hover:not(:disabled) { background: rgba(0, 0, 0, .75); transform: scale(1.06); } +.shorts-rail-btn:disabled { opacity: .4; } +.shorts-rail-btn svg { width: 1.15rem; height: 1.15rem; } +/* Flèches ↑/↓ : plus grosses (c'est LA cible de défilement). */ +.shorts-rail-btn--nav { width: 2.75rem; height: 2.75rem; } +.shorts-rail-btn--nav svg { width: 1.5rem; height: 1.5rem; } +/* Bouton actif (j'aime, abonné, lecture auto) : plein, contraste maximal. */ +.shorts-rail-btn--on { + background: rgba(255, 255, 255, .92); + color: #0f172a; + box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .9); +} +.shorts-rail-btn--on:hover:not(:disabled) { background: #fff; } +/* Abonnement : la pastille EST l'avatar de la chaîne. */ +.shorts-rail-btn--sub { overflow: visible; } +.shorts-rail-badge { + position: absolute; + right: -2px; + bottom: -2px; + display: flex; + align-items: center; + justify-content: center; + width: 1.05rem; + height: 1.05rem; + border-radius: 9999px; + background: #ef4444; + color: #fff; + font-size: .7rem; + font-weight: 800; + line-height: 1; + box-shadow: 0 1px 3px rgba(0, 0, 0, .5); +} +.shorts-rail-btn--on .shorts-rail-badge { background: #16a34a; } +@media (min-width: 768px) { + /* Bureau : rail plus compact, la vidéo reste le sujet. */ + .shorts-rail-btn { + width: 2.25rem; + height: 2.25rem; + box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .45); + } + .shorts-rail-btn svg { width: 1.05rem; height: 1.05rem; } + .shorts-rail-btn--nav { width: 2.5rem; height: 2.5rem; } + .shorts-rail-btn--nav svg { width: 1.35rem; height: 1.35rem; } +} + +/* --- Shorts : panneau d'informations (bouton ⓘ) ---------------------------- */ +.shorts-stage { --shorts-panel-w: 0px; } +@media (min-width: 768px) { + /* Le cadre est dimensionné par la hauteur du viewport : on retranche aussi + la largeur du panneau pour que la vidéo RÉTRÉCISSE au lieu d'être rognée + (exigence : « sans masquer la vidéo »). */ + .shorts-stage.shorts-panel-open { --shorts-panel-w: 356px; } +} +.shorts-info-action { + display: inline-flex; + align-items: center; + gap: .4rem; + border-radius: 9999px; + padding: .3rem .6rem; + font-size: .72rem; + font-weight: 600; + color: rgba(255, 255, 255, .75); + background: rgba(255, 255, 255, .07); + transition: background .15s ease, color .15s ease; +} +.shorts-info-action:hover:not(:disabled) { background: rgba(255, 255, 255, .16); color: #fff; } +.shorts-info-action:disabled { opacity: .45; } +.shorts-info-action--on { color: #fff; background: rgba(255, 255, 255, .2); } + +/* Contrôles flottants (rail + FAB menu) : presque fondu au repos pour laisser + la vidéo respirer (ton pro), pleins dès le moindre mouvement de souris + (chromeVisible) ou survol direct. Le bouton actif et le FAB ouvert ne sont + jamais atténués. Le tactile ne déclenche presque pas mousemove : sur mobile + tout reste donc plein (comportement voulu). */ +.shorts-frame .shorts-rail-btn, .shorts-frame app-player-menu .pm-fab { transition: opacity 0.25s ease; } -.shorts-chrome-hidden .shorts-frame .shorts-ctrl { +.shorts-chrome-hidden .shorts-frame .shorts-rail-btn { opacity: 0.18; } -.shorts-chrome-hidden .shorts-frame .shorts-ctrl:not(:disabled):hover { +.shorts-chrome-hidden .shorts-frame .shorts-rail-btn:not(:disabled):hover { opacity: 1; } .shorts-chrome-hidden .shorts-frame app-player-menu .pm-fab { diff --git a/src/app/shared/components/player-menu/player-menu.component.ts b/src/app/shared/components/player-menu/player-menu.component.ts index 1560fa1..5abafe8 100644 --- a/src/app/shared/components/player-menu/player-menu.component.ts +++ b/src/app/shared/components/player-menu/player-menu.component.ts @@ -26,6 +26,9 @@ import { CommonModule } from '@angular/common'; '(wheel)': '$event.stopPropagation()', '(touchstart)': '$event.stopPropagation()', '(touchend)': '$event.stopPropagation()', + // /shorts suit aussi le doigt en `touchmove` : sans ça, glisser le FAB + // déplacerait AUSSI le cadre (deux drags pour un geste). + '(touchmove)': '$event.stopPropagation()', }, template: `