chore: update Angular build cache and TypeScript definitions
This commit is contained in:
@@ -1,6 +1,92 @@
|
||||
<div class="container mx-auto p-4 sm:p-6">
|
||||
<h2 class="text-3xl font-bold mb-6 text-slate-100 border-l-4 border-red-500 pl-4">Vidéos que vous aimez</h2>
|
||||
<div class="container mx-auto p-4 sm:p-6 max-w-6xl">
|
||||
<h2 class="text-3xl font-bold mb-6 text-slate-100 border-l-4 border-red-500 pl-4 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-7 w-7 mr-2 text-red-400">
|
||||
<path d="M12 21s-6.716-4.248-9.193-6.725A6 6 0 0 1 12 5.414 6 6 0 0 1 21.193 14.275C18.716 16.752 12 21 12 21z" />
|
||||
</svg>
|
||||
Liked videos
|
||||
</h2>
|
||||
|
||||
<div class="bg-slate-800/50 rounded-lg p-6 border border-slate-700">
|
||||
<p class="text-slate-300">Ici apparaîtront vos vidéos aimées (tous providers). Fonctionnalité à venir.</p>
|
||||
<!-- Barre de recherche -->
|
||||
<div class="mb-4 relative">
|
||||
<input
|
||||
type="text"
|
||||
[ngModel]="searchQuery()"
|
||||
(ngModelChange)="onSearchChange($event)"
|
||||
class="block w-full pl-10 pr-10 py-2 border border-slate-600 rounded-lg bg-slate-700 text-slate-100 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition duration-150"
|
||||
placeholder="Rechercher dans les vidéos aimées..."
|
||||
/>
|
||||
<svg class="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
<button
|
||||
*ngIf="searchQuery()"
|
||||
(click)="clearSearch()"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 px-2 py-1 text-xs rounded bg-slate-600 hover:bg-slate-500 text-white"
|
||||
aria-label="Effacer la recherche"
|
||||
>
|
||||
Effacer
|
||||
</button>
|
||||
</div>
|
||||
@if (loading()) {
|
||||
<div class="text-slate-400">Chargement…</div>
|
||||
} @else if (error(); as err) {
|
||||
<div class="text-red-300">{{ err }}</div>
|
||||
} @else if (items().length === 0) {
|
||||
<div class="text-slate-400">Aucune vidéo aimée pour le moment.</div>
|
||||
} @else {
|
||||
<ul class="space-y-3">
|
||||
@for (it of items(); track it.provider + ':' + it.video_id) {
|
||||
<li class="group bg-slate-700/50 hover:bg-slate-700/80 rounded-lg overflow-hidden transition-all">
|
||||
<a [routerLink]="['/watch', it.video_id]" [queryParams]="{ p: it.provider }" class="block p-4 hover:no-underline">
|
||||
<div class="flex items-center">
|
||||
<!-- Miniature de la vidéo -->
|
||||
<div class="relative flex-shrink-0 w-24 h-16 bg-slate-800 rounded overflow-hidden mr-4">
|
||||
@if (it.thumbnail) {
|
||||
<img [src]="it.thumbnail" alt="" class="w-full h-full object-cover" />
|
||||
} @else {
|
||||
<div class="w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-700 to-slate-800">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded border text-xs"
|
||||
[ngStyle]="getProviderColors(it.provider)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
</svg>
|
||||
{{ getProviderDisplayName(it.provider) }}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Détails de la vidéo -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-slate-100 font-medium group-hover:text-red-400 truncate">
|
||||
{{ it.title || (it.provider + ':' + it.video_id) }}
|
||||
</div>
|
||||
<div class="text-xs text-slate-400 mt-1">
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded border"
|
||||
[ngStyle]="getProviderColors(it.provider)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
</svg>
|
||||
{{ getProviderDisplayName(it.provider) }}
|
||||
</span>
|
||||
@if (it.last_watched_at) {
|
||||
<span>Vu le {{ it.last_watched_at | date:'short' }}</span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Flèche -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 flex-shrink-0 text-slate-400 group-hover:text-slate-200 ml-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,93 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { LikesService, LikedVideoItem } from '../../../services/likes.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-library-liked',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, RouterLink, FormsModule],
|
||||
templateUrl: './liked.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class LikedComponent { }
|
||||
export class LikedComponent {
|
||||
private likes = inject(LikesService);
|
||||
|
||||
loading = signal<boolean>(true);
|
||||
error = signal<string | null>(null);
|
||||
items = signal<LikedVideoItem[]>([]);
|
||||
searchQuery = signal<string>('');
|
||||
|
||||
constructor() {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh(q?: string): void {
|
||||
this.loading.set(true);
|
||||
this.error.set(null);
|
||||
this.likes.list(200, q).subscribe({
|
||||
next: (rows) => {
|
||||
this.items.set(rows || []);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: (err) => {
|
||||
const msg = err?.error?.error || err?.message || 'Erreur lors du chargement des vidéos aimées';
|
||||
this.error.set(String(msg));
|
||||
this.loading.set(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSearchChange(value: string) {
|
||||
const q = (value || '').trim();
|
||||
this.searchQuery.set(value);
|
||||
this.refresh(q || undefined);
|
||||
}
|
||||
|
||||
clearSearch() {
|
||||
this.searchQuery.set('');
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
// --- Provider helpers (match History/Header badges)
|
||||
private formatProviderName(providerId: string): string {
|
||||
const map: Record<string, string> = {
|
||||
youtube: 'YouTube',
|
||||
vimeo: 'Vimeo',
|
||||
dailymotion: 'Dailymotion',
|
||||
peertube: 'PeerTube',
|
||||
rumble: 'Rumble',
|
||||
twitch: 'Twitch',
|
||||
odysee: 'Odysee',
|
||||
};
|
||||
return map[(providerId || '').toLowerCase()] || providerId;
|
||||
}
|
||||
|
||||
getProviderDisplayName(providerId: string | null | undefined): string {
|
||||
if (!providerId) return '';
|
||||
return this.formatProviderName(providerId);
|
||||
}
|
||||
|
||||
getProviderColors(providerId: string | null | undefined): { [key: string]: string } {
|
||||
const id = (providerId || '').toLowerCase();
|
||||
switch (id) {
|
||||
case 'youtube':
|
||||
return { backgroundColor: 'rgba(220, 38, 38, 0.15)', color: 'rgb(248, 113, 113)', borderColor: 'rgba(239, 68, 68, 0.3)' };
|
||||
case 'vimeo':
|
||||
return { backgroundColor: 'rgba(2, 132, 199, 0.15)', color: 'rgb(125, 211, 252)', borderColor: 'rgba(14, 165, 233, 0.3)' };
|
||||
case 'dailymotion':
|
||||
return { backgroundColor: 'rgba(37, 99, 235, 0.15)', color: 'rgb(147, 197, 253)', borderColor: 'rgba(59, 130, 246, 0.3)' };
|
||||
case 'peertube':
|
||||
return { backgroundColor: 'rgba(245, 158, 11, 0.15)', color: 'rgb(252, 211, 77)', borderColor: 'rgba(245, 158, 11, 0.3)' };
|
||||
case 'rumble':
|
||||
return { backgroundColor: 'rgba(22, 163, 74, 0.15)', color: 'rgb(134, 239, 172)', borderColor: 'rgba(34, 197, 94, 0.3)' };
|
||||
case 'twitch':
|
||||
return { backgroundColor: 'rgba(168, 85, 247, 0.15)', color: 'rgb(216, 180, 254)', borderColor: 'rgba(168, 85, 247, 0.3)' };
|
||||
case 'odysee':
|
||||
return { backgroundColor: 'rgba(236, 72, 153, 0.15)', color: 'rgb(251, 207, 232)', borderColor: 'rgba(236, 72, 153, 0.3)' };
|
||||
default:
|
||||
return { backgroundColor: 'rgba(30, 41, 59, 0.8)', color: 'rgb(203, 213, 225)', borderColor: 'rgb(51, 65, 85)' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user