fix(menu-fab): navigation du menu correcte sur /shorts + FAB plus compact
CI / build-and-test (push) Canceled after 31s
CI / build-and-test (push) Canceled after 31s
- app-player-menu : stopPropagation wheel/touchstart/touchend sur le host — les handlers window:wheel et window:touch* de /shorts ne volaient plus les gestes sur le panneau (impossible de scroller jusqu'en bas du menu, tap = play/pause, swipe = changement de short) - /shorts : ArrowUp/Down ignore quand le menu est ouvert - /shorts : le FAB passe en haut a DROITE du cadre (la fleche retour mobile z-20 passait par-dessus le FAB piege dans la scene z-10) - Look/taille : FAB 40->36px, panneau 288->240px, items compacts, max-height 70vh/480 -> 65vh/430 (plus de rognage par overflow:hidden), pastille en degrade + relief, panneau rounded-xl + highlight interne
This commit is contained in:
@@ -577,42 +577,54 @@ body {
|
||||
avec en-tête, entrée/sortie animées. Harmonisé avec les commandes overlay
|
||||
des players YouTube/Dailymotion (fond sombre translucide, blur, ring fin). */
|
||||
|
||||
/* Pastille FAB (haut-gauche du lecteur). */
|
||||
/* Pastille FAB (coin du lecteur) : disque compact en dégradé sombre, léger
|
||||
relief (ombre + highlight interne) et agrandissement au survol. */
|
||||
.pm-fab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.5rem; /* 40px */
|
||||
height: 2.5rem;
|
||||
width: 2.25rem; /* 36px */
|
||||
height: 2.25rem;
|
||||
border-radius: 9999px;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, .55);
|
||||
border: 1px solid rgba(255, 255, 255, .14);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
background: linear-gradient(180deg, rgba(30, 41, 59, .88), rgba(2, 6, 23, .9));
|
||||
border: 1px solid rgba(255, 255, 255, .18);
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .12);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
cursor: pointer;
|
||||
transition: background-color .15s ease, border-color .15s ease, transform .15s ease;
|
||||
transition: background .15s ease, border-color .15s ease, transform .15s ease, box-shadow .15s ease;
|
||||
}
|
||||
.pm-fab svg { width: 1.125rem; height: 1.125rem; }
|
||||
.pm-fab:hover { background: rgba(0, 0, 0, .72); border-color: rgba(255, 255, 255, .24); }
|
||||
.pm-fab:active { transform: scale(.93); }
|
||||
.pm-fab-open { background: rgba(0, 0, 0, .72); border-color: rgba(255, 255, 255, .24); }
|
||||
.pm-fab:focus-visible { outline: 2px solid rgba(255, 255, 255, .55); outline-offset: 2px; }
|
||||
.pm-fab svg { width: 1rem; height: 1rem; opacity: .92; }
|
||||
.pm-fab:hover {
|
||||
background: linear-gradient(180deg, rgba(51, 65, 85, .95), rgba(15, 23, 42, .95));
|
||||
border-color: rgba(255, 255, 255, .32);
|
||||
transform: scale(1.06);
|
||||
}
|
||||
.pm-fab:active { transform: scale(.94); }
|
||||
.pm-fab-open {
|
||||
background: linear-gradient(180deg, rgba(51, 65, 85, .95), rgba(2, 6, 23, .95));
|
||||
border-color: rgba(255, 255, 255, .32);
|
||||
}
|
||||
.pm-fab:focus-visible { outline: 2px solid rgba(255, 255, 255, .6); outline-offset: 2px; }
|
||||
|
||||
/* Panneau déroulant (toujours monté, animé via open/close). */
|
||||
.pm-panel {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
left: 0;
|
||||
width: 18rem; /* 288px */
|
||||
max-height: min(70vh, 480px);
|
||||
width: 15rem; /* 240px */
|
||||
/* Borné à 65vh : le cadre /shorts a `overflow:hidden` — au-delà, le bas du
|
||||
menu serait rogné sur les petits écrans (le corps scrolle donc). */
|
||||
max-height: min(65vh, 430px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
border-radius: 1rem;
|
||||
background: rgba(15, 23, 42, .92); /* slate-900/92 */
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
box-shadow: 0 18px 50px rgba(0, 0, 0, .55), 0 2px 10px rgba(0, 0, 0, .35);
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(15, 23, 42, .94); /* slate-900/94 */
|
||||
border: 1px solid rgba(255, 255, 255, .12);
|
||||
box-shadow: 0 20px 50px rgba(0, 0, 0, .6), 0 2px 10px rgba(0, 0, 0, .4),
|
||||
inset 0 1px 0 rgba(255, 255, 255, .07);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
opacity: 0;
|
||||
@@ -635,13 +647,13 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
padding: 0.625rem 0.625rem 0.625rem 0.875rem;
|
||||
gap: 0.5rem;
|
||||
padding: 0.4375rem 0.4375rem 0.4375rem 0.75rem;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .08);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.pm-panel-title {
|
||||
font-size: 0.8125rem;
|
||||
font-size: 0.75rem; /* 12px */
|
||||
font-weight: 600;
|
||||
letter-spacing: .02em;
|
||||
color: rgba(255, 255, 255, .92);
|
||||
@@ -653,20 +665,20 @@ body {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 9999px;
|
||||
color: rgba(255, 255, 255, .7);
|
||||
flex-shrink: 0;
|
||||
transition: background-color .15s ease, color .15s ease;
|
||||
}
|
||||
.pm-panel-close svg { width: 1rem; height: 1rem; }
|
||||
.pm-panel-close svg { width: 0.875rem; height: 0.875rem; }
|
||||
.pm-panel-close:hover { background: rgba(255, 255, 255, .1); color: #fff; }
|
||||
.pm-panel-close:focus-visible { outline: 2px solid rgba(255, 255, 255, .5); outline-offset: 1px; }
|
||||
|
||||
/* Corps scrollable du panneau. */
|
||||
.pm-panel-body {
|
||||
padding: 0.5rem;
|
||||
padding: 0.375rem;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
flex: 1;
|
||||
@@ -677,7 +689,7 @@ body {
|
||||
|
||||
/* Libellé de section. */
|
||||
.pm-section-label {
|
||||
padding: 0.625rem 0.75rem 0.375rem;
|
||||
padding: 0.5rem 0.625rem 0.25rem;
|
||||
font-size: 0.6875rem; /* 11px */
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
@@ -689,11 +701,11 @@ body {
|
||||
.pm-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
gap: 0.625rem;
|
||||
width: 100%;
|
||||
padding: 0.5625rem 0.75rem;
|
||||
border-radius: 0.625rem;
|
||||
font-size: 0.84375rem; /* 13.5px */
|
||||
padding: 0.5rem 0.625rem;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.8125rem; /* 13px */
|
||||
color: var(--text);
|
||||
text-align: left;
|
||||
line-height: 1.3;
|
||||
@@ -706,10 +718,17 @@ body {
|
||||
.pm-item:disabled { opacity: .4; cursor: not-allowed; }
|
||||
.pm-item svg { flex-shrink: 0; color: rgba(255, 255, 255, .75); }
|
||||
.pm-item .pm-item-label { flex: 1; min-width: 0; }
|
||||
.pm-item .pm-item-hint { font-size: 0.71875rem; color: var(--muted); }
|
||||
.pm-item .pm-item-hint { font-size: 0.6875rem; color: var(--muted); }
|
||||
|
||||
/* Séparateur. */
|
||||
.pm-sep { height: 1px; margin: 0.375rem 0.625rem; background: rgba(255, 255, 255, .08); }
|
||||
.pm-sep { height: 1px; margin: 0.25rem 0.5rem; background: rgba(255, 255, 255, .08); }
|
||||
|
||||
/* /shorts : la flèche « retour accueil » occupe le coin haut-gauche (mobile)
|
||||
et passait PAR-DESSUS le FAB (elle est à z-20 au niveau de la scène, le FAB
|
||||
étant enfermé dans le contexte z-10). Le FAB passe donc en haut à droite du
|
||||
cadre, panneau ancré sur le même côté. */
|
||||
.shorts-frame app-player-menu { left: auto; right: 0.5rem; }
|
||||
.shorts-frame app-player-menu .pm-panel { left: auto; right: 0; transform-origin: top right; }
|
||||
|
||||
/* --- Drawer / overlay plumbing -------------------------------------------- */
|
||||
/* Applied to <body> while a full-screen drawer or modal owns the viewport.
|
||||
|
||||
@@ -18,6 +18,15 @@ import { CommonModule } from '@angular/common';
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule],
|
||||
// Les pages /shorts hijackent `window:wheel` / `window:touchstart|end` pour
|
||||
// naviguer d'un short à l'autre : sans ces stopPropagation, tout geste SUR le
|
||||
// panneau ouvert scrolle la vidéo au lieu du menu (impossible d'atteindre le
|
||||
// bas du menu). Arrêté ici = corrigé une fois pour /watch ET /shorts.
|
||||
host: {
|
||||
'(wheel)': '$event.stopPropagation()',
|
||||
'(touchstart)': '$event.stopPropagation()',
|
||||
'(touchend)': '$event.stopPropagation()',
|
||||
},
|
||||
template: `
|
||||
<button type="button"
|
||||
(click)="toggle(); $event.stopPropagation()"
|
||||
|
||||
@@ -1915,7 +1915,8 @@ export class WatchShortComponent implements OnDestroy {
|
||||
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
onKey(ev: KeyboardEvent) {
|
||||
if (this.items().length === 0) return;
|
||||
// Menu FAB ouvert : ↑↓ doivent défiler PANNEAU, pas changer de short.
|
||||
if (this.items().length === 0 || this.menuOpen()) return;
|
||||
if (ev.key === 'ArrowDown') { ev.preventDefault(); this.next(); }
|
||||
if (ev.key === 'ArrowUp') { ev.preventDefault(); this.prev(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user