fix(shorts): hover-chrome, swipe mobile garanti, avance auto fiabilisee
CI / build-and-test (push) Successful in 15m2s

Chrome auto-hide au hover desktop (2,5 s). Capteur tactile mobile : swipe garanti (l'iframe mangeait les touchers), tap = play/pause YT ou 6 s d'acces direct au lecteur sinon. Fleche retour accueil mobile, cadre quasi plein ecran. Avance auto : handshake YT listening (les evenements player n'arrivaient jamais), onStateChange canonique, retry borne anti-prefetch. Docs 9.9.
This commit is contained in:
2026-09-30 12:21:15 -04:00
parent 8f100d2b78
commit 3e1980283a
4 changed files with 198 additions and 25 deletions
@@ -1,4 +1,6 @@
<div class="shorts-stage relative flex min-h-[calc(var(--app-vh,100dvh)-var(--header-offset,0px))] w-full flex-col items-center overflow-hidden bg-black" (click)="closeMenu()">
<div class="shorts-stage relative flex min-h-[calc(var(--app-vh,100dvh)-var(--header-offset,0px))] w-full flex-col items-center overflow-hidden bg-black"
[class.shorts-chrome-hidden]="!chromeVisible()"
(click)="closeMenu()" (mousemove)="pokeChrome()">
<!-- Fond d'ambiance : vignette du short courant, floutée (façon YouTube). -->
<div class="shorts-ambient" aria-hidden="true">
@if (current()?.thumbnail) {
@@ -6,8 +8,15 @@
}
</div>
<!-- Retour accueil (mobile plein écran : la vidéo occupe tout, pas de header visible) -->
<a routerLink="/"
class="absolute top-2 left-2 z-20 flex h-11 w-11 items-center justify-center rounded-full bg-black/60 text-white hover:bg-black/80 sm:hidden"
title="Retour à l'accueil NewTube" aria-label="Retour à l'accueil NewTube" (click)="$event.stopPropagation()">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 12H5m7-7l-7 7 7 7"/></svg>
</a>
<!-- Sélecteur : Pour toi + fournisseurs -->
<div class="scroll-rail no-scrollbar relative z-10 flex w-full max-w-full items-center justify-start gap-2 overflow-x-auto px-3 pt-3 sm:justify-center" role="tablist" aria-label="Fournisseur des Shorts" (click)="$event.stopPropagation()">
<div class="scroll-rail no-scrollbar shorts-chrome relative z-10 flex w-full max-w-full items-center justify-start gap-2 overflow-x-auto px-3 pt-3 sm:justify-center" role="tablist" aria-label="Fournisseur des Shorts" (click)="$event.stopPropagation()">
<button (click)="toggleForYou()"
[attr.aria-pressed]="forYou()"
class="chip shrink-0 px-3 py-2 rounded-full text-[13px] border transition-colors min-h-[44px]"
@@ -29,7 +38,7 @@
(wheel)="onWheel($event)" (touchstart)="onTouchStart($event)" (touchend)="onTouchEnd($event)">
<!-- Flèche précédent (bureau, façon YouTube) -->
<button type="button" (click)="prev(); $event.stopPropagation()" [disabled]="!canPrev()"
class="chip hidden sm:flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:opacity-30"
class="shorts-chrome chip hidden sm:flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:opacity-30"
aria-label="Short précédent">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M7 14l5-5 5 5H7z"/></svg>
</button>
@@ -55,8 +64,23 @@
}
@if (current(); as v) {
<!-- Capteur tactile (mobile uniquement) : l'iframe mange les
touchers, donc le swipe up/down passerait à la trappe. Cette
couche transparente capte swipe (navigue) et tap (play/pause
YouTube, ou accès direct au lecteur 6 s sinon). `touch-action`
via CSS : le navigateur ne scrolle/zoome pas, nos handlers
possèdent le geste. En mode passthrough, elle s'efface
(les boutons du fournisseur deviennent touchables). -->
<div class="shorts-gesture absolute inset-0 z-[1] sm:hidden"
[class.pointer-events-none]="passthrough()"
aria-hidden="true"></div>
@if (passthroughHint()) {
<div class="absolute left-1/2 top-14 z-20 -translate-x-1/2 whitespace-nowrap px-3 py-1.5 rounded-full bg-black/75 text-white text-xs" role="status">Commandes du lecteur accessibles</div>
}
<!-- Haut droite : plein écran, partage rapide, menu ⋯ -->
<div class="absolute top-2 right-2 flex items-center gap-1.5" (click)="$event.stopPropagation()">
<div class="shorts-chrome absolute top-2 right-2 z-10 flex items-center gap-1.5" (click)="$event.stopPropagation()">
<button type="button" (click)="toggleFullscreen()" class="flex h-10 w-10 items-center justify-center rounded-full bg-black/60 text-white hover:bg-black/80" [title]="isFullscreen() ? 'Quitter le plein écran' : 'Plein écran'" aria-label="Plein écran">
@if (isFullscreen()) {
<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" aria-hidden="true"><path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/></svg>
@@ -86,7 +110,7 @@
</div>
<!-- Rail d'actions OVERLAY façon YouTube (dans le cadre, comme sur mobile natif) -->
<div class="absolute right-1.5 sm:right-2.5 bottom-32 sm:bottom-36 flex flex-col items-center gap-2 sm:gap-2.5" (click)="$event.stopPropagation()">
<div class="shorts-chrome absolute right-1.5 sm:right-2.5 bottom-32 sm:bottom-36 z-10 flex flex-col items-center gap-2 sm:gap-2.5" (click)="$event.stopPropagation()">
<div class="flex flex-col items-center">
<button type="button" (click)="toggleLike()" [disabled]="!isLoggedIn() || likeBusy()"
class="flex h-12 w-12 items-center justify-center rounded-full bg-black/55 text-white hover:bg-black/75 disabled:opacity-40"
@@ -126,7 +150,7 @@
</div>
<!-- Bas : avatar + titre + méta + fraîcheur + S'abonner (safe-area incluse) -->
<div class="shorts-meta pointer-events-none absolute left-0 right-0 bottom-0 p-3 sm:p-4 text-white bg-gradient-to-t from-black/85 via-black/35 to-transparent">
<div class="shorts-meta shorts-chrome pointer-events-none absolute left-0 right-0 bottom-0 z-10 p-3 sm:p-4 text-white bg-gradient-to-t from-black/85 via-black/35 to-transparent">
<div class="flex items-end gap-2.5 text-sm" (click)="$event.stopPropagation()">
@if (v.uploaderAvatar) {
<img [src]="v.uploaderAvatar" [alt]="v.uploaderName" class="h-10 w-10 shrink-0 rounded-full object-cover ring-2 ring-white/40" loading="lazy" />
@@ -180,7 +204,7 @@
<!-- Flèche suivant (bureau, façon YouTube) -->
<button type="button" (click)="next(); $event.stopPropagation()" [disabled]="!canNext()"
class="chip hidden sm:flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:opacity-30"
class="shorts-chrome chip hidden sm:flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:opacity-30"
aria-label="Short suivant">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M7 10l5 5 5-5H7z"/></svg>
</button>