diff --git a/docs/plan-phases-catalogue-classification.md b/docs/plan-phases-catalogue-classification.md index 836ff4e..674a5bd 100644 --- a/docs/plan-phases-catalogue-classification.md +++ b/docs/plan-phases-catalogue-classification.md @@ -486,6 +486,8 @@ La table est **additive**. Le Phase 5.3 (LEFT JOIN) est le seul changement de le - [x] Son et lecture par provider : son par défaut (YT/OD/DM/PT), clips Twitch en muet forcé (pas d'API de volume sur l'embed) ; Odysee démarre muet (pas de rectangle « tap to unmute ») et ne passe au son que sur clic explicite du bouton Son (le geste autorise l'autoplay sonore) ; nudge `playVideo` YouTube si l'autoplay a calé. - [x] Avance auto en fin de vidéo tous providers : `playerState` YouTube (0 = fin → suivant, 2 = pause → minuteur désarmé, 1 = reprise → réarmé) + minuteur générique sur durée connue ou estimée (clip Twitch = 60 s, sinon plafond Short 90 s) + 2,5 s de grâce, ignoré si l'onglet est caché. - [x] Anti-Forbidden Dailymotion : `allow_embed` demandé côté serveur → `embeddable` → `raw.allowEmbed`, le garde `isPlayable` existant exclut ces vidéos avant affichage (même garde que le chemin historique). +- [x] Chrome auto-hide au hover (desktop, 2,5 s d'immobilité) ; capteur tactile mobile (l'iframe mange les touchers) : swipe = navigation garantie, tap = play/pause YouTube (API iframe) ou 6 s d'accès direct au lecteur sinon (les boutons du fournisseur restent atteignables) ; flèche retour accueil en haut à gauche sur mobile ; cadre quasi plein écran (`--shorts-chrome: 5,5rem`). +- [x] Avance auto fiabilisée : handshake `listening` YouTube SANS LEQUEL aucun événement player n'arrive (progression + fin mortes), `onStateChange` canonique, réessais bornés quand `next()` est absorbé par un pré-chargement en cours. --- diff --git a/index.css b/index.css index bbbea5c..1845a0c 100644 --- a/index.css +++ b/index.css @@ -507,9 +507,10 @@ body { } } @media (max-width: 767px) { - /* Mobile : cadre quasi plein écran (seuls les chips + marges sont réservés). */ + /* Mobile : quasi plein écran (seule la rangée de chips est réservée : + la flèche retour et le chrome vivent EN OVERLAY dans le cadre). */ .shorts-frame { - --shorts-chrome: 8.5rem; + --shorts-chrome: 5.5rem; } } @@ -547,6 +548,30 @@ body { padding-bottom: max(0.75rem, env(safe-area-inset-bottom)); } +/* --- Shorts : chrome auto-hide + capteur tactile ---------------------------- */ +/* Desktop : le chrome (pastilles, boutons, rail, méta) s'efface après 2,5 s + d'immobilité de la souris et revient au moindre mouvement (façon YouTube). + Sur tactile, `mousemove` ne tire presque jamais : tout reste visible. */ +.shorts-chrome { + transition: opacity 0.25s ease; +} +.shorts-chrome-hidden .shorts-chrome { + opacity: 0; + pointer-events: none; +} +@media (prefers-reduced-motion: reduce) { + .shorts-chrome { + transition: none; + } +} +/* Capteur tactile mobile : couche transparente AU-DESSUS de l'iframe (qui + mangerait les touchers) mais SOUS le chrome. `touch-action: none` donne le + geste à nos handlers (swipe = navigation, tap = play/pause ou accès + lecteur) au lieu de scroller/zoomer la page. */ +.shorts-gesture { + touch-action: none; +} + /* --- Drawer / overlay plumbing -------------------------------------------- */ /* Applied to
while a full-screen drawer or modal owns the viewport. Note: deliberately NOT `touch-action: none` — touch-action is intersected up diff --git a/src/components/shorts/watch-short.component.html b/src/components/shorts/watch-short.component.html index ab4746e..92c9843 100644 --- a/src/components/shorts/watch-short.component.html +++ b/src/components/shorts/watch-short.component.html @@ -1,4 +1,6 @@ -