feat(shorts): UI/UX — rail d'actions à droite (flèches ↑/↓), panneau d'infos, glissement magnétique
CI / build-and-test (push) Canceled after 8s
CI / build-and-test (push) Canceled after 8s
- Supprime les flèches Préc./Suiv. aux bords gauche/droite (troubles d'affichage récurrents) : la navigation passe au rail vertical ancré au bord DROIT de la vidéo, centré au bureau et ancré au-dessus de la méta sur mobile, avec des flèches ↑/↓ plus grosses (44 px). - Même rail : informations, j'aime, s'abonner (pastille = avatar), commentaires, partager, lecture auto. Toujours monté (comme le FAB), désactivé sans vidéo. - Bouton ⓘ : panneau d'informations (titre, vues, engagement, chaîne, description, commentaires → Watch). Colonne à droite au bureau (la vidéo rétrécit, jamais masquée : --shorts-panel-w retiré du calcul de taille), tiroir plein écran sur mobile. Échap ferme. - Transition de short : le doigt fait glisser le cadre (chrome solidaire), résistance aux extrémités, seuil de bascule 25 % de la hauteur, ressort sous le seuil, éjection + emboîtement au-delà (Web Animations, respecte prefers-reduced-motion). Aucun état de lecture modifié. - Lecture auto : interrupteur réel (rail + menu), persisté, respecté par le minuteur et par la fin de vidéo YouTube. - Tap sur un contrôle du rail = plus de play/pause parasite (garde isChromeTarget dans onTouchStart/onTouchEnd). - FAB menu conservé (haut droit, déplaçable) ; son touchmove ne déplace plus le cadre en même temps.
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user