feat: integrate FontAwesome icons across various components
- Updated apartment-list component to use FontAwesome icons for better visual representation. - Refactored brand-mark component to utilize FontAwesome for the brand icon. - Enhanced dashboard-page with FontAwesome icons for improved navigation. - Replaced SVG icons with FontAwesome in settings-page for consistency and better performance. - Updated sign-in-page to use FontAwesome for the sign-in action icon. - Refactored tenant-card to incorporate FontAwesome icons for attachments. - Enhanced workspace-navigation with FontAwesome icons for all navigation items. - Applied consistent styling for fa-icon elements across components.
This commit is contained in:
1 parent
ba695e2426
commit
713ab3b2d9
19 files changed
+531
-453
No files matched your search
@@ -86,6 +86,14 @@ test('adapts authenticated navigation to the viewport', async ({ page }, testInf
|
|||||||
expect(Math.round((navigationBox?.y ?? 0) + (navigationBox?.height ?? 0))).toBe(
|
expect(Math.round((navigationBox?.y ?? 0) + (navigationBox?.height ?? 0))).toBe(
|
||||||
viewport?.height,
|
viewport?.height,
|
||||||
);
|
);
|
||||||
|
for (const button of await navigation.locator('.navigation-item').all()) {
|
||||||
|
const buttonBox = await button.boundingBox();
|
||||||
|
const labelBox = await button.locator('.mdc-button__label > span').boundingBox();
|
||||||
|
expect(buttonBox).not.toBeNull();
|
||||||
|
expect(labelBox).not.toBeNull();
|
||||||
|
expect(labelBox!.x).toBeGreaterThanOrEqual(buttonBox!.x);
|
||||||
|
expect(labelBox!.x + labelBox!.width).toBeLessThanOrEqual(buttonBox!.x + buttonBox!.width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await navigation.getByRole('button', { name: 'Appartements' }).click();
|
await navigation.getByRole('button', { name: 'Appartements' }).click();
|
||||||
|
|||||||
@@ -1,166 +1,204 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-heading {
|
.page-heading {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
.content-region > mat-progress-bar {
|
|
||||||
margin-bottom: 16px;
|
.content-region>mat-progress-bar {
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-error {
|
.refresh-error {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-heading h1 {
|
.page-heading h1 {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
font-size: clamp(2rem, 7vw, 3.2rem);
|
font-size: clamp(2rem, 7vw, 3.2rem);
|
||||||
font-weight: 750;
|
font-weight: 750;
|
||||||
letter-spacing: -0.055em;
|
letter-spacing: -0.055em;
|
||||||
line-height: 1.02;
|
line-height: 1.02;
|
||||||
}
|
}
|
||||||
.page-heading > div > p:last-child {
|
|
||||||
margin-bottom: 0;
|
.page-heading>div>p:last-child {
|
||||||
color: var(--text-muted);
|
margin-bottom: 0;
|
||||||
line-height: 1.6;
|
color: var(--text-muted);
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-heading .primary-action {
|
.page-heading .primary-action {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
|
||||||
.button-plus {
|
|
||||||
margin-right: 4px;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state,
|
.empty-state,
|
||||||
.apartment-card {
|
.apartment-card {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 22px;
|
border-radius: 22px;
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04);
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
padding: 46px 22px;
|
padding: 46px 22px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-illustration {
|
.empty-illustration {
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
margin: 0 auto 22px;
|
margin: 0 auto 22px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
background: var(--surface-accent);
|
background: var(--surface-accent);
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
.empty-illustration svg {
|
|
||||||
width: 34px;
|
.empty-illustration fa-icon {
|
||||||
height: 34px;
|
display: flex;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-illustration fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-state h2 {
|
.empty-state h2 {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
font-size: 1.45rem;
|
font-size: 1.45rem;
|
||||||
}
|
}
|
||||||
.empty-state > p:not(.eyebrow) {
|
|
||||||
max-width: 440px;
|
.empty-state>p:not(.eyebrow) {
|
||||||
margin: 0 auto 22px;
|
max-width: 440px;
|
||||||
color: var(--text-muted);
|
margin: 0 auto 22px;
|
||||||
line-height: 1.6;
|
color: var(--text-muted);
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state .mat-mdc-outlined-button {
|
.empty-state .mat-mdc-outlined-button {
|
||||||
--mdc-outlined-button-label-text-color: var(--accent);
|
--mdc-outlined-button-label-text-color: var(--accent);
|
||||||
--mdc-outlined-button-outline-color: var(--border-strong);
|
--mdc-outlined-button-outline-color: var(--border-strong);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apartments-grid {
|
.apartments-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apartment-card {
|
.apartment-card {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apartment-card-topline {
|
.apartment-card-topline {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
margin-bottom: 22px;
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.property-label {
|
.property-label {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.property-value {
|
.property-value {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-info h2 {
|
.apt-info h2 {
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
letter-spacing: -0.035em;
|
letter-spacing: -0.035em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-address {
|
.apt-address {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
.apt-address svg {
|
|
||||||
width: 17px;
|
.apt-address fa-icon {
|
||||||
height: 17px;
|
display: flex;
|
||||||
flex: 0 0 17px;
|
width: 17px;
|
||||||
margin-top: 2px;
|
height: 17px;
|
||||||
|
flex: 0 0 17px;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.apt-address fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.apt-desc {
|
.apt-desc {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-actions {
|
.apt-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-actions .mat-mdc-button {
|
.apt-actions .mat-mdc-button {
|
||||||
--mdc-text-button-label-text-color: var(--accent);
|
--mdc-text-button-label-text-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-actions .danger-action.mat-mdc-button {
|
.apt-actions .danger-action.mat-mdc-button {
|
||||||
--mdc-text-button-label-text-color: var(--danger);
|
--mdc-text-button-label-text-color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.apt-actions mat-spinner {
|
.apt-actions mat-spinner {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-error {
|
.card-error {
|
||||||
margin: 14px 0 0;
|
margin: 14px 0 0;
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 700px) {
|
@media (min-width: 700px) {
|
||||||
.page-heading {
|
.page-heading {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 28px;
|
gap: 28px;
|
||||||
}
|
}
|
||||||
.page-heading .primary-action {
|
|
||||||
width: auto;
|
.page-heading .primary-action {
|
||||||
flex: 0 0 auto;
|
width: auto;
|
||||||
margin-top: 0;
|
flex: 0 0 auto;
|
||||||
}
|
margin-top: 0;
|
||||||
.apartments-grid {
|
}
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
.apartments-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1180px) {
|
@media (min-width: 1180px) {
|
||||||
.apartments-grid {
|
.apartments-grid {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,117 +1,92 @@
|
|||||||
<header class="page-heading">
|
<header class="page-heading">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Portefeuille</p>
|
<p class="eyebrow">Portefeuille</p>
|
||||||
<h1>Mes appartements</h1>
|
<h1>Mes appartements</h1>
|
||||||
<p>Les biens rattachés à votre activité LMNP.</p>
|
<p>Les biens rattachés à votre activité LMNP.</p>
|
||||||
</div>
|
</div>
|
||||||
<button mat-flat-button type="button" class="primary-action" (click)="addRequested.emit()">
|
<button mat-flat-button type="button" class="primary-action" (click)="addRequested.emit()">
|
||||||
<span class="button-plus" aria-hidden="true">+</span>Ajouter un appartement
|
<span aria-hidden="true">+</span> Ajouter un appartement
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="content-region" [attr.aria-busy]="loadState().loading">
|
<div class="content-region" [attr.aria-busy]="loadState().loading">
|
||||||
@if (loadState().loaded && loadState().loading) {
|
@if (loadState().loaded && loadState().loading) {
|
||||||
<mat-progress-bar mode="indeterminate" aria-label="Actualisation des appartements" />
|
<mat-progress-bar mode="indeterminate" aria-label="Actualisation des appartements" />
|
||||||
}
|
}
|
||||||
@if (loadState().loaded && loadState().error) {
|
@if (loadState().loaded && loadState().error) {
|
||||||
<div class="refresh-error" role="alert">
|
<div class="refresh-error" role="alert">
|
||||||
<p>{{ loadState().error }}</p>
|
<p>{{ loadState().error }}</p>
|
||||||
<button mat-button type="button" (click)="retryRequested.emit()">Réessayer</button>
|
<button mat-button type="button" (click)="retryRequested.emit()">Réessayer</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (!loadState().loaded && loadState().loading) {
|
@if (!loadState().loaded && loadState().loading) {
|
||||||
<div
|
<div class="apartments-grid loading-region" aria-busy="true" aria-label="Chargement des appartements">
|
||||||
class="apartments-grid loading-region"
|
@for (placeholder of [1, 2, 3]; track placeholder) {
|
||||||
aria-busy="true"
|
<article class="apartment-card skeleton-card" aria-hidden="true">
|
||||||
aria-label="Chargement des appartements"
|
<span class="skeleton-line skeleton-line-short"></span>
|
||||||
>
|
<span class="skeleton-line skeleton-line-title"></span>
|
||||||
@for (placeholder of [1, 2, 3]; track placeholder) {
|
<span class="skeleton-line"></span>
|
||||||
<article class="apartment-card skeleton-card" aria-hidden="true">
|
<span class="skeleton-line skeleton-line-medium"></span>
|
||||||
<span class="skeleton-line skeleton-line-short"></span>
|
</article>
|
||||||
<span class="skeleton-line skeleton-line-title"></span>
|
}
|
||||||
<span class="skeleton-line"></span>
|
</div>
|
||||||
<span class="skeleton-line skeleton-line-medium"></span>
|
} @else if (!loadState().loaded && loadState().error) {
|
||||||
</article>
|
<article class="load-error" role="alert">
|
||||||
}
|
<h2>Chargement impossible</h2>
|
||||||
</div>
|
<p>{{ loadState().error }}</p>
|
||||||
} @else if (!loadState().loaded && loadState().error) {
|
<button mat-stroked-button type="button" (click)="retryRequested.emit()">Réessayer</button>
|
||||||
<article class="load-error" role="alert">
|
</article>
|
||||||
<h2>Chargement impossible</h2>
|
} @else if (apartments().length === 0) {
|
||||||
<p>{{ loadState().error }}</p>
|
<article class="empty-state">
|
||||||
<button mat-stroked-button type="button" (click)="retryRequested.emit()">Réessayer</button>
|
<div class="empty-illustration" aria-hidden="true">
|
||||||
</article>
|
<fa-icon [icon]="faHouse" />
|
||||||
} @else if (apartments().length === 0) {
|
</div>
|
||||||
<article class="empty-state">
|
<p class="eyebrow">Commencez ici</p>
|
||||||
<div class="empty-illustration" aria-hidden="true">
|
<h2>Aucun appartement enregistré</h2>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
<p>Ajoutez votre premier bien pour construire votre portefeuille.</p>
|
||||||
<path d="m4 10 8-6 8 6v10H4z" />
|
<button mat-stroked-button type="button" (click)="addRequested.emit()">
|
||||||
<path d="M9 20v-6h6v6" />
|
Ajouter un appartement
|
||||||
</svg>
|
</button>
|
||||||
</div>
|
</article>
|
||||||
<p class="eyebrow">Commencez ici</p>
|
} @else {
|
||||||
<h2>Aucun appartement enregistré</h2>
|
<div class="apartments-grid">
|
||||||
<p>Ajoutez votre premier bien pour construire votre portefeuille.</p>
|
@for (apt of apartments(); track apt.id) {
|
||||||
<button mat-stroked-button type="button" (click)="addRequested.emit()">
|
<article class="apartment-card" [attr.aria-busy]="!!apt.id && deletingIds().has(apt.id)">
|
||||||
Ajouter un appartement
|
<div class="apartment-card-topline">
|
||||||
</button>
|
<span class="property-label">Bien immobilier</span>
|
||||||
</article>
|
<span class="property-value">{{ apt.purchasePrice.toLocaleString('fr-FR') }} €</span>
|
||||||
} @else {
|
</div>
|
||||||
<div class="apartments-grid">
|
<div class="apt-info">
|
||||||
@for (apt of apartments(); track apt.id) {
|
<h2>{{ apt.name }}</h2>
|
||||||
<article class="apartment-card" [attr.aria-busy]="!!apt.id && deletingIds().has(apt.id)">
|
<p class="apt-address">
|
||||||
<div class="apartment-card-topline">
|
<fa-icon [icon]="faLocationDot" aria-hidden="true" />
|
||||||
<span class="property-label">Bien immobilier</span>
|
{{ apt.address }}
|
||||||
<span class="property-value">{{ apt.purchasePrice.toLocaleString('fr-FR') }} €</span>
|
</p>
|
||||||
</div>
|
@if (apt.description) {
|
||||||
<div class="apt-info">
|
<p class="apt-desc">{{ apt.description }}</p>
|
||||||
<h2>{{ apt.name }}</h2>
|
}
|
||||||
<p class="apt-address">
|
</div>
|
||||||
<svg
|
@if (apt.id && deleteErrors()[apt.id]) {
|
||||||
viewBox="0 0 24 24"
|
<p class="card-error" role="alert">{{ deleteErrors()[apt.id] }}</p>
|
||||||
fill="none"
|
}
|
||||||
stroke="currentColor"
|
<div class="apt-actions" aria-live="polite">
|
||||||
stroke-width="1.8"
|
<button mat-button type="button" [disabled]="!!apt.id && deletingIds().has(apt.id)"
|
||||||
aria-hidden="true"
|
(click)="editRequested.emit(apt)">
|
||||||
>
|
Modifier
|
||||||
<path d="M20 10c0 5-8 11-8 11S4 15 4 10a8 8 0 1 1 16 0Z" />
|
</button>
|
||||||
<circle cx="12" cy="10" r="2.5" />
|
@if (apt.id) {
|
||||||
</svg>
|
<button mat-button type="button" class="danger-action" [disabled]="deletingIds().has(apt.id)"
|
||||||
{{ apt.address }}
|
(click)="deleteRequested.emit(apt.id)">
|
||||||
</p>
|
@if (deletingIds().has(apt.id)) {
|
||||||
@if (apt.description) {
|
<mat-spinner diameter="16" aria-hidden="true" /> Suppression…
|
||||||
<p class="apt-desc">{{ apt.description }}</p>
|
} @else {
|
||||||
}
|
Supprimer
|
||||||
</div>
|
}
|
||||||
@if (apt.id && deleteErrors()[apt.id]) {
|
</button>
|
||||||
<p class="card-error" role="alert">{{ deleteErrors()[apt.id] }}</p>
|
}
|
||||||
}
|
</div>
|
||||||
<div class="apt-actions" aria-live="polite">
|
</article>
|
||||||
<button
|
}
|
||||||
mat-button
|
</div>
|
||||||
type="button"
|
}
|
||||||
[disabled]="!!apt.id && deletingIds().has(apt.id)"
|
|
||||||
(click)="editRequested.emit(apt)"
|
|
||||||
>
|
|
||||||
Modifier
|
|
||||||
</button>
|
|
||||||
@if (apt.id) {
|
|
||||||
<button
|
|
||||||
mat-button
|
|
||||||
type="button"
|
|
||||||
class="danger-action"
|
|
||||||
[disabled]="deletingIds().has(apt.id)"
|
|
||||||
(click)="deleteRequested.emit(apt.id)"
|
|
||||||
>
|
|
||||||
@if (deletingIds().has(apt.id)) {
|
|
||||||
<mat-spinner diameter="16" aria-hidden="true" /> Suppression…
|
|
||||||
} @else {
|
|
||||||
Supprimer
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Component, input, output } from '@angular/core';
|
import { Component, input, output } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import { faHouse, faLocationDot } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
@@ -7,11 +9,13 @@ import { LoadState } from '../../services/workspace-resource';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-apartment-list',
|
selector: 'app-apartment-list',
|
||||||
imports: [MatButtonModule, MatProgressBarModule, MatProgressSpinnerModule],
|
imports: [FontAwesomeModule, MatButtonModule, MatProgressBarModule, MatProgressSpinnerModule],
|
||||||
templateUrl: './apartment-list.html',
|
templateUrl: './apartment-list.html',
|
||||||
styleUrl: './apartment-list.css',
|
styleUrl: './apartment-list.css',
|
||||||
})
|
})
|
||||||
export class ApartmentList {
|
export class ApartmentList {
|
||||||
|
readonly faHouse = faHouse;
|
||||||
|
readonly faLocationDot = faLocationDot;
|
||||||
readonly apartments = input.required<Apartment[]>();
|
readonly apartments = input.required<Apartment[]>();
|
||||||
readonly loadState = input.required<LoadState>();
|
readonly loadState = input.required<LoadState>();
|
||||||
readonly deletingIds = input<ReadonlySet<string>>(new Set());
|
readonly deletingIds = input<ReadonlySet<string>>(new Set());
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import { faHouse } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-brand-mark',
|
selector: 'app-brand-mark',
|
||||||
template: `
|
imports: [FontAwesomeModule],
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
template: ` <fa-icon [icon]="faHouse" /> `,
|
||||||
<path d="m4 10 8-6 8 6v9a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z" />
|
|
||||||
<path d="M9 20v-6h6v6" />
|
|
||||||
</svg>
|
|
||||||
`,
|
|
||||||
styles: `
|
styles: `
|
||||||
:host {
|
:host {
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
fa-icon {
|
||||||
|
display: flex;
|
||||||
width: 55%;
|
width: 55%;
|
||||||
height: 55%;
|
height: 55%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
host: { 'aria-hidden': 'true' },
|
host: { 'aria-hidden': 'true' },
|
||||||
})
|
})
|
||||||
export class BrandMark {}
|
export class BrandMark {
|
||||||
|
readonly faHouse = faHouse;
|
||||||
|
}
|
||||||
@@ -104,10 +104,15 @@
|
|||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
.feature-icon svg {
|
.feature-icon fa-icon {
|
||||||
|
display: flex;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
.feature-icon fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.user-profile {
|
.user-profile {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -13,10 +13,7 @@
|
|||||||
[attr.aria-busy]="workspace.apartmentLoadState().loading"
|
[attr.aria-busy]="workspace.apartmentLoadState().loading"
|
||||||
>
|
>
|
||||||
<div class="feature-icon" aria-hidden="true">
|
<div class="feature-icon" aria-hidden="true">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
<fa-icon [icon]="faTableCellsLarge" />
|
||||||
<path d="M4 21V5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v16M2 21h20" />
|
|
||||||
<path d="M8 8h8M8 12h8M8 16h4" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Votre portefeuille</p>
|
<p class="eyebrow">Votre portefeuille</p>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Component, computed, inject, signal } from '@angular/core';
|
import { Component, computed, inject, signal } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import { faTableCellsLarge } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
@@ -8,11 +10,12 @@ import { WorkspaceService } from '../../services/workspace.service';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard-page',
|
selector: 'app-dashboard-page',
|
||||||
imports: [MatButtonModule, MatProgressBarModule],
|
imports: [FontAwesomeModule, MatButtonModule, MatProgressBarModule],
|
||||||
templateUrl: './dashboard-page.html',
|
templateUrl: './dashboard-page.html',
|
||||||
styleUrl: './dashboard-page.css',
|
styleUrl: './dashboard-page.css',
|
||||||
})
|
})
|
||||||
export class DashboardPage {
|
export class DashboardPage {
|
||||||
|
readonly faTableCellsLarge = faTableCellsLarge;
|
||||||
private readonly http = inject(HttpClient);
|
private readonly http = inject(HttpClient);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
readonly session = inject(SessionService);
|
readonly session = inject(SessionService);
|
||||||
|
|||||||
@@ -61,10 +61,15 @@
|
|||||||
background: var(--surface-accent);
|
background: var(--surface-accent);
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
.settings-icon svg {
|
.settings-icon fa-icon {
|
||||||
|
display: flex;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
.settings-icon fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.settings-copy h2 {
|
.settings-copy h2 {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<article class="settings-card" aria-labelledby="appearance-heading">
|
<article class="settings-card" aria-labelledby="appearance-heading">
|
||||||
<div class="settings-copy">
|
<div class="settings-copy">
|
||||||
<span class="settings-icon" aria-hidden="true"
|
<span class="settings-icon" aria-hidden="true"><fa-icon [icon]="faMoon" /></span>
|
||||||
><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
|
||||||
<path d="M12 3a9 9 0 1 0 9 9c0-.5-.04-1-.12-1.47A7 7 0 0 1 12 3Z" /></svg
|
|
||||||
></span>
|
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Interface</p>
|
<p class="eyebrow">Interface</p>
|
||||||
<h2 id="appearance-heading">Apparence</h2>
|
<h2 id="appearance-heading">Apparence</h2>
|
||||||
@@ -47,11 +44,7 @@
|
|||||||
aria-labelledby="session-heading"
|
aria-labelledby="session-heading"
|
||||||
>
|
>
|
||||||
<div class="settings-copy">
|
<div class="settings-copy">
|
||||||
<span class="settings-icon" aria-hidden="true"
|
<span class="settings-icon" aria-hidden="true"><fa-icon [icon]="faUser" /></span>
|
||||||
><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
|
||||||
<circle cx="12" cy="8" r="4" />
|
|
||||||
<path d="M4 21a8 8 0 0 1 16 0" /></svg
|
|
||||||
></span>
|
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Compte</p>
|
<p class="eyebrow">Compte</p>
|
||||||
<h2 id="session-heading">Session</h2>
|
<h2 id="session-heading">Session</h2>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import { faMoon, faUser } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { SessionService } from '../../services/session.service';
|
import { SessionService } from '../../services/session.service';
|
||||||
@@ -6,13 +8,17 @@ import { ThemeService } from '../../services/theme.service';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings-page',
|
selector: 'app-settings-page',
|
||||||
imports: [MatButtonModule, MatRadioModule],
|
imports: [FontAwesomeModule, MatButtonModule, MatRadioModule],
|
||||||
templateUrl: './settings-page.html',
|
templateUrl: './settings-page.html',
|
||||||
styleUrl: './settings-page.css',
|
styleUrl: './settings-page.css',
|
||||||
})
|
})
|
||||||
export class SettingsPage {
|
export class SettingsPage {
|
||||||
|
readonly faMoon = faMoon;
|
||||||
|
readonly faUser = faUser;
|
||||||
readonly session = inject(SessionService);
|
readonly session = inject(SessionService);
|
||||||
readonly theme = inject(ThemeService);
|
readonly theme = inject(ThemeService);
|
||||||
|
|
||||||
logout(): void { window.location.href = '/logout'; }
|
logout(): void {
|
||||||
|
window.location.href = '/logout';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -51,11 +51,16 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
.sign-in-action svg {
|
.sign-in-action fa-icon {
|
||||||
|
display: flex;
|
||||||
width: 19px;
|
width: 19px;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
.sign-in-action fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.security-note {
|
.security-note {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -19,15 +19,7 @@
|
|||||||
|
|
||||||
<button mat-flat-button class="primary-action sign-in-action" (click)="loginRequested.emit()">
|
<button mat-flat-button class="primary-action sign-in-action" (click)="loginRequested.emit()">
|
||||||
Se connecter avec OIDC
|
Se connecter avec OIDC
|
||||||
<svg
|
<fa-icon [icon]="faArrowRight" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M5 12h14M13 6l6 6-6 6" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p class="security-note">
|
<p class="security-note">
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { Component, output } from '@angular/core';
|
import { Component, output } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import { faArrowRight } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { BrandMark } from '../brand-mark';
|
import { BrandMark } from '../brand-mark';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sign-in-page',
|
selector: 'app-sign-in-page',
|
||||||
imports: [BrandMark, MatButtonModule],
|
imports: [BrandMark, FontAwesomeModule, MatButtonModule],
|
||||||
templateUrl: './sign-in-page.html',
|
templateUrl: './sign-in-page.html',
|
||||||
styleUrl: './sign-in-page.css',
|
styleUrl: './sign-in-page.css',
|
||||||
})
|
})
|
||||||
export class SignInPage {
|
export class SignInPage {
|
||||||
|
readonly faArrowRight = faArrowRight;
|
||||||
readonly loginRequested = output<void>();
|
readonly loginRequested = output<void>();
|
||||||
}
|
}
|
||||||
@@ -95,6 +95,10 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
.attachment-download-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.attachment-file-name {
|
.attachment-file-name {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
@@ -107,6 +111,14 @@
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
.attachment-delete fa-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
.attachment-delete fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.upload-action {
|
.upload-action {
|
||||||
display: block;
|
display: block;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
|
|||||||
@@ -1,156 +1,212 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-navigation {
|
.app-navigation {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: calc(72px + env(safe-area-inset-bottom));
|
height: calc(72px + env(safe-area-inset-bottom));
|
||||||
padding: 6px 10px env(safe-area-inset-bottom);
|
padding: 6px 10px env(safe-area-inset-bottom);
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
background: color-mix(in srgb, var(--surface) 94%, transparent);
|
background: color-mix(in srgb, var(--surface) 94%, transparent);
|
||||||
box-shadow: 0 -10px 30px rgba(25, 40, 35, 0.06);
|
box-shadow: 0 -10px 30px rgba(25, 40, 35, 0.06);
|
||||||
backdrop-filter: blur(18px);
|
backdrop-filter: blur(18px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-brand,
|
.sidebar-brand,
|
||||||
.sidebar-user {
|
.sidebar-user {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-items {
|
.navigation-items {
|
||||||
display: grid;
|
display: grid;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-item.mat-mdc-button {
|
.navigation-item.mat-mdc-button {
|
||||||
--mdc-text-button-label-text-color: var(--text-muted);
|
--mdc-text-button-label-text-color: var(--text-muted);
|
||||||
min-width: 0;
|
width: 100%;
|
||||||
height: 60px;
|
min-width: 0;
|
||||||
border-radius: 14px;
|
height: 60px;
|
||||||
padding: 5px 4px;
|
border-radius: 14px;
|
||||||
font-weight: 650;
|
overflow: hidden;
|
||||||
letter-spacing: 0;
|
padding: 5px 4px;
|
||||||
|
font-weight: 650;
|
||||||
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-item .mat-mdc-button-touch-target {
|
.navigation-item .mat-mdc-button-touch-target {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
.navigation-item svg {
|
|
||||||
width: 21px;
|
.navigation-item fa-icon {
|
||||||
height: 21px;
|
display: flex;
|
||||||
margin: 0 auto 4px;
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
margin: 0 auto 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navigation-item fa-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.navigation-item span {
|
.navigation-item span {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 0.66rem;
|
font-size: 0.66rem;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-item.active {
|
.navigation-item.active {
|
||||||
--mdc-text-button-label-text-color: var(--accent);
|
--mdc-text-button-label-text-color: var(--accent);
|
||||||
background: var(--surface-accent);
|
background: var(--surface-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 959px) {
|
||||||
|
.navigation-item .mdc-button__label {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-item span {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
font-size: 0.62rem;
|
||||||
|
line-height: 1.05;
|
||||||
|
text-align: center;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 960px) {
|
@media (min-width: 960px) {
|
||||||
.app-navigation {
|
.app-navigation {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: auto;
|
right: auto;
|
||||||
bottom: auto;
|
bottom: auto;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
padding: 26px 18px;
|
padding: 26px 18px;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
}
|
}
|
||||||
.sidebar-brand {
|
|
||||||
display: flex;
|
.sidebar-brand {
|
||||||
align-items: center;
|
display: flex;
|
||||||
gap: 12px;
|
align-items: center;
|
||||||
padding: 0 8px 32px;
|
gap: 12px;
|
||||||
}
|
padding: 0 8px 32px;
|
||||||
.sidebar-brand > div {
|
}
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
.sidebar-brand>div {
|
||||||
font-size: 0.86rem;
|
display: flex;
|
||||||
line-height: 1.15;
|
flex-direction: column;
|
||||||
}
|
font-size: 0.86rem;
|
||||||
.sidebar-brand strong {
|
line-height: 1.15;
|
||||||
font-size: 1rem;
|
}
|
||||||
}
|
|
||||||
.sidebar-brand span:last-child {
|
.sidebar-brand strong {
|
||||||
color: var(--text-muted);
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
.navigation-items {
|
|
||||||
display: flex;
|
.sidebar-brand span:last-child {
|
||||||
height: auto;
|
color: var(--text-muted);
|
||||||
flex-direction: column;
|
}
|
||||||
gap: 6px;
|
|
||||||
}
|
.navigation-items {
|
||||||
.navigation-item.mat-mdc-button {
|
display: flex;
|
||||||
width: 100%;
|
height: auto;
|
||||||
height: 48px;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
gap: 6px;
|
||||||
border-radius: 13px;
|
}
|
||||||
padding: 0 14px;
|
|
||||||
}
|
.navigation-item.mat-mdc-button {
|
||||||
.navigation-item .mat-mdc-button-touch-target {
|
width: 100%;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
}
|
justify-content: flex-start;
|
||||||
.navigation-item .mdc-button__label {
|
border-radius: 13px;
|
||||||
display: flex;
|
padding: 0 14px;
|
||||||
align-items: center;
|
}
|
||||||
gap: 12px;
|
|
||||||
}
|
.navigation-item .mat-mdc-button-touch-target {
|
||||||
.navigation-item svg {
|
height: 48px;
|
||||||
width: 20px;
|
}
|
||||||
height: 20px;
|
|
||||||
margin: 0;
|
.navigation-item .mdc-button__label {
|
||||||
}
|
display: flex;
|
||||||
.navigation-item span {
|
align-items: center;
|
||||||
font-size: 0.86rem;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
.sidebar-user {
|
|
||||||
position: absolute;
|
.navigation-item fa-icon {
|
||||||
right: 18px;
|
display: flex;
|
||||||
bottom: 24px;
|
width: 20px;
|
||||||
left: 18px;
|
height: 20px;
|
||||||
display: grid;
|
margin: 0;
|
||||||
grid-template-columns: 36px minmax(0, 1fr);
|
}
|
||||||
gap: 10px;
|
|
||||||
padding: 14px;
|
.navigation-item span {
|
||||||
border: 1px solid var(--border);
|
font-size: 0.86rem;
|
||||||
border-radius: 16px;
|
}
|
||||||
background: var(--surface-soft);
|
|
||||||
}
|
.sidebar-user {
|
||||||
.sidebar-user > div:nth-child(2) {
|
position: absolute;
|
||||||
display: flex;
|
right: 18px;
|
||||||
min-width: 0;
|
bottom: 24px;
|
||||||
flex-direction: column;
|
left: 18px;
|
||||||
justify-content: center;
|
display: grid;
|
||||||
}
|
grid-template-columns: 36px minmax(0, 1fr);
|
||||||
.sidebar-user strong,
|
gap: 10px;
|
||||||
.sidebar-user span {
|
padding: 14px;
|
||||||
overflow: hidden;
|
border: 1px solid var(--border);
|
||||||
text-overflow: ellipsis;
|
border-radius: 16px;
|
||||||
white-space: nowrap;
|
background: var(--surface-soft);
|
||||||
}
|
}
|
||||||
.sidebar-user strong {
|
|
||||||
font-size: 0.82rem;
|
.sidebar-user>div:nth-child(2) {
|
||||||
}
|
display: flex;
|
||||||
.sidebar-user span {
|
min-width: 0;
|
||||||
color: var(--text-muted);
|
flex-direction: column;
|
||||||
font-size: 0.69rem;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.logout-action.mat-mdc-button {
|
|
||||||
--mdc-text-button-label-text-color: var(--text-muted);
|
.sidebar-user strong,
|
||||||
grid-column: 1 / -1;
|
.sidebar-user span {
|
||||||
height: 34px;
|
overflow: hidden;
|
||||||
border-top: 1px solid var(--border);
|
text-overflow: ellipsis;
|
||||||
border-radius: 0;
|
white-space: nowrap;
|
||||||
font-size: 0.75rem;
|
}
|
||||||
}
|
|
||||||
|
.sidebar-user strong {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-user span {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.69rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-action.mat-mdc-button {
|
||||||
|
--mdc-text-button-label-text-color: var(--text-muted);
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
height: 34px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
border-radius: 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,18 +12,7 @@
|
|||||||
routerLink="/dashboard"
|
routerLink="/dashboard"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<svg
|
<fa-icon [icon]="faTableCellsLarge" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.8"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<rect x="3" y="3" width="7" height="7" rx="2" />
|
|
||||||
<rect x="14" y="3" width="7" height="7" rx="2" />
|
|
||||||
<rect x="3" y="14" width="7" height="7" rx="2" />
|
|
||||||
<rect x="14" y="14" width="7" height="7" rx="2" />
|
|
||||||
</svg>
|
|
||||||
<span>Tableau de bord</span>
|
<span>Tableau de bord</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -33,16 +22,7 @@
|
|||||||
routerLink="/apartments"
|
routerLink="/apartments"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<svg
|
<fa-icon [icon]="faBuilding" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.8"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M4 21V5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v16" />
|
|
||||||
<path d="M2 21h20M8 7h2M14 7h2M8 11h2M14 11h2M8 15h2M14 15h2" />
|
|
||||||
</svg>
|
|
||||||
<span>Appartements</span>
|
<span>Appartements</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -52,18 +32,7 @@
|
|||||||
routerLink="/tenants"
|
routerLink="/tenants"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<svg
|
<fa-icon [icon]="faUsers" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.8"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<circle cx="9" cy="8" r="3" />
|
|
||||||
<path
|
|
||||||
d="M3.5 20v-2.5A4.5 4.5 0 0 1 8 13h2a4.5 4.5 0 0 1 4.5 4.5V20M16 5.5a3 3 0 0 1 0 5.8M17 14a4.5 4.5 0 0 1 3.5 4.4V20"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>Locataires</span>
|
<span>Locataires</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -73,16 +42,7 @@
|
|||||||
routerLink="/leases"
|
routerLink="/leases"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<svg
|
<fa-icon [icon]="faFileLines" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.8"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M6 3h9l4 4v14H6z" />
|
|
||||||
<path d="M14 3v5h5M9 12h7M9 16h7" />
|
|
||||||
</svg>
|
|
||||||
<span>Baux</span>
|
<span>Baux</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -92,18 +52,7 @@
|
|||||||
routerLink="/settings"
|
routerLink="/settings"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<svg
|
<fa-icon [icon]="faGear" aria-hidden="true" />
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.8"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<circle cx="12" cy="12" r="3" />
|
|
||||||
<path
|
|
||||||
d="M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.83 2.83-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 .6 1.7 1.7 0 0 0-.4 1.1V21h-4v-.09A1.7 1.7 0 0 0 8.6 19.4a1.7 1.7 0 0 0-1.88.34l-.06.06-2.83-2.83.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-.6-1 1.7 1.7 0 0 0-1.1-.4H3v-4h.09A1.7 1.7 0 0 0 4.6 8.6a1.7 1.7 0 0 0-.34-1.88l-.06-.06 2.83-2.83.06.06A1.7 1.7 0 0 0 9 4.6a1.7 1.7 0 0 0 1-.6 1.7 1.7 0 0 0 .4-1.1V3h4v.09A1.7 1.7 0 0 0 15.4 4.6a1.7 1.7 0 0 0 1.88-.34l.06-.06 2.83 2.83-.06.06A1.7 1.7 0 0 0 19.4 9c.16.38.37.72.6 1 .3.3.7.45 1.1.45h.09v4h-.09c-.4 0-.8.15-1.1.45-.23.28-.44.62-.6 1Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>Réglages</span>
|
<span>Réglages</span>
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { Component, inject, input, output } from '@angular/core';
|
import { Component, inject, input, output } from '@angular/core';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
import {
|
||||||
|
faBuilding,
|
||||||
|
faFileLines,
|
||||||
|
faGear,
|
||||||
|
faTableCellsLarge,
|
||||||
|
faUsers,
|
||||||
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { RouterLink, RouterLinkActive } from '@angular/router';
|
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { BrandMark } from '../brand-mark';
|
import { BrandMark } from '../brand-mark';
|
||||||
@@ -7,11 +15,16 @@ import { SessionService } from '../../services/session.service';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-workspace-navigation',
|
selector: 'app-workspace-navigation',
|
||||||
imports: [BrandMark, MatButtonModule, RouterLink, RouterLinkActive],
|
imports: [BrandMark, FontAwesomeModule, MatButtonModule, RouterLink, RouterLinkActive],
|
||||||
templateUrl: './workspace-navigation.html',
|
templateUrl: './workspace-navigation.html',
|
||||||
styleUrl: './workspace-navigation.css',
|
styleUrl: './workspace-navigation.css',
|
||||||
})
|
})
|
||||||
export class WorkspaceNavigation {
|
export class WorkspaceNavigation {
|
||||||
|
readonly faTableCellsLarge = faTableCellsLarge;
|
||||||
|
readonly faBuilding = faBuilding;
|
||||||
|
readonly faUsers = faUsers;
|
||||||
|
readonly faFileLines = faFileLines;
|
||||||
|
readonly faGear = faGear;
|
||||||
readonly userInitial = input.required<string>();
|
readonly userInitial = input.required<string>();
|
||||||
readonly logoutRequested = output<void>();
|
readonly logoutRequested = output<void>();
|
||||||
readonly session = inject(SessionService);
|
readonly session = inject(SessionService);
|
||||||
|
|||||||
@@ -98,6 +98,14 @@ svg {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
|
|||||||
Reference in new issue
Block a user