Conversione references in skill condivisa agency-shared-references

- Creata nuova skill agency-shared-references con 24 references centralizzate
- Spostate tutte le references da cartelle sparse (references/, agency-web-developer/, agency-archivist/) in un'unica posizione
- Aggiornati tutti i symlink delle 14 skills per puntare a ../agency-shared-references/references
- Aggiornati tutti i riferimenti nei SKILL.md (percorsi coerenti)
- README.md aggiornato con nuova struttura e istruzioni generiche
- INSTALL.sh semplificato con istruzioni platform-agnostic
- Eliminata cartella references/ dal root (ora centralizzata)
- Struttura più pulita e mantenibile, facile da installare su qualsiasi piattaforma
This commit is contained in:
AgentePotente 2026-03-11 00:11:03 +01:00
parent c496db151c
commit b289d87033
55 changed files with 288 additions and 142 deletions

View file

@ -346,21 +346,16 @@ $(document).ready(function() {
## References
### Technical (Web Developer Specific)
- [html_semantics.md](./references/html_semantics.md) — Semantic HTML best practices
- [css_layout.md](./references/css_layout.md) — Layout, responsive, Bootstrap
- [js_interactivity.md](./references/js_interactivity.md) — jQuery + GSAP patterns
### UX/Design Patterns (Shared References)
**Consultare PRIMA di implementare:**
- [hero_sections.md](../references/hero_sections.md) — Hero checklist, formula, layouts
- [design_patterns.md](../references/design_patterns.md) — Card grid, split layout, testimonial, FAQ patterns
- [navigation_patterns.md](../references/navigation_patterns.md) — Primary nav, mobile nav, IA
- [conversion_patterns.md](../references/conversion_patterns.md) — CTA hierarchy, forms, friction reducers
- [layout_systems.md](../references/layout_systems.md) — Grid, spacing, vertical rhythm
### Resources & Assets
- [resource_types.md](../agency-archivist/references/resource_types.md) — Tipologie risorse e use case
### Shared References (Agency Suite)
- [html_semantics.md](../agency-shared-references/references/html_semantics.md) — Semantic HTML best practices
- [css_layout.md](../agency-shared-references/references/css_layout.md) — Layout, responsive, Bootstrap
- [js_interactivity.md](../agency-shared-references/references/js_interactivity.md) — jQuery + GSAP patterns
- [hero_sections.md](../agency-shared-references/references/hero_sections.md) — Hero checklist, formula, layouts
- [design_patterns.md](../agency-shared-references/references/design_patterns.md) — Card grid, split layout, testimonial, FAQ patterns
- [navigation_patterns.md](../agency-shared-references/references/navigation_patterns.md) — Primary nav, mobile nav, IA
- [conversion_patterns.md](../agency-shared-references/references/conversion_patterns.md) — CTA hierarchy, forms, friction reducers
- [layout_systems.md](../agency-shared-references/references/layout_systems.md) — Grid, spacing, vertical rhythm
- [resource_types.md](../agency-shared-references/references/resource_types.md) — Tipologie risorse e use case
**Flusso consigliato:**
1. Leggi catalogo risorse (`assets/catalog.md`)

View file

@ -0,0 +1 @@
../agency-shared-references/references

View file

@ -1,647 +0,0 @@
# CSS Layout — Bootstrap e Custom
Guida per creare layout responsive con Bootstrap o CSS custom.
---
## Decisione: Bootstrap vs Custom
### Usa Bootstrap Quando:
✅ Design standard (grid, cards, buttons)
✅ Progetto veloce / MVP
✅ Cliente non richiede customizzazione estrema
✅ Team piccolo, nessun designer dedicato
### Usa Custom CSS Quando:
✅ Design altamente personalizzato
✅ Brand guidelines specifiche
✅ Layout non-standard / creativi
✅ Performance critica (no CSS unused)
---
## Bootstrap Setup
### CDN Setup
```html
<head>
<!-- Bootstrap CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
rel="stylesheet"
>
<!-- Custom CSS (override) -->
<link rel="stylesheet" href="css/custom.css">
</head>
<body>
<!-- Bootstrap JS (opzionale, solo se serve JS components) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
```
### Custom CSS Override
```css
/* css/custom.css */
:root {
/* Override Bootstrap variables */
--bs-primary: #005fcc;
--bs-secondary: #6c757d;
--bs-font-sans-serif: 'Inter', system-ui, -apple-system, sans-serif;
--bs-body-font-size: 1rem;
--bs-body-line-height: 1.6;
}
/* Custom styles */
.hero {
padding: 120px 0;
background: linear-gradient(135deg, #005fcc 0%, #003d99 100%);
color: white;
}
.btn-primary {
padding: 12px 32px;
font-weight: 600;
border-radius: 4px;
}
```
---
## Responsive Design
### Breakpoints
```css
/* Mobile-first approach */
/* Mobile: default (< 768px) */
.container {
padding: 0 16px;
}
/* Tablet (≥ 768px) */
@media (min-width: 768px) {
.container {
padding: 0 24px;
}
.hero {
padding: 160px 0;
}
}
/* Desktop (≥ 1024px) */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 32px;
}
}
/* Large Desktop (≥ 1440px) */
@media (min-width: 1440px) {
.container {
max-width: 1400px;
}
}
```
### Bootstrap Grid
```html
<!-- Container -->
<div class="container">
<!-- Row -->
<div class="row">
<!-- Mobile: 1 colonna, Tablet: 2 colonne, Desktop: 3 colonne -->
<div class="col-12 col-md-6 col-lg-4">
<!-- Content -->
</div>
<div class="col-12 col-md-6 col-lg-4">
<!-- Content -->
</div>
<div class="col-12 col-md-6 col-lg-4">
<!-- Content -->
</div>
</div>
</div>
```
---
## Typography
### Design Tokens
```css
:root {
/* Font Families */
--font-primary: 'Inter', system-ui, -apple-system, sans-serif;
--font-secondary: 'Georgia', serif;
/* Font Sizes (modular scale) */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
--text-5xl: 3rem; /* 48px */
/* Font Weights */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
/* Line Heights */
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Letter Spacing */
--tracking-tight: -0.025em;
--tracking-normal: 0;
--tracking-wide: 0.025em;
}
/* Base Typography */
body {
font-family: var(--font-primary);
font-size: var(--text-base);
line-height: var(--leading-normal);
color: #1a1a1a;
}
/* Headings */
h1 {
font-size: var(--text-5xl);
font-weight: var(--font-bold);
line-height: var(--leading-tight);
letter-spacing: var(--tracking-tight);
}
h2 {
font-size: var(--text-4xl);
font-weight: var(--font-bold);
line-height: var(--leading-tight);
}
h3 {
font-size: var(--text-3xl);
font-weight: var(--font-semibold);
line-height: var(--leading-tight);
}
/* Responsive typography */
@media (max-width: 767px) {
h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
}
```
---
## Spacing System
### Scala Modulare
```css
:root {
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
--space-16: 64px;
--space-20: 80px;
--space-24: 96px;
}
/* Section padding */
.section-padding {
padding: var(--space-16) 0;
}
@media (min-width: 768px) {
.section-padding {
padding: var(--space-24) 0;
}
}
/* Component spacing */
.card {
padding: var(--space-6);
}
.btn {
padding: var(--space-3) var(--space-6);
}
```
---
## Color System
### Palette
```css
:root {
/* Primary Brand Colors */
--color-primary: #005fcc;
--color-primary-dark: #003d99;
--color-primary-light: #3385ff;
/* Secondary Colors */
--color-secondary: #6c757d;
--color-secondary-dark: #5a6268;
--color-secondary-light: #868e96;
/* Neutrals */
--color-white: #ffffff;
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-400: #9ca3af;
--color-gray-500: #6b7280;
--color-gray-600: #4b5563;
--color-gray-700: #374151;
--color-gray-800: #1f2937;
--color-gray-900: #111827;
--color-black: #000000;
/* Semantic Colors */
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6;
/* Text Colors */
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-600);
--text-muted: var(--color-gray-500);
--text-inverse: var(--color-white);
/* Background Colors */
--bg-primary: var(--color-white);
--bg-secondary: var(--color-gray-50);
--bg-tertiary: var(--color-gray-100);
}
```
### Usage
```css
/* Text */
.text-primary { color: var(--text-primary); }
.text-secondary { color: var(--text-secondary); }
.text-muted { color: var(--text-muted); }
.text-inverse { color: var(--text-inverse); }
/* Backgrounds */
.bg-primary { background-color: var(--bg-primary); }
.bg-secondary { background-color: var(--bg-secondary); }
.bg-brand { background-color: var(--color-primary); }
/* Buttons */
.btn-primary {
background-color: var(--color-primary);
color: var(--color-white);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
}
.btn-secondary {
background-color: transparent;
color: var(--color-primary);
border: 2px solid var(--color-primary);
}
```
---
## Component Styles
### Buttons
```css
.btn {
display: inline-block;
padding: 12px 32px;
font-size: var(--text-base);
font-weight: var(--font-semibold);
text-decoration: none;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-white);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 95, 204, 0.3);
}
.btn-secondary {
background-color: transparent;
color: var(--color-primary);
border: 2px solid var(--color-primary);
}
.btn-secondary:hover {
background-color: var(--color-primary);
color: var(--color-white);
}
/* Responsive buttons */
@media (max-width: 767px) {
.btn {
width: 100%;
text-align: center;
}
}
```
### Cards
```css
.card {
background: var(--color-white);
border-radius: 8px;
padding: var(--space-6);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.card-image {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 4px;
margin-bottom: var(--space-4);
}
.card-title {
font-size: var(--text-xl);
font-weight: var(--font-semibold);
margin-bottom: var(--space-2);
}
.card-description {
color: var(--text-secondary);
margin-bottom: var(--space-4);
}
```
### Forms
```css
.form-group {
margin-bottom: var(--space-4);
}
.form-label {
display: block;
font-weight: var(--font-medium);
margin-bottom: var(--space-2);
color: var(--text-primary);
}
.form-control {
width: 100%;
padding: 12px 16px;
font-size: var(--text-base);
border: 1px solid var(--color-gray-300);
border-radius: 4px;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.1);
}
.form-control::placeholder {
color: var(--text-muted);
}
.form-error {
color: var(--color-error);
font-size: var(--text-sm);
margin-top: var(--space-1);
}
```
---
## Layout Patterns
### Hero Section
```css
.hero {
position: relative;
padding: 120px 0;
background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
color: var(--color-white);
overflow: hidden;
}
.hero-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.hero h1 {
font-size: var(--text-5xl);
margin-bottom: var(--space-4);
}
.hero-sub {
font-size: var(--text-xl);
opacity: 0.9;
margin-bottom: var(--space-8);
}
.hero-cta {
display: flex;
gap: var(--space-4);
justify-content: center;
flex-wrap: wrap;
}
/* Responsive hero */
@media (max-width: 767px) {
.hero {
padding: 80px 0;
}
.hero h1 {
font-size: var(--text-4xl);
}
.hero-sub {
font-size: var(--text-lg);
}
}
```
### Grid Layout
```css
.grid {
display: grid;
gap: var(--space-6);
}
.grid-2 {
grid-template-columns: repeat(2, 1fr);
}
.grid-3 {
grid-template-columns: repeat(3, 1fr);
}
.grid-4 {
grid-template-columns: repeat(4, 1fr);
}
/* Responsive grid */
@media (max-width: 1023px) {
.grid-4 {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 767px) {
.grid-2,
.grid-3,
.grid-4 {
grid-template-columns: 1fr;
}
}
```
### Split Layout
```css
.split-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-12);
align-items: center;
}
.split-image {
width: 100%;
height: auto;
border-radius: 8px;
}
/* Responsive split */
@media (max-width: 1023px) {
.split-layout {
grid-template-columns: 1fr;
gap: var(--space-8);
}
.split-image {
order: -1; /* Image first on mobile */
}
}
```
---
## Utility Classes
```css
/* Display */
.d-none { display: none; }
.d-block { display: block; }
.d-flex { display: flex; }
.d-grid { display: grid; }
.d-inline-block { display: inline-block; }
/* Flexbox */
.flex-row { flex-direction: row; }
.flex-column { flex-direction: column; }
.justify-start { justify-content: flex-start; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.justify-between { justify-content: space-between; }
.align-start { align-items: flex-start; }
.align-center { align-items: center; }
.align-end { align-items: flex-end; }
.flex-wrap { flex-wrap: wrap; }
.gap-2 { gap: var(--space-2); }
.gap-4 { gap: var(--space-4); }
.gap-6 { gap: var(--space-6); }
.gap-8 { gap: var(--space-8); }
/* Text Alignment */
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }
/* Spacing */
.mt-4 { margin-top: var(--space-4); }
.mb-4 { margin-bottom: var(--space-4); }
.py-8 { padding-top: var(--space-8); padding-bottom: var(--space-8); }
.px-4 { padding-left: var(--space-4); padding-right: var(--space-4); }
/* Visibility */
.visible { visibility: visible; }
.invisible { visibility: hidden; }
```
---
## Checklist Layout
- [ ] Mobile-first approach
- [ ] Breakpoints definiti (mobile, tablet, desktop)
- [ ] Typography scale coerente
- [ ] Spacing system modulare
- [ ] Color palette definita
- [ ] Buttons stilizzati (hover states)
- [ ] Cards con shadow e hover effect
- [ ] Forms accessibili e responsive
- [ ] Grid system funzionante
- [ ] Utility classes per layout veloci
- [ ] Test su mobile/tablet/desktop
---
_References per agency-web-developer skill_

View file

@ -1,418 +0,0 @@
# HTML Semantics — Best Practices
Guida per costruire HTML semantico, accessibile e SEO-friendly.
---
## Document Structure
### Base Template
```html
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{descrizione pagina}">
<title>{Titolo pagina} | {Brand}</title>
<!-- CSS -->
<link rel="stylesheet" href="css/main.css">
<!-- Favicon -->
<link rel="icon" href="assets/img/favicon.ico" type="image/x-icon">
</head>
<body>
<header>{Navigation}</header>
<main>{Contenuto principale}</main>
<footer>{Footer}</footer>
<!-- JS -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
```
---
## Semantic Elements
### Header
```html
<header>
<nav aria-label="Main navigation">
<a href="/" class="logo">
<img src="assets/img/logo.svg" alt="{Brand Name}">
</a>
<ul class="nav-menu">
<li><a href="/">Home</a></li>
<li><a href="/pages/services.html">Servizi</a></li>
<li><a href="/pages/about.html">Chi Siamo</a></li>
<li><a href="/pages/contact.html">Contatti</a></li>
</ul>
<button class="mobile-menu-toggle" aria-label="Toggle menu">
<span></span>
<span></span>
<span></span>
</button>
</nav>
</header>
```
### Main Content
```html
<main>
<!-- Hero Section -->
<section class="hero" aria-labelledby="hero-title">
<h1 id="hero-title">Headline principale</h1>
<p class="hero-sub">Subcopy di supporto</p>
<a href="#cta" class="btn btn-primary">Call to Action</a>
</section>
<!-- Services Section -->
<section class="services" aria-labelledby="services-title">
<h2 id="services-title">I Nostri Servizi</h2>
<div class="services-grid">
<article class="service-card">
<h3>Servizio 1</h3>
<p>Descrizione servizio</p>
<a href="#">Scopri di più</a>
</article>
<!-- Altre card -->
</div>
</section>
<!-- Testimonial Section -->
<section class="testimonials" aria-labelledby="testimonials-title">
<h2 id="testimonials-title">Dicono di Noi</h2>
<article class="testimonial">
<blockquote>
<p>"Testimonial text"</p>
</blockquote>
<cite>— Nome Cliente, Azienda</cite>
</article>
</section>
<!-- FAQ Section -->
<section class="faq" aria-labelledby="faq-title">
<h2 id="faq-title">Domande Frequenti</h2>
<div class="faq-list">
<article class="faq-item">
<h3>
<button class="faq-question" aria-expanded="false">
Domanda 1
</button>
</h3>
<div class="faq-answer">
<p>Risposta alla domanda</p>
</div>
</article>
</div>
</section>
<!-- CTA Section -->
<section class="cta" aria-labelledby="cta-title">
<h2 id="cta-title">Pronto a Iniziare?</h2>
<a href="/pages/contact.html" class="btn btn-primary" id="cta">Contattaci</a>
</section>
</main>
```
### Footer
```html
<footer>
<div class="footer-content">
<div class="footer-brand">
<img src="assets/img/logo.svg" alt="{Brand Name}">
<p>Descrizione breve del brand</p>
</div>
<nav aria-label="Footer navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/pages/services.html">Servizi</a></li>
<li><a href="/pages/about.html">Chi Siamo</a></li>
<li><a href="/pages/contact.html">Contatti</a></li>
</ul>
</nav>
<div class="footer-contact">
<p>Email: info@example.com</p>
<p>Tel: +39 123 456 7890</p>
</div>
<div class="footer-social">
<a href="#" aria-label="Facebook">FB</a>
<a href="#" aria-label="Instagram">IG</a>
<a href="#" aria-label="LinkedIn">LI</a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2024 {Brand Name}. Tutti i diritti riservati.</p>
<nav aria-label="Legal navigation">
<a href="/pages/privacy.html">Privacy Policy</a>
<a href="/pages/cookie.html">Cookie Policy</a>
</nav>
</div>
</footer>
```
---
## Heading Hierarchy
### Regole
1. **Un solo H1 per pagina** (di solito nella hero)
2. **Mai saltare livelli** (H2 → H3 → H4, non H2 → H4)
3. **Heading descrittivi** (non "Section 1", ma "I Nostri Servizi")
4. **Keyword rilevanti** (SEO-friendly ma naturale)
### Esempio Corretto
```html
<h1>Consulenza Marketing Digitale</h1>
<section>
<h2>I Nostri Servizi</h2>
<article>
<h3>SEO Optimization</h3>
<p>...</p>
</article>
<article>
<h3>Social Media Management</h3>
<p>...</p>
</article>
</section>
<section>
<h2>Perché Sceglierci</h2>
<h3>Esperienza Decennale</h3>
<h3>Team Certificato</h3>
</section>
```
---
## Accessibility
### ARIA Labels
```html
<!-- Navigation -->
<nav aria-label="Main navigation">...</nav>
<nav aria-label="Footer navigation">...</nav>
<!-- Sections -->
<section aria-labelledby="services-title">
<h2 id="services-title">Servizi</h2>
</section>
<!-- Buttons -->
<button aria-label="Close menu" class="close-btn">×</button>
<button aria-label="Toggle FAQ" aria-expanded="false" class="faq-question">
Domanda
</button>
<!-- Forms -->
<label for="email">Email</label>
<input type="email" id="email" name="email" required aria-required="true">
<!-- Images -->
<img src="team-photo.jpg" alt="Team di 5 persone in ufficio">
<img src="decorative-pattern.svg" alt="" role="presentation">
```
### Focus States
```css
/* Assicurati che tutti gli elementi focusabili abbiano visible focus */
a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
/* Skip link per keyboard navigation */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #005fcc;
color: white;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
```
```html
<body>
<a href="#main-content" class="skip-link">Vai al contenuto principale</a>
<header>...</header>
<main id="main-content">...</main>
</body>
```
---
## Images
### Best Practices
```html
<!-- Immagine con descrizione -->
<img src="team.jpg" alt="Team di 5 persone sorridenti in ufficio moderno">
<!-- Immagine decorativa (no alt text) -->
<img src="pattern.svg" alt="" role="presentation">
<!-- Immagine responsive -->
<img
src="hero-mobile.jpg"
srcset="hero-mobile.jpg 480w, hero-tablet.jpg 768w, hero-desktop.jpg 1200w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 100vw, 100vw"
alt="Hero image"
>
<!-- Lazy loading -->
<img src="placeholder.jpg" data-src="actual-image.jpg" loading="lazy" alt="Descrizione">
```
---
## Forms
### Contact Form
```html
<form action="https://formspree.io/f/{id}" method="POST" class="contact-form">
<div class="form-group">
<label for="name">Nome Completo</label>
<input
type="text"
id="name"
name="name"
required
aria-required="true"
autocomplete="name"
>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
required
aria-required="true"
autocomplete="email"
>
</div>
<div class="form-group">
<label for="message">Messaggio</label>
<textarea
id="message"
name="message"
rows="5"
required
aria-required="true"
></textarea>
</div>
<button type="submit" class="btn btn-primary">Invia Messaggio</button>
<p class="form-note">
<small>Inviando questo form accetti la nostra
<a href="/pages/privacy.html">privacy policy</a>.</small>
</p>
</form>
```
---
## SEO On-Page
### Meta Tags
```html
<head>
<!-- Required -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{Keyword Primaria} | {Brand Name}</title>
<meta name="description" content="{150-160 caratteri con keyword}">
<!-- Open Graph (social sharing) -->
<meta property="og:title" content="{Titolo pagina}">
<meta property="og:description" content="{Descrizione}">
<meta property="og:image" content="https://example.com/assets/img/og-image.jpg">
<meta property="og:url" content="https://example.com/pagina.html">
<meta property="og:type" content="website">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{Titolo}">
<meta name="twitter:description" content="{Descrizione}">
<meta name="twitter:image" content="https://example.com/assets/img/twitter-image.jpg">
<!-- Canonical URL -->
<link rel="canonical" href="https://example.com/pagina.html">
</head>
```
### Structured Data (JSON-LD)
```html
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "{Brand Name}",
"image": "https://example.com/assets/img/logo.png",
"description": "{Descrizione business}",
"address": {
"@type": "PostalAddress",
"streetAddress": "Via Roma 123",
"addressLocality": "Milano",
"postalCode": "20100",
"addressCountry": "IT"
},
"telephone": "+391234567890",
"url": "https://example.com"
}
</script>
```
---
## Checklist Semantica
- [ ] Un solo H1 per pagina
- [ ] Heading hierarchy corretta (no salti)
- [ ] Tag semantici usati (`<header>`, `<main>`, `<footer>`, `<section>`, `<article>`, `<nav>`)
- [ ] ARIA labels dove necessario
- [ ] Alt text su tutte le immagini (o vuoto per decorative)
- [ ] Form label associati correttamente
- [ ] Focus states visibili
- [ ] Skip link per keyboard navigation
- [ ] Meta title + description unici per pagina
- [ ] Canonical URL impostata
- [ ] Open Graph tags per social sharing
---
_References per agency-web-developer skill_

View file

@ -1,730 +0,0 @@
# JavaScript Interactivity — jQuery + GSAP
Guida per aggiungere interattività e animazioni fluide ai siti web.
---
## Setup Librerie
### CDN Links
```html
<head>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- GSAP -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<!-- GSAP ScrollTrigger (opzionale, per scroll animations) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
</head>
<body>
<!-- Main JS -->
<script src="js/main.js"></script>
</body>
```
---
## jQuery Patterns
### Document Ready
```javascript
$(document).ready(function() {
// Tutto il codice va qui dentro
// o usa la shorthand:
});
// Shorthand (equivalente)
$(function() {
// Codice qui
});
```
### Mobile Menu Toggle
```javascript
$(function() {
const $menuToggle = $('.mobile-menu-toggle');
const $navMenu = $('.nav-menu');
const $body = $('body');
$menuToggle.on('click', function() {
$navMenu.toggleClass('is-open');
$menuToggle.toggleClass('is-active');
$body.toggleClass('menu-open');
// Update ARIA
const expanded = $menuToggle.attr('aria-expanded') === 'true';
$menuToggle.attr('aria-expanded', !expanded);
});
// Close menu on link click (mobile)
$navMenu.find('a').on('click', function() {
if ($(window).width() < 768) {
$navMenu.removeClass('is-open');
$menuToggle.removeClass('is-active');
$body.removeClass('menu-open');
$menuToggle.attr('aria-expanded', 'false');
}
});
// Close menu on outside click
$(document).on('click', function(e) {
if (!$(e.target).closest('.nav-menu, .mobile-menu-toggle').length) {
$navMenu.removeClass('is-open');
$menuToggle.removeClass('is-active');
$body.removeClass('menu-open');
$menuToggle.attr('aria-expanded', 'false');
}
});
});
```
### Smooth Scroll
```javascript
$(function() {
$('a[href^="#"]').on('click', function(e) {
const targetId = this.getAttribute('href');
// Ignora link vuoti o non-anchor
if (targetId === '#' || !targetId.startsWith('#')) return;
const $target = $(targetId);
if ($target.length) {
e.preventDefault();
const offsetTop = $target.offset().top;
const headerHeight = $('header').outerHeight() || 0;
const scrollPosition = offsetTop - headerHeight - 20;
$('html, body').stop().animate({
scrollTop: scrollPosition
}, 800, 'easeInOutQuad');
// Update URL without jumping
history.pushState(null, null, targetId);
}
});
});
// Easing function (se non usi jQuery easing plugin)
$.easing.easeInOutQuad = function(x, t, b, c, d) {
t /= d / 2;
if (t < 1) return c / 2 * t * t + b;
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
};
```
### FAQ Accordion
```javascript
$(function() {
const $faqQuestions = $('.faq-question');
$faqQuestions.on('click', function() {
const $question = $(this);
const $answer = $question.next('.faq-answer');
const $item = $question.closest('.faq-item');
const isActive = $question.hasClass('is-active');
// Close all other items (accordion style)
$faqQuestions.not(this).removeClass('is-active');
$('.faq-answer').not($answer).slideUp(300);
$('.faq-item').not($item).removeClass('is-active');
// Toggle current item
$question.toggleClass('is-active');
$answer.slideToggle(300);
$item.toggleClass('is-active');
// Update ARIA
const expanded = $question.attr('aria-expanded') === 'true';
$question.attr('aria-expanded', !expanded);
});
// Keyboard accessibility
$faqQuestions.on('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
$(this).click();
}
});
});
```
### Form Validation
```javascript
$(function() {
const $form = $('.contact-form');
const $submitBtn = $form.find('button[type="submit"]');
$form.on('submit', function(e) {
let isValid = true;
// Validate required fields
$form.find('[required]').each(function() {
const $field = $(this);
const value = $field.val().trim();
const $error = $field.siblings('.form-error');
if (!value) {
isValid = false;
$field.addClass('is-invalid');
if ($error.length) {
$error.text('Questo campo è obbligatorio').show();
} else {
$field.after('<span class="form-error">Questo campo è obbligatorio</span>');
}
} else {
$field.removeClass('is-invalid');
$error.hide();
// Email validation
if ($field.attr('type') === 'email') {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
isValid = false;
$field.addClass('is-invalid');
if ($error.length) {
$error.text('Inserisci un\'email valida').show();
} else {
$field.after('<span class="form-error">Inserisci un\'email valida</span>');
}
}
}
}
});
if (!isValid) {
e.preventDefault();
// Scroll to first error
const $firstError = $form.find('.is-invalid').first();
if ($firstError.length) {
$('html, body').animate({
scrollTop: $firstError.offset().top - 100
}, 500);
}
}
});
// Clear error on input
$form.find('input, textarea').on('input', function() {
$(this).removeClass('is-invalid');
$(this).siblings('.form-error').hide();
});
// Form submission success (AJAX example with Formspree)
$form.on('submit', function(e) {
e.preventDefault();
$submitBtn.prop('disabled', true).text('Invio in corso...');
$.ajax({
url: $form.attr('action'),
method: 'POST',
data: $form.serialize(),
headers: { 'Accept': 'application/json' }
})
.done(function(response) {
$form.trigger('reset');
$submitBtn.text('Messaggio Inviato!');
// Show success message
$form.after('<div class="form-success">Grazie! Ti contatteremo presto.</div>');
setTimeout(function() {
$submitBtn.prop('disabled', false).text('Invia Messaggio');
$('.form-success').fadeOut();
}, 3000);
})
.fail(function() {
$submitBtn.prop('disabled', false).text('Riprova');
$form.after('<div class="form-error">Errore nell\'invio. Riprova più tardi.</div>');
});
});
});
```
### Back to Top Button
```javascript
$(function() {
const $backToTop = $('.back-to-top');
// Show/hide on scroll
$(window).on('scroll', function() {
if ($(window).scrollTop() > 300) {
$backToTop.addClass('is-visible');
} else {
$backToTop.removeClass('is-visible');
}
});
// Smooth scroll to top
$backToTop.on('click', function(e) {
e.preventDefault();
$('html, body').animate({
scrollTop: 0
}, 800);
});
});
```
```html
<!-- HTML for back to top -->
<a href="#top" class="back-to-top" aria-label="Torna su">
<svg><!-- icon --></svg>
</a>
```
```css
.back-to-top {
position: fixed;
bottom: 32px;
right: 32px;
width: 48px;
height: 48px;
background: var(--color-primary);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 100;
}
.back-to-top.is-visible {
opacity: 1;
visibility: visible;
}
.back-to-top:hover {
background: var(--color-primary-dark);
transform: translateY(-4px);
}
```
### Image Lazy Loading
```javascript
$(function() {
const $lazyImages = $('img[loading="lazy"]');
// Native lazy loading support check
if ('loading' in HTMLImageElement.prototype) {
// Browser supports native lazy loading
$lazyImages.each(function() {
const src = $(this).data('src');
if (src) {
$(this).attr('src', src);
}
});
} else {
// Fallback for browsers without support
const imageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const $img = $(entry.target);
const src = $img.data('src');
if (src) {
$img.attr('src', src);
$img.on('load', function() {
$img.addClass('is-loaded');
});
}
observer.unobserve(entry.target);
}
});
});
$lazyImages.each(function() {
imageObserver.observe(this);
});
}
});
```
---
## GSAP Animations
### Basic Animations
```javascript
$(function() {
// Fade in element
gsap.from('.hero h1', {
duration: 1,
opacity: 0,
y: 30,
ease: 'power3.out'
});
// Stagger animation
gsap.from('.service-card', {
duration: 0.8,
opacity: 0,
y: 40,
stagger: 0.15,
ease: 'power3.out',
delay: 0.3
});
// Multiple properties
gsap.from('.hero .btn', {
duration: 1,
opacity: 0,
y: 20,
scale: 0.95,
delay: 0.5,
ease: 'back.out(1.7)'
});
});
```
### Timeline
```javascript
$(function() {
const tl = gsap.timeline({ defaults: { ease: 'power3.out' } });
tl.from('.hero h1', {
duration: 1,
opacity: 0,
y: 50
})
.from('.hero-sub', {
duration: 0.8,
opacity: 0,
y: 30
}, '-=0.5')
.from('.hero .btn', {
duration: 0.6,
opacity: 0,
y: 20
}, '-=0.4')
.from('.logo-wall', {
duration: 1,
opacity: 0
}, '-=0.3');
});
```
### ScrollTrigger Animations
```javascript
// Register ScrollTrigger
gsap.registerPlugin(ScrollTrigger);
$(function() {
// Fade in on scroll
gsap.utils.toArray('.fade-on-scroll').forEach(function(elem) {
gsap.to(elem, {
scrollTrigger: {
trigger: elem,
start: 'top 85%',
toggleActions: 'play none none none'
},
opacity: 1,
y: 0,
duration: 1,
ease: 'power3.out'
});
});
// Slide in from left
gsap.utils.toArray('.slide-in-left').forEach(function(elem) {
gsap.from(elem, {
scrollTrigger: {
trigger: elem,
start: 'top 80%',
toggleActions: 'play none none none'
},
opacity: 0,
x: -50,
duration: 1,
ease: 'power3.out'
});
});
// Slide in from right
gsap.utils.toArray('.slide-in-right').forEach(function(elem) {
gsap.from(elem, {
scrollTrigger: {
trigger: elem,
start: 'top 80%',
toggleActions: 'play none none none'
},
opacity: 0,
x: 50,
duration: 1,
ease: 'power3.out'
});
});
// Scale up
gsap.utils.toArray('.scale-up').forEach(function(elem) {
gsap.from(elem, {
scrollTrigger: {
trigger: elem,
start: 'top 85%',
toggleActions: 'play none none none'
},
opacity: 0,
scale: 0.8,
duration: 1,
ease: 'back.out(1.7)'
});
});
// Parallax effect
gsap.to('.parallax-bg', {
scrollTrigger: {
trigger: '.hero',
start: 'top top',
end: 'bottom top',
scrub: true
},
y: 100,
ease: 'none'
});
// Pin section (sticky)
gsap.to('.sticky-section', {
scrollTrigger: {
trigger: '.sticky-section',
start: 'top top',
end: '+=100%',
pin: true,
scrub: true
}
});
});
```
### Hover Animations
```javascript
$(function() {
// Card hover with GSAP
const $cards = $('.service-card');
$cards.each(function() {
const $card = $(this);
$card.on('mouseenter', function() {
gsap.to($card, {
duration: 0.3,
y: -8,
boxShadow: '0 12px 32px rgba(0, 0, 0, 0.15)',
ease: 'power2.out'
});
});
$card.on('mouseleave', function() {
gsap.to($card, {
duration: 0.3,
y: 0,
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
ease: 'power2.out'
});
});
});
// Button hover
const $buttons = $('.btn');
$buttons.each(function() {
const $btn = $(this);
$btn.on('mouseenter', function() {
gsap.to($btn, {
duration: 0.2,
scale: 1.05,
ease: 'power2.out'
});
});
$btn.on('mouseleave', function() {
gsap.to($btn, {
duration: 0.2,
scale: 1,
ease: 'power2.out'
});
});
});
});
```
### Complex Animation Sequence
```javascript
$(function() {
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.feature-section',
start: 'top 70%',
toggleActions: 'play none none none'
}
});
tl.from('.feature-section h2', {
duration: 0.8,
opacity: 0,
y: 30,
ease: 'power3.out'
})
.from('.feature-section p', {
duration: 0.6,
opacity: 0,
y: 20
}, '-=0.4')
.from('.feature-grid .feature-card', {
duration: 0.6,
opacity: 0,
y: 40,
stagger: 0.1,
ease: 'back.out(1.7)'
}, '-=0.3')
.from('.feature-section .btn', {
duration: 0.5,
opacity: 0,
scale: 0.9
}, '-=0.3');
});
```
---
## Performance Best Practices
### Reduce Motion
```javascript
// Check for reduced motion preference
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
// Disable GSAP animations
gsap.globalTimeline.timeScale(0);
// Or set duration to 0
gsap.defaults({ duration: 0 });
}
```
### Debounce Scroll Events
```javascript
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Usage
$(window).on('scroll', debounce(function() {
// Scroll logic here
}, 100));
```
### Use CSS for Simple Animations
```css
/* Prefer CSS transitions for simple hover effects */
.btn {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.btn:hover {
transform: translateY(-2px);
}
/* Use GSAP only for complex animations */
```
---
## Accessibility
### Respect User Preferences
```javascript
// Check reduced motion
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReducedMotion) {
// Initialize animations
initAnimations();
}
function initAnimations() {
// GSAP animations here
}
```
### Focus Management
```javascript
// Trap focus in mobile menu
function trapFocus($element) {
const $focusable = $element.find('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
const $first = $focusable.first();
const $last = $focusable.last();
$element.on('keydown', function(e) {
if (e.key === 'Tab') {
if (e.shiftKey) {
if (document.activeElement === $first[0]) {
e.preventDefault();
$last.focus();
}
} else {
if (document.activeElement === $last[0]) {
e.preventDefault();
$first.focus();
}
}
}
});
}
```
---
## Checklist Interattività
- [ ] Mobile menu toggle funzionante
- [ ] Smooth scroll per anchor links
- [ ] FAQ accordion accessibile
- [ ] Form validation con feedback
- [ ] Back to top button (se pagine lunghe)
- [ ] Lazy loading immagini
- [ ] GSAP animations (hero, scroll)
- [ ] Hover effects su cards/buttons
- [ ] Respect reduced motion preference
- [ ] Keyboard navigation testata
- [ ] No console errors
- [ ] Performance ottimizzata (debounce, CSS where possible)
---
_References per agency-web-developer skill_