feat(lecteur): menu FAB partage /watch et /shorts
CI / build-and-test (push) Successful in 14m48s

- PlayerMenuComponent : FAB circulaire translucide (haut-gauche) + panneau
  deroulant, commun aux deux pages (position, style, open/close, clic exterieur)
- /shorts : consolidation de tous les boutons (fournisseurs, langue, actions)
  dans le menu FAB ; suppression du rail a droite et de la rangee du haut
- /watch : actions (cinema, qualite, j'aime, playlist, transcription,
  telechargement, partage, ouvrir) deplacees dans le menu FAB
- AddToPlaylistComponent : variante menuItem pour s'integrer au menu
- styles .pm-item/.pm-sep/.pm-section-label dans index.css
This commit is contained in:
2026-09-30 22:50:46 -04:00
parent 2bcc7321aa
commit 01e0671de9
7 changed files with 301 additions and 240 deletions
@@ -0,0 +1,65 @@
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core';
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.
*
* Usage : `<app-player-menu [(open)]="menuOpen"> …items… </app-player-menu>`
* dans un conteneur `position: relative` (le `:host` se place en absolu).
*/
@Component({
selector: 'app-player-menu',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule],
template: `
<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"/>
</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()">
<ng-content></ng-content>
</div>
}
`,
styles: [
`:host { position: absolute; top: 0.5rem; left: 0.5rem; z-index: 30; display: block; }`,
],
})
export class PlayerMenuComponent {
@Input() open = false;
@Output() openChange = new EventEmitter<boolean>();
constructor(private el: ElementRef<HTMLElement>) {}
toggle(): void {
this.openChange.emit(!this.open);
}
close(): void {
if (this.open) this.openChange.emit(false);
}
@HostListener('document:click', ['$event'])
onDocumentClick(event: Event): void {
if (!this.open) return;
const target = event.target as Node | null;
if (target && this.el.nativeElement.contains(target)) return;
this.close();
}
}