feat(watch,themes): transcript en sidebar, seek fiable, player instantane, bande themes repliable
CI / build-and-test (push) Failing after 8m19s
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:
@@ -1,4 +1,19 @@
|
||||
<nav class="sticky top-16 left-0 right-0 z-40 w-full relative"
|
||||
@if (collapsed()) {
|
||||
<!-- Barre repliée : fine, rouvrable à tout moment -->
|
||||
<div class="sticky top-16 left-0 right-0 z-40 flex w-full items-center gap-2 border-b border-slate-700/60 bg-slate-800/60 px-3 py-1 backdrop-blur-sm">
|
||||
<span class="text-xs font-medium text-slate-400">{{ 'themes.title' | t : 'Thèmes' }}</span>
|
||||
@if (activeThemeLabel(); as label) {
|
||||
<span class="rounded-full border border-red-500/60 bg-slate-100/10 px-2 py-0.5 text-xs text-white">{{ label }}</span>
|
||||
}
|
||||
<button type="button" (click)="toggleCollapsed()" [attr.aria-expanded]="false" aria-controls="themes-bar"
|
||||
[title]="'themes.show' | t : 'Afficher la bande des thèmes'"
|
||||
class="ml-auto inline-flex items-center gap-1 rounded-full px-2 py-1 text-xs font-semibold text-slate-300 transition hover:bg-slate-700 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500">
|
||||
<span>{{ 'themes.show' | t : 'Afficher' }}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
} @else {
|
||||
<nav id="themes-bar" class="sticky top-16 left-0 right-0 z-40 w-full relative"
|
||||
[ngClass]="{
|
||||
'bg-slate-800 border-b border-slate-700': isDarkTheme(),
|
||||
'bg-slate-900 border-b border-slate-800': isBlackTheme(),
|
||||
@@ -24,6 +39,18 @@
|
||||
»
|
||||
</button>
|
||||
|
||||
<!-- Replier la bande -->
|
||||
<button type="button" (click)="toggleCollapsed()" [attr.aria-expanded]="true" aria-controls="themes-bar"
|
||||
[title]="'themes.hide' | t : 'Masquer la bande des thèmes'"
|
||||
class="absolute right-12 top-1/2 z-10 hidden h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full shadow transition focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 md:flex"
|
||||
[ngClass]="{
|
||||
'bg-white/90 border border-slate-300 text-slate-700 hover:bg-slate-100': isLightTheme(),
|
||||
'bg-slate-800/90 border border-slate-700 text-slate-200 hover:bg-slate-700': isDarkTheme() || isBlackTheme() || isBlueTheme()
|
||||
}"
|
||||
aria-label="Masquer la bande des thèmes">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z" clip-rule="evenodd" /></svg>
|
||||
</button>
|
||||
|
||||
<div class="w-full overflow-x-auto no-scrollbar" #scroll (wheel)="onWheel($event)">
|
||||
<ul role="tablist" aria-label="Themes" class="flex gap-2 px-12 py-2 min-w-max items-center">
|
||||
<li *ngFor="let t of displayedThemes(); let i = index" class="shrink-0">
|
||||
@@ -45,6 +72,13 @@
|
||||
<span>{{ themesSvc.i18nLabel(t) }}</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="shrink-0 md:hidden">
|
||||
<button type="button" (click)="toggleCollapsed()"
|
||||
class="px-3 py-1.5 rounded-full text-xs font-semibold text-slate-400 border border-slate-700 whitespace-nowrap">
|
||||
{{ 'themes.hide' | t : 'Masquer' }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user