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">
<form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()">
<ev-card>
<img src="/logo.png" alt="EnerVision" class="auth-logo" />
<ev-brand class="auth-brand" />
<h1>Nouveau mot de passe</h1>
<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);
}
.auth-logo {
display: block;
height: 96px;
margin: 0 auto 1.5rem;
.auth-brand {
justify-content: center;
width: 100%;
font-size: 2.1rem;
margin-bottom: 1.75rem;
}
h1 {
@@ -5,11 +5,12 @@ import { AuthService } from '../../../core/services/auth.service';
import { Button } from '../../../shared/components/ui/button/button';
import { Card } from '../../../shared/components/ui/card/card';
import { Alert } from '../../../shared/components/ui/alert/alert';
import { Brand } from '../../../shared/components/ui/brand/brand';
@Component({
selector: 'app-change-password',
standalone: true,
imports: [ReactiveFormsModule, Button, Card, Alert],
imports: [ReactiveFormsModule, Button, Card, Alert, Brand],
templateUrl: './change-password.html',
styleUrl: './change-password.scss',
})
@@ -1,7 +1,7 @@
<div class="auth-page">
<form class="auth-card-wrapper" [formGroup]="form" (ngSubmit)="onSubmit()">
<ev-card>
<img src="/logo.png" alt="EnerVision" class="auth-logo" />
<ev-brand class="auth-brand" />
<h1>Connexion</h1>
<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);
}
.auth-logo {
display: block;
height: 96px;
margin: 0 auto 1.5rem;
.auth-brand {
justify-content: center;
width: 100%;
font-size: 2.1rem;
margin-bottom: 1.75rem;
}
h1 {
@@ -6,11 +6,12 @@ import { AuthService } from '../../../core/services/auth.service';
import { Button } from '../../../shared/components/ui/button/button';
import { Card } from '../../../shared/components/ui/card/card';
import { Alert } from '../../../shared/components/ui/alert/alert';
import { Brand } from '../../../shared/components/ui/brand/brand';
@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule, Button, Card, Alert],
imports: [ReactiveFormsModule, Button, Card, Alert, Brand],
templateUrl: './login.html',
styleUrl: './login.scss',
})
@@ -1,7 +1,7 @@
<div class="dashboard">
<header class="dashboard__header">
<div class="dashboard__brand">
<img src="/logo.png" alt="EnerVision" class="dashboard__logo" />
<ev-brand class="dashboard__logo" />
<div>
<h1>Vue d'ensemble</h1>
<p class="dashboard__subtitle">Consommation instantanée du parc</p>
@@ -26,8 +26,7 @@
}
.dashboard__logo {
height: 48px;
width: auto;
font-size: 1.3rem;
}
.dashboard__subtitle {
@@ -13,6 +13,7 @@ import { Alert, AlertSeverity } from '../../shared/models/alert.model';
import { Card } from '../../shared/components/ui/card/card';
import { Alert as EvAlert } from '../../shared/components/ui/alert/alert';
import { Badge, BadgeTone } from '../../shared/components/ui/badge/badge';
import { Brand } from '../../shared/components/ui/brand/brand';
const REFRESH_INTERVAL_MS = 10000;
const UNAVAILABLE_MESSAGE =
@@ -28,7 +29,7 @@ const TON_PAR_SEVERITE: Record<AlertSeverity, BadgeTone> = {
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [DecimalPipe, ConsumptionGauge, SiteLoadChart, Card, EvAlert, Badge],
imports: [DecimalPipe, ConsumptionGauge, SiteLoadChart, Card, EvAlert, Badge, Brand],
templateUrl: './dashboard.html',
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
<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
`apps/frontend/public/logo.png` (192×128, recadré et compressé depuis l'asset source du projet)
est affiché en en-tête des pages d'authentification et du tableau de bord :
```html
<img src="logo.png" alt="EnerVision" class="auth-logo" />
```
Le favicon reste `apps/frontend/public/favicon.ico` (non remplacé par ce chantier).
L'icône seule (sans le mot-symbole), recadrée depuis l'asset source du projet, vit à deux
endroits qui doivent rester synchronisés si le logo change un jour :
`apps/frontend/public/logo-icon.png` (utilisée par `<ev-brand>`) et
`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
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
`apps/backend/app/static/logo-icon.png` et référencée par `/docs` (favicon Swagger) et `/redoc`
(logo natif via l'extension `x-logo` du schéma OpenAPI, voir `app/main.py`).
Le favicon `apps/frontend/public/favicon.ico` est généré depuis la même icône (multi-tailles
16 à 256px).
## Règle pour toute nouvelle page