fix(frontend): lockup logo via texte reel plutot qu'un raster recadre

Recomposer icone+texte en une seule image bitmap (recadrage pixel de
l'asset source) donnait un rendu bruite et un espacement fige, impossible
a ajuster proprement (cause du "gros espace entre le texte et l'image"
remonte). Nouveau composant ev-brand : icone PNG nette + texte "EnerVision"
reel en police systeme, tailles liees en em pour que le lockup grossisse en
gardant le meme rapport, et un ecart controlable en CSS plutot que fige
dans un fichier image.
This commit is contained in:
Johan LEROY
2026-09-17 11:36:29 +02:00
parent cc7ca2d359
commit 517144f7e5
16 changed files with 81 additions and 25 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

@@ -1,7 +1,7 @@
<div class="auth-page"> <div class="auth-page">
<form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()"> <form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()">
<ev-card> <ev-card>
<img src="/logo.png" alt="EnerVision" class="auth-logo" /> <ev-brand class="auth-brand" />
<h1>Nouveau mot de passe</h1> <h1>Nouveau mot de passe</h1>
<p class="auth-subtitle">Votre mot de passe est provisoire, vous devez le modifier avant de continuer</p> <p class="auth-subtitle">Votre mot de passe est provisoire, vous devez le modifier avant de continuer</p>
@@ -5,10 +5,11 @@ ev-card {
0 8px 10px -6px rgba(0, 0, 0, 0.04); 0 8px 10px -6px rgba(0, 0, 0, 0.04);
} }
.auth-logo { .auth-brand {
display: block; justify-content: center;
height: 96px; width: 100%;
margin: 0 auto 1.5rem; font-size: 2.1rem;
margin-bottom: 1.75rem;
} }
h1 { h1 {
@@ -5,11 +5,12 @@ import { AuthService } from '../../../core/services/auth.service';
import { Button } from '../../../shared/components/ui/button/button'; import { Button } from '../../../shared/components/ui/button/button';
import { Card } from '../../../shared/components/ui/card/card'; import { Card } from '../../../shared/components/ui/card/card';
import { Alert } from '../../../shared/components/ui/alert/alert'; import { Alert } from '../../../shared/components/ui/alert/alert';
import { Brand } from '../../../shared/components/ui/brand/brand';
@Component({ @Component({
selector: 'app-change-password', selector: 'app-change-password',
standalone: true, standalone: true,
imports: [ReactiveFormsModule, Button, Card, Alert], imports: [ReactiveFormsModule, Button, Card, Alert, Brand],
templateUrl: './change-password.html', templateUrl: './change-password.html',
styleUrl: './change-password.scss', styleUrl: './change-password.scss',
}) })
@@ -1,7 +1,7 @@
<div class="auth-page"> <div class="auth-page">
<form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()"> <form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()">
<ev-card> <ev-card>
<img src="/logo.png" alt="EnerVision" class="auth-logo" /> <ev-brand class="auth-brand" />
<h1>Connexion</h1> <h1>Connexion</h1>
<p class="auth-subtitle">Accédez à votre espace EnerVision</p> <p class="auth-subtitle">Accédez à votre espace EnerVision</p>
@@ -5,10 +5,11 @@ ev-card {
0 8px 10px -6px rgba(0, 0, 0, 0.04); 0 8px 10px -6px rgba(0, 0, 0, 0.04);
} }
.auth-logo { .auth-brand {
display: block; justify-content: center;
height: 96px; width: 100%;
margin: 0 auto 1.5rem; font-size: 2.1rem;
margin-bottom: 1.75rem;
} }
h1 { h1 {
@@ -6,11 +6,12 @@ import { AuthService } from '../../../core/services/auth.service';
import { Button } from '../../../shared/components/ui/button/button'; import { Button } from '../../../shared/components/ui/button/button';
import { Card } from '../../../shared/components/ui/card/card'; import { Card } from '../../../shared/components/ui/card/card';
import { Alert } from '../../../shared/components/ui/alert/alert'; import { Alert } from '../../../shared/components/ui/alert/alert';
import { Brand } from '../../../shared/components/ui/brand/brand';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
standalone: true, standalone: true,
imports: [ReactiveFormsModule, Button, Card, Alert], imports: [ReactiveFormsModule, Button, Card, Alert, Brand],
templateUrl: './login.html', templateUrl: './login.html',
styleUrl: './login.scss', styleUrl: './login.scss',
}) })
@@ -1,7 +1,7 @@
<div class="dashboard"> <div class="dashboard">
<header class="dashboard__header"> <header class="dashboard__header">
<div class="dashboard__brand"> <div class="dashboard__brand">
<img src="/logo.png" alt="EnerVision" class="dashboard__logo" /> <ev-brand class="dashboard__logo" />
<div> <div>
<h1>Vue d'ensemble</h1> <h1>Vue d'ensemble</h1>
<p class="dashboard__subtitle">Consommation instantanée du parc</p> <p class="dashboard__subtitle">Consommation instantanée du parc</p>
@@ -26,8 +26,7 @@
} }
.dashboard__logo { .dashboard__logo {
height: 48px; font-size: 1.3rem;
width: auto;
} }
.dashboard__subtitle { .dashboard__subtitle {
@@ -13,6 +13,7 @@ import { Alert, AlertSeverity } from '../../shared/models/alert.model';
import { Card } from '../../shared/components/ui/card/card'; import { Card } from '../../shared/components/ui/card/card';
import { Alert as EvAlert } from '../../shared/components/ui/alert/alert'; import { Alert as EvAlert } from '../../shared/components/ui/alert/alert';
import { Badge, BadgeTone } from '../../shared/components/ui/badge/badge'; import { Badge, BadgeTone } from '../../shared/components/ui/badge/badge';
import { Brand } from '../../shared/components/ui/brand/brand';
const REFRESH_INTERVAL_MS = 10000; const REFRESH_INTERVAL_MS = 10000;
const UNAVAILABLE_MESSAGE = const UNAVAILABLE_MESSAGE =
@@ -28,7 +29,7 @@ const TON_PAR_SEVERITE: Record<AlertSeverity, BadgeTone> = {
@Component({ @Component({
selector: 'app-dashboard', selector: 'app-dashboard',
standalone: true, standalone: true,
imports: [DecimalPipe, ConsumptionGauge, SiteLoadChart, Card, EvAlert, Badge], imports: [DecimalPipe, ConsumptionGauge, SiteLoadChart, Card, EvAlert, Badge, Brand],
templateUrl: './dashboard.html', templateUrl: './dashboard.html',
styleUrl: './dashboard.scss', styleUrl: './dashboard.scss',
}) })
@@ -0,0 +1,2 @@
<img src="/logo-icon.png" alt="" class="ev-brand__icon" />
<span class="ev-brand__name">EnerVision</span>
@@ -0,0 +1,19 @@
:host {
display: inline-flex;
align-items: center;
gap: 0.45em;
font-size: 1.5rem;
font-weight: 700;
color: var(--color-text);
line-height: 1;
}
.ev-brand__icon {
height: 1.3em;
width: auto;
flex-shrink: 0;
}
.ev-brand__name {
white-space: nowrap;
}
@@ -0,0 +1,14 @@
import { TestBed } from '@angular/core/testing';
import { Brand } from './brand';
describe('Brand', () => {
it("affiche l'icône et le nom EnerVision", async () => {
await TestBed.configureTestingModule({ imports: [Brand] }).compileComponents();
const fixture = TestBed.createComponent(Brand);
fixture.detectChanges();
const icon = fixture.nativeElement.querySelector('img.ev-brand__icon');
expect(icon).toBeTruthy();
expect(fixture.nativeElement.textContent).toContain('EnerVision');
});
});
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'ev-brand',
standalone: true,
templateUrl: './brand.html',
styleUrl: './brand.scss',
})
export class Brand {}
@@ -60,19 +60,27 @@ dans le tableau `imports` du composant qui l'utilise.
```html ```html
<ev-badge tone="danger">critique</ev-badge> <ev-badge tone="danger">critique</ev-badge>
``` ```
- **`<ev-brand>`** (`brand/`) : lockup icône + « EnerVision », sans input. La taille se pilote
entièrement via `font-size` (l'icône et le texte sont exprimés en `em`, donc ils grossissent
ensemble en gardant le même écart proportionnel) : une page l'agrandit simplement avec
`ev-brand { font-size: 2.1rem; }`. Ne pas recomposer icône + texte en une seule image bitmap :
un essai en ce sens (recadrage pixel de l'asset source) a produit un rendu bruité et un espacement
figé, impossible à ajuster proprement.
```html
<ev-brand />
```
## Logo ## Logo
`apps/frontend/public/logo.png` (192×128, recadré et compressé depuis l'asset source du projet) L'icône seule (sans le mot-symbole), recadrée depuis l'asset source du projet, vit à deux
est affiché en en-tête des pages d'authentification et du tableau de bord : endroits qui doivent rester synchronisés si le logo change un jour :
```html `apps/frontend/public/logo-icon.png` (utilisée par `<ev-brand>`) et
<img src="logo.png" alt="EnerVision" class="auth-logo" /> `apps/backend/app/static/logo-icon.png` (référencée par `/docs`, favicon Swagger, et `/redoc` via
``` l'extension `x-logo` du schéma OpenAPI, voir `app/main.py`). Le mot-symbole « EnerVision » n'est
Le favicon reste `apps/frontend/public/favicon.ico` (non remplacé par ce chantier). jamais une image : c'est le texte du composant `<ev-brand>`, en police système.
Côté backend, l'icône seule (sans le mot-symbole) est servie depuis Le favicon `apps/frontend/public/favicon.ico` est généré depuis la même icône (multi-tailles
`apps/backend/app/static/logo-icon.png` et référencée par `/docs` (favicon Swagger) et `/redoc` 16 à 256px).
(logo natif via l'extension `x-logo` du schéma OpenAPI, voir `app/main.py`).
## Règle pour toute nouvelle page ## Règle pour toute nouvelle page