Add scouthub-attivita-fe
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
.header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 16px 24px;
|
||||
background: var(--color-header);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.back-arrow {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.brand--right {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.header--back .logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
font-weight: 700;
|
||||
font-size: 19px;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.nav-items {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-left: auto;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
cursor: pointer;
|
||||
padding: 8px 14px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: var(--color-text);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-item--active {
|
||||
color: var(--color-primary-text-strong);
|
||||
background: var(--color-primary-soft);
|
||||
}
|
||||
|
||||
.auth-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.auth-name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.btn-secondary--sm {
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
@if (isDetailOrForm()) {
|
||||
<div class="header header--back">
|
||||
<div class="back-link" (click)="back()">
|
||||
<span class="back-arrow">←</span>
|
||||
<span>Indietro</span>
|
||||
</div>
|
||||
<div class="brand brand--right">
|
||||
<div class="logo">S</div>
|
||||
<span class="brand-name">Scouthub</span>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="header header--nav">
|
||||
<a class="brand" routerLink="/">
|
||||
<div class="logo">S</div>
|
||||
<span class="brand-name">Scouthub</span>
|
||||
</a>
|
||||
<nav class="nav-items">
|
||||
@for (item of navItems; track item.path) {
|
||||
<a
|
||||
class="nav-item"
|
||||
[class.nav-item--active]="isActive(item.path)"
|
||||
[routerLink]="item.path"
|
||||
>
|
||||
{{ item.label }}
|
||||
</a>
|
||||
}
|
||||
</nav>
|
||||
<div class="auth-section">
|
||||
@if (isAuthenticated()) {
|
||||
<span class="auth-name">{{ displayName() }}</span>
|
||||
<div class="btn-secondary btn-secondary--sm" (click)="logout()">Esci</div>
|
||||
} @else {
|
||||
<div class="btn-secondary btn-secondary--sm" (click)="login()">Accedi</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { NavigationEnd, Router, RouterLink } from '@angular/router';
|
||||
import { filter } from 'rxjs';
|
||||
import Keycloak from 'keycloak-js';
|
||||
import { KEYCLOAK_EVENT_SIGNAL } from 'keycloak-angular';
|
||||
|
||||
interface NavItem {
|
||||
path: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
imports: [RouterLink],
|
||||
templateUrl: './header.html',
|
||||
styleUrl: './header.css',
|
||||
})
|
||||
export class Header {
|
||||
private readonly router = inject(Router);
|
||||
private readonly location = inject(Location);
|
||||
private readonly keycloak = inject(Keycloak);
|
||||
private readonly keycloakEvent = inject(KEYCLOAK_EVENT_SIGNAL);
|
||||
|
||||
readonly currentUrl = signal(this.router.url);
|
||||
|
||||
readonly isAuthenticated = computed(() => {
|
||||
this.keycloakEvent();
|
||||
return !!this.keycloak.authenticated;
|
||||
});
|
||||
|
||||
readonly displayName = computed(() => {
|
||||
this.keycloakEvent();
|
||||
const token = this.keycloak.tokenParsed;
|
||||
return (token?.['name'] as string) ?? (token?.['preferred_username'] as string) ?? '';
|
||||
});
|
||||
|
||||
readonly isDetailOrForm = computed(() => {
|
||||
const url = this.currentUrl();
|
||||
return url.startsWith('/attivita/dettaglio') || url.startsWith('/nuova-attivita') || url.startsWith('/modifica-attivita');
|
||||
});
|
||||
|
||||
readonly navItems: NavItem[] = [
|
||||
{ path: '/', label: 'Home' },
|
||||
{ path: '/ricerca', label: 'Cerca' },
|
||||
{ path: '/mie-attivita', label: 'Le mie attività' },
|
||||
{ path: '/profilo', label: 'Profilo' },
|
||||
];
|
||||
|
||||
constructor() {
|
||||
this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
|
||||
this.currentUrl.set(this.router.url);
|
||||
});
|
||||
}
|
||||
|
||||
isActive(path: string): boolean {
|
||||
return path === '/' ? this.currentUrl() === '/' : this.currentUrl().startsWith(path);
|
||||
}
|
||||
|
||||
back(): void {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
login(): void {
|
||||
this.keycloak.login({ redirectUri: window.location.href });
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.keycloak.logout({ redirectUri: window.location.origin + '/' });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user