Files
cima-progetti/README.md
T
stefanomanca e3098d3004 refactor[ frontend / components ]: aggiornamento UI globale, ottimizzazione header e gestione errori
Header: Rifatto il componente con menu mobile ed effetti di background.

Cleanup: Rimossi i componenti Hero e Services non più necessari.

Layout: Migliorata la struttura e lo stile della pagina Contacts.

Core: Implementata la gestione globale degli errori in main.js.

Styles: Aggiornati gli stili globali e le media queries per una migliore responsività.
2026-05-06 23:05:17 +02:00

590 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Cima Progetti - Sito Aziendale
Sito web moderno, performante e accessibile sviluppato con **Svelte 5 + Vite** per presentare servizi, metodologia e contatti aziendali. Completamente responsivo con supporto completo per telefoni e tablet.
## ✨ Funzionalità principali
- 🌓 **Tema light/dark** con persistenza dual-storage (localStorage + cookie backup)
- 📱 **Design completamente responsivo** con breakpoint intelligenti
- ⬆️ **Header smart** — trasparente all'inizio, sfondo blur opaco dopo scroll
- 🍔 **Menu hamburger** con animazione fluida di apertura/chiusura
- 🎨 **Sistema di componenti riusabili** e theme-aware
- 🚀 **Routing client-side** con History API e fallback 404 per pagine non create
- 🔐 **Cookie consent** con personalizzazione categorie
-**Accessibilità** — focus-visible preservato, tap highlight rimosso su touch
-**Svelte 5 Runes** — reattività state-driven con $state(), $derived()
- 🐛 **Global error handling** — trap di SyntaxError visibile su dev server
## 🛠️ Requisiti
- **Node.js** 18+ (consigliato LTS)
- **npm** 9+
## 🚀 Avvio rapido
```bash
npm install
npm run dev
```
Applicazione disponibile su `http://localhost:5173` (accesso locale) e `http://192.168.XX.XXX:5173` (rete locale).
## 📝 Script disponibili
| Script | Descrizione |
|--------|-------------|
| `npm run dev` | Avvia il server di sviluppo con hot reload (esposto su 0.0.0.0:5173) |
| `npm run build` | Genera la build di produzione ottimizzata in `dist/` |
| `npm run preview` | Avvia preview della build (simula produzione in locale) |
## 📁 Struttura del progetto
```
cimaprogetti/
├── index.html # Template HTML entry point
├── package.json # Dependencies e scripts
├── vite.config.js # Configurazione Vite (SPA + host 0.0.0.0)
├── svelte.config.js # Configurazione Svelte
├── src/
│ ├── main.js # Entry point con error trap globale
│ ├── App.svelte # Root component con routing e layout
│ │
│ ├── components/
│ │ ├── Header/
│ │ │ ├── Header.svelte # Navbar sticky con tema + scroll detection
│ │ │ └── Header.css # Stili header (blur backdrop, absolute menu)
│ │ │
│ │ ├── Button/
│ │ │ ├── Button.svelte # Button/link riusabile (16 prop)
│ │ │ └── Button.css # Stili + focus-visible + no tap highlight
│ │ │
│ │ ├── CookiePopUp/
│ │ │ ├── CookiePopUp.svelte # Cookie consent con toggle personalizzato
│ │ │ ├── CookiePopUp.css # Dialog mobile + desktop
│ │ │ └── assets/ # SVG cookie icon
│ │ │
│ │ ├── Toggle/
│ │ │ ├── Toggle.svelte # Switch accessibile
│ │ │ └── Toggle.css # Stili toggle (animated knob)
│ │ │
│ │ ├── ThemeToggle/
│ │ │ ├── ThemeToggle.svelte
│ │ │ └── ThemeToggle.css
│ │ │
│ │ ├── Footer/
│ │ │ ├── Footer.svelte
│ │ │ └── Footer.css
│ │ │
│ │ └── Hero/, Services/ # Componenti home
│ │
│ ├── pages/
│ │ ├── index.svelte # Home page
│ │ ├── Contacts.svelte # Pagina contatti con team profiles
│ │ ├── 403.svelte, 404.svelte, 500.svelte, errore.svelte # Error pages
│ │
│ ├── lib/
│ │ ├── theme.js # Theme persistence (localStorage + cookie)
│ │ ├── navigation.js # Client-side routing utilities
│ │ ├── cookieConsent.js # Cookie storage & consent management
│ │ └── errorRouting.js # Path normalization & aliases
│ │
│ └── styles/
│ ├── global.css # CSS variables, typography, resets
│ ├── App.css # Layout principale
│ ├── contacts.css # Pagina contatti (flex + absolute positioning)
│ └── error-pages.css # Pagine errore (clamp typography)
└── public/
└── images/
├── background/ # Background patterns
├── icons/ # Logo, UI icons
└── contacts/ # Hero images (light/dark theme)
```
## 🌐 Configurazione Network
Il server Vite è configurato per essere **accessibile dalla rete locale**:
```js
// vite.config.js
server: {
host: '0.0.0.0', // Ascolta su tutte le interfacce
port: 5173,
}
```
### Accesso dal telefono sulla stessa Wi-Fi
1. Avvia il dev server: `npm run dev`
2. Nel terminale vedrai l'indirizzo IP locale (es. `192.168.68.119`)
3. Dal telefono apri: `http://192.168.68.119:5173`
**Nota:** Per produzione, usa `npm run build && npm run preview` per servire la versione compilata su `http://192.168.68.119:4173` (compatibile con browser vecchi).
## 🗺️ Routing
Il routing è **client-side only** — nessuna pagina server. Gestito in `App.svelte` leggendo `window.location.pathname` e reagendo ai cambi di History API.
### Tabella rotte
| Route | Pagina | Comportamento |
|-------|--------|---------------|
| `/` | `index.svelte` | Home page (Hero + Services) |
| `/contatti` o `/contacts` | `Contacts.svelte` | Info contatti + team profiles |
| `/servizi`, `/metodo`, `/progetti`, `/chi-siamo` | `404.svelte` | Non create — mostra 404 ma mantiene URL |
| `/403`, `/404`, `/500`, `/errore` | Error pages | Pagine errore dedicate |
| Qualsiasi altra rotta | `404.svelte` | Fallback automatico |
### Meccanismo di routing
```js
// src/App.svelte
const getRoute = (path) => {
const normalized = resolvePathname(path) // Normalizza trailing slash
if (normalized === '/') return 'home'
if (normalized === '/contatti' || normalized === '/contacts') return 'contacts'
// ...
return '404' // Fallback
}
let currentRoute = $derived(getRoute(pathname))
```
### Come aggiungere una nuova pagina
1. **Crea il componente** in `src/pages/MyPage.svelte`
2. **Importa in App.svelte**:
```svelte
import MyPage from "./pages/MyPage.svelte"
```
3. **Aggiungi la route** in `getRoute()`:
```js
if (normalized === '/my-page') return 'mypage'
```
4. **Renderizza nel template**:
```svelte
{:else if currentRoute === 'mypage'}
<MyPage />
```
## 🎨 Sistema di Tema
### Tema Persistente Dual-Storage
Il tema viene salvato su **localStorage** (primario) e **cookie** (backup) simultaneamente. Questo assicura che il tema sopravviva anche se l'utente cancella parte dello storage del browser.
```js
// src/lib/theme.js
export const getSavedTheme = () => {
// Prova localStorage prima, poi cookie come fallback
return localStorage.getItem('theme') || getCookie('theme')
}
export const saveTheme = (theme) => {
localStorage.setItem('theme', theme)
setCookie('theme', theme) // Backup redundante
}
export const applyTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme)
}
```
### Variabili CSS Globali
Tutte le variabili tema sono in `src/styles/global.css`:
```css
:root {
--navbar-height: 140px;
--primary-color: #1343F0; /* Blu Cima */
--text-color: #111827; /* Grigio scuro */
--surface: #ffffff; /* Background carta */
--background: rgba(246, 249, 255, 0.5);
--background-opaque: #00000033;
--muted-color: #6b7280;
--lateral-margin: 12rem;
}
:root[data-theme='dark'] {
--primary-color: #4983F2; /* Blu chiaro */
--text-color: #e6eef8; /* Grigio molto chiaro */
--surface: #000;
--background: rgba(0, 0, 0, 0.8);
--background-opaque: rgba(255, 255, 255, 0.2);
}
/* Mobile breakpoint */
@media (max-width: 900px) {
:root {
--navbar-height: 110px;
--lateral-margin: 1.5rem;
}
}
```
### Come usare i colori tema
```svelte
<div style="color: var(--text-color); background: var(--surface);">
Contenuto automaticamente theme-aware
</div>
```
## 🧩 Componenti Principali
### Header (Navbar Intelligente)
La navbar è **sticky** e reagisce allo scroll con una transizione elegante:
- **Trasparente all'inizio** (`background-color: transparent`)
- **Sfondo blur dopo 100px di scroll** (`backdrop-filter: blur(8px)`)
- **Scompare al scroll verso il basso** (nascosto con `translateY(-100%)`)
- **Riappare al scroll verso l'alto** (velocità rilevata)
```svelte
<Header />
```
**Modifiche in Header.svelte:**
- Stato `hasBackground` che attiva a `scrollY > 100`
- Classe `with-bg` per applicare blur e shadow
- Mobile menu hamburger con animazione da basso
**CSS Features:**
- `backdrop-filter: blur(8px)` per effetto frosted glass
- `position: fixed` con `transition: transform 0.28s`
- Menu mobile `transform: translateY(100%)` → `translateY(0)` con cubic-bezier smoothing
### Button (Componente Riusabile)
Componente ultra-flessibile che renderizza come `<a>` se ha `href`, altrimenti `<button>`.
```svelte
<Button
text="PRENOTA UNA CALL"
href="/contatti"
borderWidth="1.5px"
borderColor="var(--text-color)"
color="transparent"
textColor="var(--text-color)"
padding="12px 32px"
round="5px"
margin="1rem 0 0"
bold
/>
```
**Tutte le prop:**
| Prop | Default | Descrizione |
|------|---------|-------------|
| `text` | `'Button'` | Testo del pulsante |
| `color` | `var(--primary-color)` | Background |
| `textColor` | `var(--surface)` | Colore testo |
| `padding` | `'10px 20px'` | Padding interno |
| `round` | `'5px'` | border-radius |
| `href` | — | Se presente, renderizza come `<a>` con navigazione client-side |
| `borderWidth` | `'0px'` | Spessore border interno (inset) |
| `borderColor` | `var(--primary-color)` | Colore border |
| `bold` | `true` | Font-weight bold |
| `margin` | `'0'` | **NEW** — margini esterni |
**Accessibilità:**
- Outline su `:focus-visible` (tastiera)
- Tap highlight rimosso su touch (`:focus:not(:focus-visible)`)
### CookiePopUp (Cookie Consent Dialog)
Dialog modale con due view:
1. **Main** — Descrizione generica + bottoni accetta/rifiuta/personalizza
2. **Prefs** — Toggle per tre categorie: Tecnici (always on), Analitici, Profilazione
```svelte
<CookiePopUp />
```
**Varianti layout:**
- **Desktop** (> 900px): Fixed al bottom, full-width
- **Tablet** (768900px): Drawer da destra (clip-path animation)
- **Mobile** (< 768px): Full-page dal basso (translateY animation)
**Accessibilità:**
- `role="dialog"` + `aria-modal="true"`
- Focus trap — primo elemento focusabile automaticamente
- Escape key per chiudere (con reject)
- Tap highlight disabilitato
### Contacts Page (Pagina Contatti)
Layout two-column con immagine decorativa e team profiles.
```svelte
<div class="contact-us">
<div class="contact-us-container">
<!-- Titolo, testo, email/WhatsApp, button -->
</div>
<div class="contact-image">
<!-- SVG tema-aware (light/dark) -->
</div>
</div>
<div class="behind-cima">
<h2>PEOPLE BEHIND CIMA</h2>
<div class="profiles-container">
<!-- Due profile cards con flex: 1 1 0 -->
</div>
</div>
```
**Responsive:**
- **Desktop** (> 900px): Due colonne con gap 40px
- **Mobile** (< 900px):
- `contact-image` diventa `position: absolute` centrata
- `contact-us-container` full width
- Profili stacked verticalmente
### Toggle (Accessibile Switch)
Switch accessibile con label opzionale e stato animato.
```svelte
<Toggle
bind:checked={analitici}
label="Analitici"
disabled={false}
/>
```
**CSS Variables** (customizzabile):
- `--toggle-on-bg` — colore quando ON
- `--toggle-off-bg` — colore quando OFF
- `--toggle-knob` — colore pallina
- `--toggle-width` / `--toggle-height` — dimensioni
## 📱 Responsive Design
### Breakpoint Principale
L'unico breakpoint è **900px** (tablet). Sotto questo valore attivano:
- Margini orizzontali ridotti: `12rem` → `1.5rem`
- Navbar height ridotta: `140px` → `110px`
- Menu hamburger (al posto di nav desktop)
- Header flexibile trasparente con blur
- Contatti layout single-column
- Profiles stacked
- Error pages con tipografia clamp()
### Clamp() per Tipografia Fluida
Errori, heading e font-size critici usano `clamp()` per scalare fluidamente:
```css
/* Error code number */
.error-code {
font-size: clamp(2rem, 5vw, 4rem);
}
/* Error page title background */
.error-text {
font-size: clamp(10rem, 20vw, 15rem) !important;
}
/* Links in contacts */
.contact-info-item a {
font-size: clamp(1.25rem, 2.5vw, 2rem);
}
```
## 🔐 Cookie Consent & Privacy
### Gestione Categoria Cookie
```js
// src/lib/cookieConsent.js
const consent = {
value: 'custom', // 'accepted_all', 'rejected_all', 'custom'
preferences: {
tecnici: true, // Obbligatorio
analitici: false, // Personalizzabile
profilazione: false // Personalizzabile
}
}
```
### Persistenza
- Cookie di consenso salvato in `cookie-consent` (via `js-cookie`)
- Configurazione letta al mount di `App.svelte`
- Toggle popup non riappare se esiste consenso valido
## 🐛 Error Handling & Debugging
### Global Error Trap (main.js)
```js
// Cattura SyntaxError e runtime errors prima del mount
window.addEventListener('error', (event) => {
const msg = `ERROR: ${event.error?.message || event.message}`;
console.error(msg, event.error);
alert(msg); // Visibile su telefono per debug
}, true);
try {
const app = mount(App, { target: document.getElementById('app') })
console.log("App mounted successfully!")
} catch (e) {
alert(`Mount Error: ${e.message}`)
}
```
### Diagnostica Schermo Bianco
Se il telefono mostra schermo bianco:
1. **Apri DevTools** → Console → controlla errori
2. **Prova build di produzione**:
```bash
npm run build
npm run preview
# Accedi da http://192.168.XX.XXX:4173
```
3. **Se l'alert appare**, c'è un SyntaxError nei moduli ES
4. **Prova altro browser** (Chrome vs Safari su iOS)
## 🔄 Svelte 5 & Modern JavaScript
### Svelte 5 Runes
Il progetto usa **Svelte 5 Runes** per reattività state-driven:
```svelte
<script>
let activeNav = $state(window.location.pathname)
let isMenuOpen = $state(false)
let hasBackground = $state(false)
let currentRoute = $derived(getRoute(pathname))
</script>
```
**Evitare:**
- ~~`on:click`~~ → Usare `onclick={...}`
- ~~Stores `writable()`~~ → Usare `$state()`
- ~~`reactive`~~ → Usare `$derived()`
### Rune Disponibili
- `$state(value)` — Mutabile, reattivo
- `$derived(expr)` — Calcolato e cached
- `$effect(fn)` — Side effect reattivo
- `$props()` — Default props type-safe
## 🚀 Build & Deploy
### Build di Produzione
```bash
npm run build
```
Genera file ottimizzati in `dist/`:
- `.html` minificato
- `.js` bundle (tree-shaken)
- `.css` minificato
- Source map opzionali
### Preview Locale
```bash
npm run preview
```
Simula il server di produzione su `http://localhost:4173` — ottimo per testare la build prima di deployare.
### Deployment
Il progetto è una **SPA statica** — deployabile su:
- **Vercel**, **Netlify** (drag & drop `dist/`)
- **GitHub Pages** (aggiungere `base: "/repo-name/"` in vite.config.js)
- **AWS S3 + CloudFront**
- **Qualsiasi server web** (serve `dist/` con fallback 404 → `/index.html`)
## 📦 Dipendenze
```json
{
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^7.0.0",
"svelte": "^5.55.5",
"vite": "^8.0.10"
}
}
```
**Zero runtime dependencies** — tutta la logica è vanilla JavaScript.
## 🎓 Tecnologie & Approcci
| Aspetto | Soluzione |
|---------|----------|
| **Framework UI** | Svelte 5 (Runes + reactivity) |
| **Build** | Vite 8 (zero-config, super veloce) |
| **CSS** | CSS3 nativo (custom properties + clamp) |
| **Routing** | History API (client-side only) |
| **Tema** | Data attribute + CSS variables |
| **Cookies** | Vanilla JS (no library) |
| **Accessibilità** | ARIA roles + focus-visible + keyboard nav |
| **Mobile** | Responsive design + touch optimized |
## 🎯 Convenzioni Codice
### Naming
- **Components**: PascalCase (`Header.svelte`, `Button.svelte`)
- **Pages**: PascalCase (`Contacts.svelte`, `index.svelte`)
- **Styles**: kebab-case (`.contact-us-container`, `.mobile-menu`)
- **JS utils**: camelCase (`getSavedTheme`, `navigateTo`)
### Organizzazione File
```
Component/
├── Component.svelte # Logica + template
├── Component.css # Stili isolati
└── assets/ # SVG, immagini specifiche
```
### CSS Classi
- `.component-name` per root
- `.component-name-child` per nested (BEM-like)
- Aggiungere media query alla fine del file
- Commentare sezioni con `/* ===== SECTION NAME ===== */`
## 🤝 Contribuire
### Workflow
1. **Crea branch** per feature: `git checkout -b feature/nome`
2. **Test locale**: `npm run dev` + mobile preview
3. **Build test**: `npm run build && npm run preview`
4. **Commit**: Messaggi chiari (`feat:`, `fix:`, `docs:`)
5. **Push** e open PR
## 🔗 Link Utili
- [Svelte 5 Docs](https://svelte.dev)
- [Vite Docs](https://vitejs.dev)
- [Svelte REPL](https://svelte.dev/repl)
- [Can I Use](https://caniuse.com) — Compatibilità browser
## 📄 Licenza
Progetto proprietario © **CIMA PROGETTI**