Nouvelle liste dans la section Vous de la barre latérale, avec un bouton
horloge a cote du coeur sur toutes les cartes (accueil, themes, provider-
themes, recherche).
- db : les 4 fonctions de listes (like/unlike/isLiked/list) prennent un
paramètre `tag` — la table `tags` sert déjà de mot-clés génériques, donc
zéro migration.
- api : les 4 routes likes sont générées par registerVideoTagRoutes(prefix,
tagName) ; /api/user/watch-later = même fabrique, même enrichissement
yt-dlp, même middleware cookie-aware. Entrée OpenAPI ajoutée.
- front : LikesService prend un VideoTag, like-button un @Input() list
(icône horloge, ambre quand enregistré, libellés a11y dédiés) — un seul
composant pour les deux boutons, pas de copie.
- cartes de recherche : la grille partagée n'avait AUCUN bouton ; cœur +
horloge ajoutés, masqués sur les lives et cartes chaîne (coin bas-gauche
déjà occupé par le compteur de spectateurs / pas des vidéos).
- route /library/watch-later = LikedComponent via data.list (titre, icône,
placeholder et état vide pilotés par la route), clés nav.watchLater FR/EN.
Tests : npm run test:api 41/41 (nouveau test watch-later : ajout, statut,
indépendance vis-à-vis des likes, liste, retrait, 400, 401) + 21 autres
suites vertes. Build OK, instance locale 4200 rebuildée. Sondage Playwright
desktop+mobile : 12/14 (2 faux positifs du sondage : accordéon replié sur
une route hors /library, 3×401 console pendant la phase déconnectée).
- 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
Le header était en grid-cols-[auto_1fr_auto] avec une barre de recherche
non-wrappable (7 chips + input + 2 boutons, aucun min-w-0) : ~1000px de
largeur intrinsèque dans un viewport de 375px. Toutes les routes
débordaient horizontalement et les boutons Connexion/Inscription partaient
hors écran.
Socle
- --header-h / --header-offset / --app-vh centralisent la métrique du
header : supprime les top-16 codés en dur (channel-tabs était en top-0 et
glissait sous le header au scroll).
- Safe-area iOS, viewport-fit=cover, color-scheme/theme-color.
- dvh partout (100vh > hauteur visible sur iOS), overflow-x: clip au lieu de
hidden (hidden cassait silencieusement tous les sticky).
- Cible tactile 44px sur pointeur grossier, skip link, focus-ring clavier,
scroll-rail pour les tab strips.
Header
- Barre mobile (burger, logo, recherche, menu ⋮) + barre desktop inchangée.
- Le menu ⋮ expose ce qui disparaissait : bande des thèmes, préférences,
historique, favoris, téléchargements, thème, connexion/inscription.
- Recherche en feuille sous le header avec focus automatique.
- Échap / clic extérieur / navigation ferment les panneaux transitoires.
Drawer
- Partait à inset-y-0 : les 56 premiers px du menu étaient derrière le
header. Descend sous le header, bouton fermer intégré, verrouille le
scroll, se ferme à Échap.
Barre de recherche
- Chips masquées sous lg, remplacées par un bouton résumé qui ouvre le
sélecteur de fournisseurs. Suggestions en dvh, menu Ctrl+K plein écran
sur mobile.
Pages
- Shorts : cadre 9:16 contraint par dvh ET vw (il débordait en paysage),
Préc./Suiv. qui étaient hors du conteneur height-capped.
- Watch : barre d'actions qui wrappe, mode cinéma en opacity-0 group-hover
donc invisible au doigt, thumbnails fluides, playsinline sur les iframes.
- Historique, thèmes, chaîne, playlists, préférences, sessions : rails
swipables, min-w-0, truncate, en-têtes qui wrappent.
Vérifié : audit navigateur (CDP) sur 17 routes x 7 largeurs (320→1440),
zéro débordement horizontal ; 19 tests d'interaction mobile ; suites de
tests du dépôt vertes (api 40/40, transcript 27/27, search, suggest,
playlists, preferences, subscriptions, highlight, telemetry).
- likes + playlists: authMiddlewareCookieAware (cookies + Bearer) au lieu
du Bearer seul -> corrige 401 Unauthorized meme connecte (creation
playlist, ajout video, bouton J'aime)
- add-to-playlist/like-button/search-box: retire HttpClientModule local
qui court-circuitait les intercepteurs fonctionnels
- intercepteur: refresh+retry sur 401 meme sans token en memoire (F5)
- UserService: apiBase() au lieu de /proxy/api en dur (prod :4000)
- J'aime: envoie titre/miniature, erreur visible au lieu de bouton mort
- download: seaux separes (lectures 120/min, ecritures 30/min, formats
30/min) + reponses limiter en JSON rate_limited + Retry-After
- formats: cache memoire 10 min + ytdlpNetOpts + retry front avec backoff
- polling allege (downloads 5s, suivi job 4s, 429 transitoire non fatal)
- erreurs FR precises (http-error.util): 401/403/404/410/429/quota/500
avec compte a rebours + bouton Reessayer