# 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'} ``` ## 🎨 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
Contenuto automaticamente theme-aware
``` ## 🧩 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
``` **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 `` se ha `href`, altrimenti `