From 608b7fc6f50672b67365dd420a9805cabeb0db94 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Thu, 26 Sep 2024 17:50:14 +0200 Subject: [PATCH] refact: move badge to a separate component --- .../app/GN2CommonModule/GN2Common.module.ts | 3 + .../others/badge/badge.component.html | 7 ++ .../others/badge/badge.component.scss | 15 ++++ .../others/badge/badge.component.ts | 68 +++++++++++++++++++ .../infos/status/status.component.html | 14 ++-- .../infos/status/status.component.scss | 13 ---- .../infos/status/status.component.ts | 58 ++++------------ 7 files changed, 114 insertions(+), 64 deletions(-) create mode 100644 frontend/src/app/GN2CommonModule/others/badge/badge.component.html create mode 100644 frontend/src/app/GN2CommonModule/others/badge/badge.component.scss create mode 100644 frontend/src/app/GN2CommonModule/others/badge/badge.component.ts diff --git a/frontend/src/app/GN2CommonModule/GN2Common.module.ts b/frontend/src/app/GN2CommonModule/GN2Common.module.ts index 6cd8392c2d..3eb4649c98 100644 --- a/frontend/src/app/GN2CommonModule/GN2Common.module.ts +++ b/frontend/src/app/GN2CommonModule/GN2Common.module.ts @@ -40,6 +40,7 @@ import { AreasIntersectedComponent } from './form/areas-intersected/areas-inters import { AutoCompleteComponent } from '@geonature_common/form/autocomplete/autocomplete.component'; import { ConfirmationDialog } from '@geonature_common/others/modal-confirmation/confirmation.dialog'; import { DatalistComponent } from '@geonature_common/form/datalist/datalist.component'; +import { BadgeComponent } from '@geonature_common/others/badge/badge.component'; import { BreadcrumbsComponent } from '@geonature_common/others/breadcrumbs/breadcrumbs.component'; import { DatasetsComponent } from './form/datasets/datasets.component'; import { DateComponent } from './form/date/date.component'; @@ -141,6 +142,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component'; AreasComponent, NomenclatureComponent, ObserversComponent, + BadgeComponent, BreadcrumbsComponent, DateComponent, TaxonomyComponent, @@ -208,6 +210,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component'; AcquisitionFrameworksComponent, AreasComponent, MunicipalitiesComponent, + BadgeComponent, BreadcrumbsComponent, DynamicFormComponent, NomenclatureComponent, diff --git a/frontend/src/app/GN2CommonModule/others/badge/badge.component.html b/frontend/src/app/GN2CommonModule/others/badge/badge.component.html new file mode 100644 index 0000000000..7d5af3e2c3 --- /dev/null +++ b/frontend/src/app/GN2CommonModule/others/badge/badge.component.html @@ -0,0 +1,7 @@ + + {{ text }} + diff --git a/frontend/src/app/GN2CommonModule/others/badge/badge.component.scss b/frontend/src/app/GN2CommonModule/others/badge/badge.component.scss new file mode 100644 index 0000000000..2a48c04202 --- /dev/null +++ b/frontend/src/app/GN2CommonModule/others/badge/badge.component.scss @@ -0,0 +1,15 @@ +.badge { + --bgColor: #ffffff; // Default value + --textColor: #444; // Default value + + display: flex; + flex-flow: row nowrap; + white-space: nowrap; + gap: 0.25rem; + text-transform: uppercase; + font-weight: bold; + + background-color: var(--bgColor); + border: 2px solid color-mix(in srgb, var(--bgColor) 80%, black); + color: var(--textColor); +} diff --git a/frontend/src/app/GN2CommonModule/others/badge/badge.component.ts b/frontend/src/app/GN2CommonModule/others/badge/badge.component.ts new file mode 100644 index 0000000000..d395ce19e1 --- /dev/null +++ b/frontend/src/app/GN2CommonModule/others/badge/badge.component.ts @@ -0,0 +1,68 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input, OnInit } from '@angular/core'; +import { GN2CommonModule } from '@geonature_common/GN2Common.module'; + +// //////////////////////////////////////////////////////////////////////////// +// helper method +// //////////////////////////////////////////////////////////////////////////// + +function isHexadecimalColor(color: string) { + return /^#[0-9A-F]{6}$/i.test(color); +} + +function computeContrastColor(backgroundColor: string) { + // Convertir la couleur en un format RGB + const r = parseInt(backgroundColor.slice(1, 3), 16); + const g = parseInt(backgroundColor.slice(3, 5), 16); + const b = parseInt(backgroundColor.slice(5, 7), 16); + + // Calculer la luminosité + const luminance = 0.299 * r + 0.587 * g + 0.114 * b; + + // Retourner une couleur claire ou foncée selon la luminosité + return luminance < 128 ? '#ffffff' : '#444'; +} + +function colorToCSS(color: string) { + return `--bgColor: ${color}; --textColor: ${computeContrastColor(color)};`; +} + +// //////////////////////////////////////////////////////////////////////////// +// Badge parameters +// //////////////////////////////////////////////////////////////////////////// + +export interface BadgeSymbology { + color?: string; +} + +// //////////////////////////////////////////////////////////////////////////// +// helper method +// //////////////////////////////////////////////////////////////////////////// + +@Component({ + selector: 'gn-badge', + templateUrl: 'badge.component.html', + styleUrls: ['badge.component.scss'], +}) +export class BadgeComponent { + @Input() + text: string; + + @Input() + tooltip: string; + + symbologyAsCSS: string; + + @Input() + set symbology(symbology: BadgeSymbology | null) { + this.symbologyAsCSS = ''; + if (!symbology) { + return; + } + if (!isHexadecimalColor(symbology.color)) { + console.warn(`[badge] ${symbology.color} is not a valid hexadecimal color`); + return; + } + this.symbologyAsCSS = colorToCSS(symbology.color); + } +} diff --git a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.html b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.html index 3623d6205d..f7a4de80b6 100644 --- a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.html +++ b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.html @@ -1,13 +1,11 @@
Statuts
- - {{ status.badge }} - +
diff --git a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.scss b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.scss index c77e17171b..871f7ecef0 100644 --- a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.scss +++ b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.scss @@ -20,18 +20,5 @@ width: 100%; gap: $gap; line-height: inherit; - --bgColor: #ffffff; // Default value - --textColor: #444; // Default value - .badge { - display: flex; - flex-flow: row nowrap; - white-space: nowrap; - gap: $gap / 2; - text-transform: uppercase; - font-weight: bold; - background-color: var(--bgColor); - border: 2px solid color-mix(in srgb, var(--bgColor) 80%, black); - color: var(--textColor); - } } } diff --git a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.ts b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.ts index 7638b3c0ec..f8ca16252a 100644 --- a/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.ts +++ b/frontend/src/app/syntheseModule/taxon-sheet/infos/status/status.component.ts @@ -3,30 +3,13 @@ import { Component, Input, OnInit } from '@angular/core'; import { Taxon } from '@geonature_common/form/taxonomy/taxonomy.component'; import { GN2CommonModule } from '@geonature_common/GN2Common.module'; import { TaxonSheetService } from '../../taxon-sheet.service'; +import { BadgeSymbology } from '@geonature_common/others/badge/badge.component'; interface Status { badge: string; tooltip: string; - symbologyAsCSS: string; + symbology: BadgeSymbology | null; } - -function computeContrastColor(backgroundColor: string) { - // Convertir la couleur en un format RGB - const r = parseInt(backgroundColor.slice(1, 3), 16); - const g = parseInt(backgroundColor.slice(3, 5), 16); - const b = parseInt(backgroundColor.slice(5, 7), 16); - - // Calculer la luminosité - const luminance = 0.299 * r + 0.587 * g + 0.114 * b; - - // Retourner une couleur claire ou foncée selon la luminosité - return luminance < 128 ? '#ffffff' : '#444'; -} - -function colorToCSS(color: string) { - return `--bgColor: ${color}; --textColor: ${computeContrastColor(color)};`; -} - @Component({ standalone: true, selector: 'status', @@ -38,12 +21,7 @@ export class StatusComponent implements OnInit { _taxon: Taxon | null; _symbology: Array<{ types: Array; - values: Record< - string, - { - symbologyAsCSSStyle: string; - } - >; + values: Record; }>; status: Array = []; @@ -55,33 +33,27 @@ export class StatusComponent implements OnInit { if (!symbology || !symbology.symbologies) { return; } - for (const symbologyItem of symbology.symbologies) { - const values = {}; - for (const key of Object.keys(symbologyItem.values)) { - values[key] = { - symbologyAsCSSStyle: colorToCSS(symbologyItem.values[key].color), - }; - } - this._symbology.push({ - types: symbologyItem.types, - values: values, - }); - } + this._symbology = symbology.symbologies; + this.computeStatus(); }); this._tss.fetchStatusSymbology(); } - _getSymbologyAsCSSStyle(type: string, value: string): string { + _getSymbologyAsBadgeSymbology(type: string, value: string): BadgeSymbology | null { if (!this._symbology) { - return ''; + return null; } const symbologieItem = this._symbology.find((item) => item.types.includes(type)); if (!symbologieItem) { - return ''; + return null; } - - return symbologieItem.values[value]?.symbologyAsCSSStyle ?? ''; + if (!('color' in symbologieItem.values[value])) { + return null; + } + return { + color: symbologieItem.values[value].color, + }; } @Input() @@ -106,7 +78,7 @@ export class StatusComponent implements OnInit { this.status.push({ badge: badgeValue, tooltip: `${status.cd_type_statut} : ${value.display} - ${text.full_citation}`, - symbologyAsCSS: this._getSymbologyAsCSSStyle(status.cd_type_statut, value.code_statut), + symbology: this._getSymbologyAsBadgeSymbology(status.cd_type_statut, value.code_statut), }); } }