fix(search): le repli des rails ne masque plus la grille + logos de marque
CI / build-and-test (push) Successful in 14m9s
CI / build-and-test (push) Successful in 14m9s
Bug : le @if (hasQuery()) englobant toute la section basse avait ete passe en @if (hasQuery() && railsOpen()), donc replier le rail masquait aussi la grille, le loader et le sentinel de scroll infini. Seul le panneau ' types + sources ' est desormais imbrique dans @if (railsOpen()). Logos : les formes geometriques approximees sont remplacees par les six marques officielles (traces et couleurs Simple Icons, CC0-1.0), stockees en local pour eviter toute dependance CDN a l'execution. Dailymotion garde le bleu de la marque (#0066DC) plutot que le #0A0A0A de Simple Icons, invisible sur fond sombre. L'etat actif/masque n'est plus porte par la couleur de l'icone (fixe par marque) mais par le bouton : fond plein + logo couleur, ou fond transparent + logo grayscale 40%.
This commit is contained in:
@@ -68,87 +68,94 @@
|
||||
<p class="mt-2 text-slate-400">{{ 'search.hint' | t }}</p>
|
||||
}
|
||||
|
||||
@if (hasQuery() && railsOpen()) {
|
||||
@if (hasQuery()) {
|
||||
<!-- ============ Rail de filtres (types + sources) ============ -->
|
||||
<div id="search-rails" class="mt-2.5 rounded-xl border border-slate-700 bg-slate-800/50 p-1.5">
|
||||
<!-- Types de contenu : sélection unique, façon YouTube.
|
||||
Le rail défile horizontalement (scrollbar masqué) : le fade de droite
|
||||
signale qu'il reste des pastilles hors champ. -->
|
||||
<div class="scroll-rail-fade">
|
||||
<div class="scroll-rail no-scrollbar flex items-center gap-1.5" role="group" aria-label="Filtrer par type de contenu">
|
||||
<button type="button" (click)="setTypePill('all')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'all' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'all'">
|
||||
Tout <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().all) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().live > 0 || typePill() === 'live'" (click)="setTypePill('live')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'live' ? 'border border-transparent bg-purple-600 text-white' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'live'">
|
||||
Directs <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().live) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().video > 0 || typePill() === 'video'" (click)="setTypePill('video')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'video' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'video'">
|
||||
Vidéos <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().video) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().clip > 0 || typePill() === 'shorts'" (click)="setTypePill('shorts')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'shorts' ? 'border border-transparent bg-purple-600 text-white' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'shorts'">
|
||||
Clips <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().clip) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().channel > 0 || typePill() === 'channel'" (click)="setTypePill('channel')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'channel' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'channel'">
|
||||
Chaînes <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().channel) }}</span>
|
||||
</button>
|
||||
<!-- Repliable via l'icône œil : seule cette section disparaît, jamais la
|
||||
grille ni la pagination qui suivent. -->
|
||||
@if (railsOpen()) {
|
||||
<div id="search-rails" class="mt-2.5 rounded-xl border border-slate-700 bg-slate-800/50 p-1.5">
|
||||
<!-- Types de contenu : sélection unique, façon YouTube.
|
||||
Le rail défile horizontalement (scrollbar masqué) : le fade de droite
|
||||
signale qu'il reste des pastilles hors champ. -->
|
||||
<div class="scroll-rail-fade">
|
||||
<div class="scroll-rail no-scrollbar flex items-center gap-1.5" role="group" aria-label="Filtrer par type de contenu">
|
||||
<button type="button" (click)="setTypePill('all')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'all' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'all'">
|
||||
Tout <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().all) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().live > 0 || typePill() === 'live'" (click)="setTypePill('live')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'live' ? 'border border-transparent bg-purple-600 text-white' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'live'">
|
||||
Directs <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().live) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().video > 0 || typePill() === 'video'" (click)="setTypePill('video')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'video' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'video'">
|
||||
Vidéos <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().video) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().clip > 0 || typePill() === 'shorts'" (click)="setTypePill('shorts')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'shorts' ? 'border border-transparent bg-purple-600 text-white' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'shorts'">
|
||||
Clips <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().clip) }}</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="typeCounts().channel > 0 || typePill() === 'channel'" (click)="setTypePill('channel')"
|
||||
class="chip inline-flex h-8 shrink-0 items-center whitespace-nowrap rounded-full px-3 text-[13px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="typePill() === 'channel' ? 'border border-transparent bg-slate-200 text-slate-900' : 'border border-slate-700 bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
[attr.aria-pressed]="typePill() === 'channel'">
|
||||
Chaînes <span class="ml-1.5 text-[11px] tabular-nums opacity-60">{{ countLabel(typeCounts().channel) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-1.5 h-px bg-slate-700"></div>
|
||||
<div class="my-1.5 h-px bg-slate-700"></div>
|
||||
|
||||
<!-- Sources : bascules d'affichage. Boutons icône seule — la marque
|
||||
hérite de la couleur du bouton, donc l'état actif / masqué se lit
|
||||
sans pastille supplémentaire. Le libellé et le compte passent par
|
||||
`title` / `aria-label`. -->
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="shrink-0 pl-2 text-[11px] font-medium uppercase tracking-wide text-slate-400">Sources</span>
|
||||
<div class="scroll-rail-fade min-w-0 flex-1">
|
||||
<div class="scroll-rail no-scrollbar flex items-center gap-1.5" role="group" aria-label="Afficher ou masquer une source">
|
||||
<!-- Sources : bascules d'affichage. Boutons icône seule — la marque
|
||||
hérite de la couleur du bouton, donc l'état actif / masqué se lit
|
||||
sans pastille supplémentaire. Le libellé et le compte passent par
|
||||
`title` / `aria-label`. -->
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="shrink-0 pl-2 text-[11px] font-medium uppercase tracking-wide text-slate-400">Sources</span>
|
||||
<div class="scroll-rail-fade min-w-0 flex-1">
|
||||
<div class="scroll-rail no-scrollbar flex items-center gap-1.5" role="group" aria-label="Afficher ou masquer une source">
|
||||
@for (chip of providerChips(); track chip.id) {
|
||||
<button type="button" (click)="toggleProvider(chip.id)"
|
||||
class="chip inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]"
|
||||
[ngClass]="chip.visible ? 'border-slate-700 bg-slate-800 text-slate-200 hover:bg-slate-700' : 'border-slate-700 text-slate-400 hover:bg-slate-800'"
|
||||
[ngClass]="chip.visible ? 'border-slate-700 bg-slate-800 hover:bg-slate-700' : 'border-slate-700 hover:bg-slate-800'"
|
||||
[attr.aria-pressed]="chip.visible"
|
||||
[attr.aria-label]="(chip.visible ? 'Masquer ' : 'Afficher ') + chip.displayName + ' (' + chip.countLabel + ')'"
|
||||
[attr.title]="(chip.visible ? 'Masquer ' : 'Afficher ') + chip.displayName + ' — ' + chip.countLabel + ' résultat(s)'">
|
||||
<app-provider-icon [key]="chip.id" [size]="18"></app-provider-icon>
|
||||
</button>
|
||||
}
|
||||
@if (!allProvidersVisible()) {
|
||||
<button type="button" (click)="showAllProviders()"
|
||||
class="chip inline-flex h-8 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-3 text-[13px] text-slate-300 underline decoration-dotted underline-offset-2 hover:text-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]">
|
||||
Tout afficher
|
||||
<span class="rounded-full bg-slate-700 px-1.5 text-[11px] tabular-nums text-slate-400 no-underline">{{ hiddenProviderCount() }}</span>
|
||||
</button>
|
||||
}
|
||||
@if (!allSourcesActive()) {
|
||||
<button type="button" (click)="enableAllSources()"
|
||||
class="chip inline-flex h-8 shrink-0 items-center gap-1 whitespace-nowrap rounded-full border border-slate-700 px-3 text-[13px] text-slate-300 hover:bg-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]">
|
||||
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
Toutes les sources
|
||||
<!-- Source masquée : logo désaturé, la marque reste identifiable. -->
|
||||
<app-provider-icon [key]="chip.id" [size]="20"
|
||||
[class.opacity-40]="!chip.visible"
|
||||
[class.grayscale]="!chip.visible"></app-provider-icon>
|
||||
</button>
|
||||
}
|
||||
@if (!allProvidersVisible()) {
|
||||
<button type="button" (click)="showAllProviders()"
|
||||
class="chip inline-flex h-8 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-3 text-[13px] text-slate-300 underline decoration-dotted underline-offset-2 hover:text-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]">
|
||||
Tout afficher
|
||||
<span class="rounded-full bg-slate-700 px-1.5 text-[11px] tabular-nums text-slate-400 no-underline">{{ hiddenProviderCount() }}</span>
|
||||
</button>
|
||||
}
|
||||
@if (!allSourcesActive()) {
|
||||
<button type="button" (click)="enableAllSources()"
|
||||
class="chip inline-flex h-8 shrink-0 items-center gap-1 whitespace-nowrap rounded-full border border-slate-700 px-3 text-[13px] text-slate-300 hover:bg-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]">
|
||||
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
Toutes les sources
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ============ Panneau de filtres (repliable) ============ -->
|
||||
@if (filtersOpen()) {
|
||||
|
||||
Reference in New Issue
Block a user