feat(watch,themes): transcript en sidebar, seek fiable, player instantane, bande themes repliable
CI / build-and-test (push) Failing after 8m19s

- watch: panneau transcription deplace en tete de sidebar au-dessus de
  A suivre (+ scroll auto a l'ouverture sur mobile)
- seek transcript: seekTo postMessage YouTube (sans rechargement),
  time= Twitch VOD, t= Odysee, start= Rumble (start/dm/pt existants)
- watch: lecteur monte des les parametres de route (embed natif),
  squelettes partiels pendant /details au lieu du plein ecran
- themes-nav: bouton replier/deplier persistant (localStorage),
  barre fine avec theme actif quand repliee, cles i18n FR/EN
This commit is contained in:
2026-09-26 09:56:04 -04:00
parent d5ceab7115
commit a70d7b9797
5 changed files with 694 additions and 508 deletions
+24 -1
View File
@@ -2,12 +2,15 @@ import { ChangeDetectionStrategy, Component, ElementRef, QueryList, ViewChild, V
import { CommonModule } from '@angular/common';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { ThemesService } from '../../services/themes.service';
import { TranslatePipe } from '../../pipes/translate.pipe';
const THEMES_BAR_COLLAPSED_KEY = 'newtube.themesBarCollapsed';
@Component({
selector: 'app-themes-nav',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule],
imports: [CommonModule, TranslatePipe],
templateUrl: './themes-nav.component.html'
})
export class ThemesNavComponent implements OnDestroy {
@@ -19,6 +22,26 @@ export class ThemesNavComponent implements OnDestroy {
activeSlug = this.themesSvc.activeSlug;
displayedThemes = () => this.themes();
/** Bande repliée/dépliée (persistée) : la barre reste masquable en permanence. */
collapsed = signal<boolean>((() => {
try { return localStorage.getItem(THEMES_BAR_COLLAPSED_KEY) === '1'; } catch { return false; }
})());
toggleCollapsed(): void {
const next = !this.collapsed();
this.collapsed.set(next);
try { localStorage.setItem(THEMES_BAR_COLLAPSED_KEY, next ? '1' : '0'); } catch {}
}
activeThemeLabel(): string {
try {
const slug = this.activeSlug();
const found = this.themes().find((t) => t.slug === slug);
if (found) return this.themesSvc.i18nLabel(found);
} catch {}
return '';
}
@ViewChildren('pill', { read: ElementRef }) pills!: QueryList<ElementRef<HTMLButtonElement>>;
@ViewChild('scroll', { static: false }) scrollRef?: ElementRef<HTMLDivElement>;