feat(menu-lecteur): refonte UI/UX professionnelle du menu FAB
CI / build-and-test (push) Successful in 14m57s

- FAB : pastille verre depoli 40px + icone sliders (standard options)
- Panneau : en-tete (titre + fermer), verre depoli, ombre profonde, coins arrondis
- Animations ouverture/fermeture (fondu + slide + scale), fermeture Echap + clic exterieur
- Items : hover/active/focus, icones teintees, sections + separateurs raffinés
- Playlist : modale rendue HORS du panneau (backdrop-filter piegeait position:fixed)
This commit is contained in:
2026-10-01 07:20:26 -04:00
parent 01e0671de9
commit 7ceec59841
5 changed files with 182 additions and 29 deletions
@@ -4,11 +4,11 @@ import { CommonModule } from '@angular/common';
/**
* Bouton-menu flottant (FAB) partagé entre /watch et /shorts.
*
* Pastille circulaire translucide en haut à gauche du lecteur, façon
* commandes overlay des players YouTube/Dailymotion : elle ouvre un panneau
* déroulant qui reçoit son contenu par projection (`ng-content`) — chaque page
* fournit ses propres options, la coque (position, style, open/close, clic
* extérieur) est identique partout.
* Pastille circulaire translucide en haut à gauche du lecteur (façon commandes
* overlay des players YouTube/Dailymotion) qui ouvre un panneau déroulant en
* « verre dépoli » avec en-tête (titre + fermeture) et contenu projeté via
* `ng-content`. Animation d'ouverture/fermeture fluide (fondu + glissement +
* échelle), fermeture au clic extérieur et à Échap.
*
* Usage : `<app-player-menu [(open)]="menuOpen"> …items… </app-player-menu>`
* dans un conteneur `position: relative` (le `:host` se place en absolu).
@@ -22,20 +22,29 @@ import { CommonModule } from '@angular/common';
<button type="button"
(click)="toggle(); $event.stopPropagation()"
[attr.aria-expanded]="open"
aria-haspopup="menu"
aria-label="Menu"
title="Menu"
class="flex h-9 w-9 items-center justify-center rounded-full bg-black/50 text-white ring-1 ring-white/15 backdrop-blur-md transition hover:bg-black/70 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
<path d="M4 6h16M4 12h16M4 18h16"/>
aria-haspopup="dialog"
[attr.aria-label]="title"
[title]="title"
class="pm-fab" [class.pm-fab-open]="open">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/>
<line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/>
<line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/>
<line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/>
</svg>
</button>
@if (open) {
<div class="absolute left-0 top-11 max-h-[70vh] w-64 overflow-y-auto overscroll-contain rounded-xl bg-black/70 p-1.5 shadow-2xl ring-1 ring-white/10 backdrop-blur-xl"
role="menu" (click)="$event.stopPropagation()">
<div class="pm-panel" [class.pm-panel-open]="open" role="dialog" [attr.aria-label]="title" (click)="$event.stopPropagation()">
<div class="pm-panel-header">
<span class="pm-panel-title">{{ title }}</span>
<button type="button" class="pm-panel-close" (click)="close()" aria-label="Fermer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6L6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="pm-panel-body">
<ng-content></ng-content>
</div>
}
</div>
`,
styles: [
`:host { position: absolute; top: 0.5rem; left: 0.5rem; z-index: 30; display: block; }`,
@@ -43,6 +52,7 @@ import { CommonModule } from '@angular/common';
})
export class PlayerMenuComponent {
@Input() open = false;
@Input() title = 'Options';
@Output() openChange = new EventEmitter<boolean>();
constructor(private el: ElementRef<HTMLElement>) {}
@@ -62,4 +72,9 @@ export class PlayerMenuComponent {
if (target && this.el.nativeElement.contains(target)) return;
this.close();
}
@HostListener('document:keydown.escape')
onEscape(): void {
this.close();
}
}