feat(search): repli des rails filtres + boutons sources en icones
CI / build-and-test (push) Successful in 14m10s

- nouveau bouton oeil a droite de 'Filtres' pour replier le bloc
  types + sources (railsOpen, persiste en localStorage) ; pastille d'accent
  quand un filtre de type est actif alors que le rail est replie
- nouveau composant app-provider-icon : marques des 6 sources en trait,
  currentColor pour que l'icone herite de l'etat actif/masque du bouton
- pastilles sources en icone seule (h-8 w-8), libelle et compte passes par
  aria-label / title ; plus de point de couleur ni de nom visible
- suppression de PROVIDER_DOTS et providerDotStyle
This commit is contained in:
2026-09-28 22:28:08 -04:00
parent 7c3471596e
commit dccc1c8eb1
3 changed files with 157 additions and 60 deletions
@@ -0,0 +1,86 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
/** Clés courtes du registre fournisseurs (provider-registry.ts). */
export type ProviderIconKey = 'yt' | 'dm' | 'tw' | 'pt' | 'od' | 'ru';
/**
* Marque d'une source, dessinée au trait et colorée en `currentColor` :
* - l'icône hérite de la couleur du bouton, donc l'état actif / masqué
* reste lisible sans ajouter une pastille de couleur à côté ;
* - un seul style graphique pour les six sources, cohérent avec les icônes
* d'interface (œil, chevron…) de la même barre.
*
* Les formes sont volontairement géométriques et sobres : l'identité vient du
* geste (bouton lecture, bulle de discussion, initiale), pas d'un logo coloré
* qui ne serait plus lisible une fois réduit à 18 px.
*/
@Component({
selector: 'app-provider-icon',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@switch (normalized) {
@case ('yt') {
<!-- YouTube : cadre arrondi + triangle de lecture -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="2.5" y="5.5" width="19" height="13" rx="4" />
<path d="M10.4 9.4v5.2l4.4-2.6-4.4-2.6Z" fill="currentColor" stroke="none" />
</svg>
}
@case ('tw') {
<!-- Twitch : bulle de discussion + deux yeux -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 3h16v11.2L14.8 19.4h-4.3L7.2 22.7V19.4H4V3Z" />
<path d="M9.2 8.4v2.8M14.8 8.4v2.8" />
</svg>
}
@case ('dm') {
<!-- Dailymotion : « D » -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5.5 4.5v15" />
<path d="M5.5 4.5h4.2a7.5 7.5 0 0 1 0 15H5.5" />
</svg>
}
@case ('pt') {
<!-- PeerTube : « P » -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M7.5 20V4.5h5.6a5.4 5.4 0 0 1 0 10.8H7.5" />
</svg>
}
@case ('od') {
<!-- Odysee : « O » barré -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="12" cy="12" r="8.2" />
<path d="M8.3 15.7 15.7 8.3" />
</svg>
}
@case ('ru') {
<!-- Rumble : « R » -->
<svg [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M6 20V4.5h6.2a4.6 4.6 0 0 1 0 9.2H6" />
<path d="M12.4 13.7 17.6 20" />
</svg>
}
}
`
})
export class ProviderIconComponent {
/** Clé courte du fournisseur. Inconnue => aucun rendu. */
@Input() key: ProviderIconKey | string | null | undefined;
/** Taille en px (carré). */
@Input() size = 18;
/** Clé normalisée ; seules les six clés connues dessinent quelque chose. */
get normalized(): ProviderIconKey | null {
const k = String(this.key || '').toLowerCase();
return (['yt', 'dm', 'tw', 'pt', 'od', 'ru'] as const).includes(k as ProviderIconKey)
? (k as ProviderIconKey)
: null;
}
}