sexyjekyll-theme 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +82 -0
  3. data/LICENSE +21 -0
  4. data/README.de.md +276 -0
  5. data/README.es.md +276 -0
  6. data/README.fr.md +276 -0
  7. data/README.it.md +219 -0
  8. data/README.md +276 -0
  9. data/_includes/critical-css.html +4 -0
  10. data/_includes/footer.html +81 -0
  11. data/_includes/head.html +88 -0
  12. data/_includes/nav.html +21 -0
  13. data/_includes/related-posts.html +75 -0
  14. data/_includes/social-icon.html +98 -0
  15. data/_includes/structured-data-article.html +55 -0
  16. data/_includes/structured-data-breadcrumb.html +28 -0
  17. data/_includes/structured-data-person.html +82 -0
  18. data/_includes/structured-data-website.html +23 -0
  19. data/_layouts/blog.html +101 -0
  20. data/_layouts/category.html +66 -0
  21. data/_layouts/contact.html +26 -0
  22. data/_layouts/default.html +13 -0
  23. data/_layouts/home.html +30 -0
  24. data/_layouts/llms.txt +34 -0
  25. data/_layouts/post.html +99 -0
  26. data/_plugins/auto_related_posts.rb +153 -0
  27. data/_plugins/category_generator.rb +27 -0
  28. data/_plugins/llms_txt_generator.rb +45 -0
  29. data/_plugins/localized_date.rb +52 -0
  30. data/assets/bg.jpeg +0 -0
  31. data/assets/bg.webp +0 -0
  32. data/assets/debug/blocco.png +0 -0
  33. data/assets/debug/categorie.jpeg +0 -0
  34. data/assets/debug/categorie.png +0 -0
  35. data/assets/debug/codice.png +0 -0
  36. data/assets/debug/contrasto.jpeg +0 -0
  37. data/assets/debug/dipendenze.png +0 -0
  38. data/assets/debug/h1.png +0 -0
  39. data/assets/debug/pagespeed.png +0 -0
  40. data/assets/debug/ricerca.png +0 -0
  41. data/assets/debug/richieste.png +0 -0
  42. data/assets/favicon/android-icon-144x144.png +0 -0
  43. data/assets/favicon/android-icon-192x192.png +0 -0
  44. data/assets/favicon/android-icon-36x36.png +0 -0
  45. data/assets/favicon/android-icon-48x48.png +0 -0
  46. data/assets/favicon/android-icon-72x72.png +0 -0
  47. data/assets/favicon/android-icon-96x96.png +0 -0
  48. data/assets/favicon/apple-icon-114x114.png +0 -0
  49. data/assets/favicon/apple-icon-120x120.png +0 -0
  50. data/assets/favicon/apple-icon-144x144.png +0 -0
  51. data/assets/favicon/apple-icon-152x152.png +0 -0
  52. data/assets/favicon/apple-icon-180x180.png +0 -0
  53. data/assets/favicon/apple-icon-57x57.png +0 -0
  54. data/assets/favicon/apple-icon-60x60.png +0 -0
  55. data/assets/favicon/apple-icon-72x72.png +0 -0
  56. data/assets/favicon/apple-icon-76x76.png +0 -0
  57. data/assets/favicon/apple-icon-precomposed.png +0 -0
  58. data/assets/favicon/apple-icon.png +0 -0
  59. data/assets/favicon/favicon-16x16.png +0 -0
  60. data/assets/favicon/favicon-32x32.png +0 -0
  61. data/assets/favicon/favicon-96x96.png +0 -0
  62. data/assets/favicon/favicon.ico +0 -0
  63. data/assets/favicon/ms-icon-144x144.png +0 -0
  64. data/assets/favicon/ms-icon-150x150.png +0 -0
  65. data/assets/favicon/ms-icon-310x310.png +0 -0
  66. data/assets/favicon/ms-icon-70x70.png +0 -0
  67. data/assets/images/aiact.jpeg +0 -0
  68. data/assets/images/aiethics.jpeg +0 -0
  69. data/assets/images/green.jpeg +0 -0
  70. data/assets/images/jekyll.webp +0 -0
  71. data/assets/images/parenting.jpeg +0 -0
  72. data/assets/images/seo-generativo.jpeg +0 -0
  73. data/assets/images/upskilling-ai.jpeg +0 -0
  74. data/assets/pic.jpeg +0 -0
  75. data/assets/screens/screen.jpeg +0 -0
  76. data/assets/screens/screen2.jpeg +0 -0
  77. data/css/animations.css +404 -0
  78. data/css/style.css +2250 -0
  79. data/css/syntax-dark.css +157 -0
  80. data/css/syntax-light.css +157 -0
  81. data/js/main.js +706 -0
  82. data/js/simple-jekyll-search.min.js +6 -0
  83. metadata +254 -0
data/README.md ADDED
@@ -0,0 +1,276 @@
1
+ # SexyJekyll Theme
2
+
3
+ A modern, feature-rich Jekyll theme designed for professional blogs and personal websites. Built with accessibility, performance, and user experience in mind.
4
+
5
+ ![SexyJekyll Theme](screenshot.png)
6
+
7
+ ## Features
8
+
9
+ ### Design & User Experience
10
+ - **Modern Design**: Clean, minimalist aesthetic
11
+ - **Fully Responsive**: Mobile-first design that works on all devices
12
+ - **Reading Progress**: Visual indicator showing article reading progress
13
+ - **Print Styles**: Optimized layouts for printing
14
+
15
+ ### Content & Navigation
16
+ - **Advanced Search**: Instant client-side search with keyword highlighting
17
+ - **Related Posts**: Smart post recommendations based on categories and tags
18
+ - **Categories**: Category-based filtering and organization
19
+ - **Pagination**: Customizable post pagination
20
+
21
+ ### SEO & Social
22
+ - **SEO Optimized**: Meta tags, Open Graph, Twitter Cards
23
+ - **Structured Data**: JSON-LD schema for better search engine understanding
24
+ - **RSS Feed**: Automatic feed generation
25
+ - **Sitemap**: Auto-generated sitemap for search engines
26
+
27
+ ### Accessibility
28
+ - **WCAG 2.1 Level AA**: Comprehensive accessibility support
29
+ - **Skip to Content**: Keyboard navigation helpers
30
+ - **Semantic HTML**: Proper HTML5 landmarks and structure
31
+ - **ARIA Labels**: Screen reader friendly
32
+ - **Reduced Motion**: Respects user motion preferences
33
+ - **High Contrast**: Excellent color contrast ratios
34
+
35
+ ### Performance
36
+ - **Responsive Images**: WebP format with multiple sizes
37
+ - **Lazy Loading**: Images load as needed
38
+ - **Optimized CSS/JS**: Minified and efficient code
39
+ - **Fast Load Times**: Optimized for performance
40
+
41
+ ### Developer Features
42
+ - **Syntax Highlighting**: Code blocks with line numbers (Rouge)
43
+ - **Reading Time**: Automatic reading time estimation
44
+ - **Multi-language**: Full i18n system supporting English, Italian, German, French, and Spanish
45
+ - **Customizable**: Easy configuration via `_config.yml`
46
+ - **Well Documented**: Comprehensive documentation included
47
+
48
+ ### AI & LLM Features
49
+ - **llms.txt Support**: Automatic generation of AI-friendly content summaries
50
+ - **Per-Post llms.txt**: Each blog post generates its own dedicated llms.txt file at `/blog/YYYY/MM/DD/post-slug/llms.txt`
51
+ - **Site-level llms.txt**: Main llms.txt file at root with site overview and content structure
52
+ - **Structured Content**: Clean, semantic HTML5 markup optimized for AI crawlers
53
+ - **JSON-LD Schema**: Rich structured data for better content understanding
54
+ - **AI Crawler Friendly**: Welcoming approach to AI indexing with clear instructions
55
+
56
+ ## Installation
57
+
58
+ ### As a Ruby Gem (Recommended)
59
+
60
+ Add this line to your Jekyll site's `Gemfile`:
61
+
62
+ ```ruby
63
+ gem "sexyjekyll-theme"
64
+ ```
65
+
66
+ And add this line to your Jekyll site's `_config.yml`:
67
+
68
+ ```yaml
69
+ theme: sexyjekyll-theme
70
+ ```
71
+
72
+ Then execute:
73
+
74
+ ```bash
75
+ bundle install
76
+ ```
77
+
78
+ ### Remote Theme (GitHub Pages)
79
+
80
+ If you're using GitHub Pages, add this to your `_config.yml`:
81
+
82
+ ```yaml
83
+ remote_theme: amargiovanni/sexyjekyll-theme
84
+ ```
85
+
86
+ ### Manual Installation
87
+
88
+ 1. Download or clone this repository
89
+ 2. Copy the files to your Jekyll site
90
+ 3. Update your `_config.yml` with the theme settings
91
+
92
+ ## Quick Start
93
+
94
+ 1. **Install the theme** using one of the methods above
95
+
96
+ 2. **Configure** your `_config.yml`:
97
+
98
+ ```yaml
99
+ # Site settings
100
+ title: Your Name
101
+ email: your.email@example.com
102
+ description: Your site description
103
+ baseurl: ""
104
+ url: "https://yoursite.com"
105
+ lang: en # Options: en, it, de, fr, es
106
+
107
+ # Author information
108
+ author:
109
+ name: Your Name
110
+ email: your.email@example.com
111
+ linkedin: https://www.linkedin.com/in/yourprofile/
112
+ bluesky: https://bsky.app/profile/yourhandle
113
+
114
+ # Navigation logo
115
+ nav_logo:
116
+ type: text # 'text' or 'image'
117
+ text: YN # Your initials or text
118
+ # image: /assets/img/logo.png # Or path to logo image
119
+ # alt: Your Logo
120
+
121
+ # Hero section
122
+ hero:
123
+ name: Your Name
124
+ role: Your Role
125
+ subtitle: Your Company or Tagline
126
+ tagline: Your personal tagline
127
+ description: A brief description about you
128
+
129
+ # Blog section
130
+ blog:
131
+ title: Blog
132
+ description: Your blog description
133
+
134
+ # Contact section
135
+ contact:
136
+ title: Get In Touch
137
+ description: Contact page description
138
+ links:
139
+ - name: Email
140
+ url: mailto:your.email@example.com
141
+ type: email
142
+ - name: LinkedIn
143
+ url: https://www.linkedin.com/in/yourprofile/
144
+ type: linkedin
145
+ ```
146
+
147
+ 3. **Create your first post** in `_posts/`:
148
+
149
+ ```markdown
150
+ ---
151
+ layout: post
152
+ title: "Your First Post"
153
+ subtitle: "Optional subtitle"
154
+ date: 2025-11-01
155
+ categories: blog tech
156
+ ---
157
+
158
+ Your post content here...
159
+ ```
160
+
161
+ 4. **Run Jekyll**:
162
+
163
+ ```bash
164
+ bundle exec jekyll serve
165
+ ```
166
+
167
+ Visit `http://localhost:4000` to see your site!
168
+
169
+ ## Configuration
170
+
171
+ ### Available Layouts
172
+
173
+ - `default` - Base layout for all pages
174
+ - `home` - Homepage with hero section
175
+ - `blog` - Blog listing page
176
+ - `post` - Individual blog post
177
+ - `about` - About page
178
+ - `contact` - Contact page with social links
179
+ - `category` - Category-specific post listing
180
+ - `404` - Custom 404 error page
181
+
182
+ ### Plugins
183
+
184
+ The theme uses these Jekyll plugins:
185
+
186
+ **Standard Plugins:**
187
+ - `jekyll-feed` - RSS feed generation
188
+ - `jekyll-seo-tag` - SEO meta tags
189
+ - `jekyll-paginate` - Post pagination
190
+ - `jekyll-sitemap` - Sitemap generation
191
+ - `liquid_reading_time` - Reading time estimation
192
+ - `jekyll_picture_tag` - Responsive images
193
+
194
+ **Custom Plugins:**
195
+ - `llms_txt_generator` - Automatically generates llms.txt files for each blog post and creates AI-friendly content summaries
196
+ - `auto_related_posts` - Intelligent post recommendation system based on categories, tags, and content similarity using TF-IDF-like algorithm
197
+ - `category_generator` - Automatically creates dedicated pages for each category with filtered post listings
198
+ - `localized_date` - Liquid filter for formatting dates according to the selected language (e.g., "15 January 2025" in English, "15 gennaio 2025" in Italian)
199
+
200
+ ### Customization
201
+
202
+ #### Colors and Styles
203
+
204
+ Edit `css/style.css` to customize colors, fonts, and styles.
205
+
206
+ #### Social Links
207
+
208
+ Configure social links in `_config.yml` under `contact.links`. Supported types:
209
+ - email, linkedin, bluesky, twitter, github, instagram, facebook
210
+ - youtube, mastodon, telegram, whatsapp, medium, reddit
211
+ - discord, tiktok, twitch, slack
212
+
213
+ ## Documentation
214
+
215
+ Detailed documentation is available in the following files:
216
+
217
+ - [I18N.md](docs/I18N.md) - Internationalization system and language support
218
+ - [ACCESSIBILITY.md](docs/ACCESSIBILITY.md) - Accessibility features and testing
219
+ - [SEARCH.md](docs/SEARCH.md) - Search functionality
220
+ - [READING_PROGRESS.md](docs/READING_PROGRESS.md) - Reading progress indicator
221
+ - [STRUCTURED_DATA.md](docs/STRUCTURED_DATA.md) - SEO structured data
222
+ - [SOCIAL_SHARE.md](SOCIAL_SHARE.md) - How to add social sharing (optional)
223
+ - [COMMENTS.md](docs/COMMENTS.md) - How to add comments (optional)
224
+ - [CHANGELOG.md](CHANGELOG.md) - Version history
225
+ - [PUBLISHING.md](PUBLISHING.md) - Guide to publish your theme
226
+
227
+ ### Available in Multiple Languages
228
+
229
+ - 🇬🇧 [README.md](README.md) - English
230
+ - 🇮🇹 [README.it.md](README.it.md) - Italian
231
+ - 🇩🇪 [README.de.md](README.de.md) - German
232
+ - 🇫🇷 [README.fr.md](README.fr.md) - French
233
+ - 🇪🇸 [README.es.md](README.es.md) - Spanish
234
+
235
+ ## Browser Support
236
+
237
+ - Chrome (latest)
238
+ - Firefox (latest)
239
+ - Safari (latest)
240
+ - Edge (latest)
241
+ - Mobile browsers (iOS Safari, Chrome Mobile)
242
+
243
+ ## Contributing
244
+
245
+ Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
246
+
247
+ 1. Fork the repository
248
+ 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
249
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
250
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
251
+ 5. Open a Pull Request
252
+
253
+ ## Support
254
+
255
+ If you encounter any issues or have questions:
256
+
257
+ - Open an issue on [GitHub](https://github.com/amargiovanni/sexyjekyll-theme/issues)
258
+ - Check the [documentation](https://github.com/amargiovanni/sexyjekyll-theme#readme)
259
+
260
+ ## License
261
+
262
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
263
+
264
+ ## Credits
265
+
266
+ Created by [Andrea Margiovanni](https://margiovanni.it)
267
+
268
+ ## Acknowledgments
269
+
270
+ - Built with [Jekyll](https://jekyllrb.com/)
271
+ - Syntax highlighting by [Rouge](https://github.com/rouge-ruby/rouge)
272
+ - Icons and design inspiration from modern web design trends
273
+
274
+ ---
275
+
276
+ If you find this theme useful, please consider giving it a star on GitHub!
@@ -0,0 +1,4 @@
1
+ <style>
2
+ /* Critical CSS - Inline per LCP ottimizzato */
3
+ :root{--bg-primary:#0f0f23;--bg-secondary:rgba(20,20,40,.7);--bg-elevated:rgba(30,30,60,.8);--text-primary:#fff;--text-secondary:#e0e0ff;--text-tertiary:#a0a0d0;--nav-bg:rgba(15,15,35,.6);--color-purple:#a855f7;--color-pink:#ec4899;--color-blue:#3b82f6;--color-cyan:#06b6d4;--accent:#a855f7;--accent-hover:#c084fc;--border:rgba(168,85,247,.2);--font-heading:'Sora',system-ui,sans-serif;--font-body:'Plus Jakarta Sans',system-ui,sans-serif;--spacing-xs:.5rem;--spacing-sm:1rem;--spacing-md:1.5rem;--spacing-lg:2rem;--spacing-xl:3rem;--spacing-2xl:4rem;--spacing-3xl:6rem;--radius-sm:.5rem;--radius-md:1rem;--radius-lg:1.5rem;--radius-full:9999px;--transition-fast:.15s cubic-bezier(.4,0,.2,1);--transition-base:.3s cubic-bezier(.4,0,.2,1)}*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:var(--font-body);background-color:var(--bg-primary);background-image:url('/assets/bg.webp');background-size:cover;background-position:center;background-repeat:no-repeat;background-attachment:fixed;color:var(--text-primary);line-height:1.7;font-size:18px;overflow-x:hidden;position:relative}h1{font-size:inherit}section h1{font-size:clamp(3rem,8vw,6rem)}.nav{position:sticky;top:0;left:0;right:0;z-index:1000;background:var(--nav-bg);backdrop-filter:blur(20px) saturate(180%);border-bottom:1px solid var(--border);transition:all var(--transition-base);box-shadow:0 4px 30px rgba(0,0,0,.15)}.nav-container{max-width:1400px;margin:0 auto;padding:1.5rem var(--spacing-lg);display:flex;justify-content:space-between;align-items:center}.nav-logo{font-family:var(--font-heading);font-size:2rem;font-weight:800;background:linear-gradient(135deg,var(--color-purple) 0%,var(--color-pink) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;text-decoration:none;transition:transform var(--transition-base);display:inline-flex;align-items:center}.nav-logo-image{height:2.5rem;width:auto;max-width:12rem;object-fit:contain;display:block;border-radius:50%}.nav-links{display:flex;gap:var(--spacing-xl)}.nav-link{color:var(--text-secondary);text-decoration:none;font-weight:600;font-size:1.1rem;transition:all var(--transition-base);position:relative;padding:.5rem 0}.hero{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:var(--spacing-3xl) var(--spacing-lg);position:relative}.hero-container{max-width:1100px;margin:0 auto;width:100%}.hero-content{text-align:center}.hero-name{display:block;font-family:var(--font-heading);font-size:clamp(3rem,8vw,6rem);font-weight:800;line-height:1.1;margin-bottom:var(--spacing-md);background:linear-gradient(135deg,var(--color-purple) 0%,var(--color-pink) 50%,var(--color-cyan) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;letter-spacing:-.02em}@media (max-width:768px){body{font-size:16px}.nav-container{padding:1.25rem var(--spacing-md)}.nav-logo{font-size:1.6rem}.nav-links{gap:var(--spacing-lg)}.hero{padding:var(--spacing-2xl) var(--spacing-md);min-height:calc(100vh - 70px)}}
4
+ </style>
@@ -0,0 +1,81 @@
1
+ {% assign t = site.data.i18n[site.lang] %}
2
+ <footer class="footer">
3
+ <div class="footer-container">
4
+ <div class="footer-grid">
5
+ <!-- Column 1: About Section -->
6
+ <div class="footer-section">
7
+ <p class="footer-title">{{ site.author.name }}</p>
8
+ <p class="footer-description">{{ site.description }}</p>
9
+ </div>
10
+
11
+ <!-- Column 2: Navigation -->
12
+ <div class="footer-section">
13
+ <p class="footer-title">{{ t.footer.navigation }}</p>
14
+ <ul class="footer-links">
15
+ <li><a href="{{ '/' | relative_url }}">{{ t.nav.home }}</a></li>
16
+ <li><a href="{{ '/blog' | relative_url }}">{{ t.nav.blog }}</a></li>
17
+ <li><a href="{{ '/categories' | relative_url }}">{{ t.nav.categories }}</a></li>
18
+ <li><a href="{{ '/contact' | relative_url }}">{{ t.nav.contacts }}</a></li>
19
+ </ul>
20
+ </div>
21
+
22
+ <!-- Column 3: Social Links -->
23
+ <div class="footer-section">
24
+ <p class="footer-title">{{ t.footer.follow_me }}</p>
25
+ <ul class="footer-links footer-contact-list">
26
+ {% for link in site.contact.links %}
27
+ <li>
28
+ <a href="{{ link.url }}" class="footer-contact-link" {% if link.type != 'email' %}target="_blank" rel="noopener noreferrer"{% endif %}>
29
+ <span class="contact-icon">
30
+ {% case link.type %}
31
+ {% when 'email' %}
32
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
33
+ {% when 'linkedin' %}
34
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>
35
+ {% when 'github' %}
36
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
37
+ {% when 'instagram' %}
38
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg>
39
+ {% when 'bluesky' %}
40
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg>
41
+ {% when 'mastodon' %}
42
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M21.327 8.566c0-4.339-2.843-5.61-2.843-5.61-1.433-.658-3.894-.935-6.451-.956h-.063c-2.557.021-5.016.298-6.45.956 0 0-2.843 1.272-2.843 5.61 0 .993-.019 2.181.012 3.441.103 4.243.778 8.425 4.701 9.463 1.809.479 3.362.579 4.612.51 2.268-.126 3.541-.809 3.541-.809l-.075-1.646s-1.621.511-3.441.449c-1.804-.062-3.707-.194-3.999-2.409a4.523 4.523 0 0 1-.04-.621s1.77.433 4.014.536c1.372.063 2.658-.08 3.965-.236 2.506-.299 4.688-1.843 4.962-3.254.434-2.223.398-5.424.398-5.424zm-3.353 5.59h-2.081V9.057c0-1.075-.452-1.62-1.357-1.62-1 0-1.501.647-1.501 1.927v2.791h-2.069V9.364c0-1.28-.501-1.927-1.502-1.927-.905 0-1.357.546-1.357 1.62v5.099H6.026V8.903c0-1.074.273-1.927.823-2.558.566-.631 1.307-.955 2.228-.955 1.065 0 1.872.409 2.405 1.228l.518.869.519-.869c.533-.819 1.34-1.228 2.405-1.228.92 0 1.662.324 2.228.955.549.631.822 1.484.822 2.558v5.253z"/></svg>
43
+ {% else %}
44
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
45
+ {% endcase %}
46
+ </span>
47
+ <span class="contact-label">{{ link.name }}</span>
48
+ </a>
49
+ </li>
50
+ {% endfor %}
51
+ </ul>
52
+ </div>
53
+
54
+ <!-- Column 4: Built With -->
55
+ <div class="footer-section">
56
+ <p class="footer-title">{{ t.footer.built_with }}</p>
57
+ <a href="https://jekyllrb.com" target="_blank" rel="noopener noreferrer" style="display: inline-block; margin-bottom: var(--spacing-xs);">
58
+ <img src="{{ '/assets/images/jekyll.webp' | relative_url }}" alt="Jekyll" style="height: 40px; width: auto; opacity: 0.9; transition: opacity var(--transition-base);" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.9'">
59
+ </a>
60
+ <p class="footer-description">
61
+ {{ t.footer.jekyll_description }}
62
+ </p>
63
+ </div>
64
+ </div>
65
+
66
+ <!-- Bottom Bar -->
67
+ <div class="footer-bottom">
68
+ <div class="footer-license">
69
+ <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener noreferrer" class="cc-license">
70
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
71
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"/>
72
+ </svg>
73
+ <span>{{ t.footer.license }}</span>
74
+ </a>
75
+ <span class="separator">·</span>
76
+ <span>&copy; {{ 'now' | date: "%Y" }} {{ site.author.name }}</span>
77
+ </div>
78
+ <p class="footer-tagline">{{ t.footer.made_with_love }} <a href="https://margiovanni.it" title="Andrea">Andrea</a></p>
79
+ </div>
80
+ </div>
81
+ </footer>
@@ -0,0 +1,88 @@
1
+ {% assign t = site.data.i18n[site.lang] %}
2
+ <head>
3
+ <meta charset="UTF-8">
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta name="description" content="{% if page.description %}{{ page.description }}{% else %}{{ site.description }}{% endif %}">
6
+ <meta name="author" content="{{ site.author.name }}">
7
+ <meta name="keywords" content="{% if page.keywords %}{{ page.keywords }}{% else %}{{ t.seo.default_keywords }}{% endif %}">
8
+
9
+ <!-- AI Crawlers Meta Tags -->
10
+ <meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
11
+ <meta property="article:author" content="{{ site.author.name }}">
12
+ {% if page.date %}
13
+ <meta property="article:published_time" content="{{ page.date | date_to_xmlschema }}">
14
+ <meta property="article:modified_time" content="{{ page.date | date_to_xmlschema }}">
15
+ {% endif %}
16
+ {% if page.categories %}
17
+ {% for category in page.categories %}
18
+ <meta property="article:tag" content="{{ category }}">
19
+ {% endfor %}
20
+ {% endif %}
21
+ <link rel="canonical" href="{{ page.url | absolute_url }}">
22
+
23
+ <!-- Open Graph -->
24
+ <meta property="og:title" content="{% if page.title %}{{ page.title }} - {{ site.title }}{% else %}{{ site.title }}{% endif %}">
25
+ <meta property="og:description" content="{% if page.description %}{{ page.description }}{% else %}{{ site.description }}{% endif %}">
26
+ <meta property="og:type" content="{% if page.layout == 'post' %}article{% else %}website{% endif %}">
27
+ {% if page.image %}
28
+ <meta property="og:image" content="{{ page.image | absolute_url }}">
29
+ {% endif %}
30
+
31
+ <title>{% if page.title %}{{ page.title }} - {{ site.title }}{% else %}{{ site.title }}{% endif %}</title>
32
+
33
+ <!-- Favicon -->
34
+ <link rel="apple-touch-icon" sizes="57x57" href="{{ '/assets/favicon/apple-icon-57x57.png' | relative_url }}">
35
+ <link rel="apple-touch-icon" sizes="60x60" href="{{ '/assets/favicon/apple-icon-60x60.png' | relative_url }}">
36
+ <link rel="apple-touch-icon" sizes="72x72" href="{{ '/assets/favicon/apple-icon-72x72.png' | relative_url }}">
37
+ <link rel="apple-touch-icon" sizes="76x76" href="{{ '/assets/favicon/apple-icon-76x76.png' | relative_url }}">
38
+ <link rel="apple-touch-icon" sizes="114x114" href="{{ '/assets/favicon/apple-icon-114x114.png' | relative_url }}">
39
+ <link rel="apple-touch-icon" sizes="120x120" href="{{ '/assets/favicon/apple-icon-120x120.png' | relative_url }}">
40
+ <link rel="apple-touch-icon" sizes="144x144" href="{{ '/assets/favicon/apple-icon-144x144.png' | relative_url }}">
41
+ <link rel="apple-touch-icon" sizes="152x152" href="{{ '/assets/favicon/apple-icon-152x152.png' | relative_url }}">
42
+ <link rel="apple-touch-icon" sizes="180x180" href="{{ '/assets/favicon/apple-icon-180x180.png' | relative_url }}">
43
+ <link rel="icon" type="image/png" sizes="192x192" href="{{ '/assets/favicon/android-icon-192x192.png' | relative_url }}">
44
+ <link rel="icon" type="image/png" sizes="32x32" href="{{ '/assets/favicon/favicon-32x32.png' | relative_url }}">
45
+ <link rel="icon" type="image/png" sizes="96x96" href="{{ '/assets/favicon/favicon-96x96.png' | relative_url }}">
46
+ <link rel="icon" type="image/png" sizes="16x16" href="{{ '/assets/favicon/favicon-16x16.png' | relative_url }}">
47
+ <link rel="shortcut icon" href="{{ '/assets/favicon/favicon.ico' | relative_url }}">
48
+ <meta name="msapplication-TileColor" content="#ffffff">
49
+ <meta name="msapplication-TileImage" content="{{ '/assets/favicon/ms-icon-144x144.png' | relative_url }}">
50
+ <meta name="theme-color" content="#ffffff">
51
+
52
+ <!-- Preconnect to external domains for faster resource loading -->
53
+ <link rel="preconnect" href="https://fonts.googleapis.com">
54
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
55
+
56
+ <!-- Preload risorse critiche -->
57
+ <link rel="preload" href="{{ '/assets/bg.webp' | relative_url }}" as="image" type="image/webp">
58
+
59
+ <!-- Critical CSS inline per LCP ottimizzato -->
60
+ {% include critical-css.html %}
61
+
62
+ <!-- Preload del CSS completo -->
63
+ <link rel="preload" href="{{ '/css/style.css' | relative_url }}?v={{ site.time | date: '%s' }}" as="style">
64
+
65
+ <!-- CSS completo caricato in modo asincrono -->
66
+ <link rel="stylesheet" href="{{ '/css/style.css' | relative_url }}?v={{ site.time | date: '%s' }}" media="print" onload="this.media='all';this.onload=null">
67
+ <noscript><link rel="stylesheet" href="{{ '/css/style.css' | relative_url }}?v={{ site.time | date: '%s' }}"></noscript>
68
+
69
+ <!-- Non-critical CSS preloaded and loaded asynchronously -->
70
+ <link rel="preload" href="{{ '/css/animations.css' | relative_url }}?v={{ site.time | date: '%s' }}" as="style" onload="this.onload=null;this.rel='stylesheet'">
71
+ <noscript><link rel="stylesheet" href="{{ '/css/animations.css' | relative_url }}?v={{ site.time | date: '%s' }}"></noscript>
72
+
73
+ <link rel="preload" href="{{ '/css/syntax-dark.css' | relative_url }}?v={{ site.time | date: '%s' }}" as="style" onload="this.onload=null;this.rel='stylesheet'">
74
+ <noscript><link rel="stylesheet" href="{{ '/css/syntax-dark.css' | relative_url }}?v={{ site.time | date: '%s' }}"></noscript>
75
+
76
+ <!-- Google Fonts loaded asynchronously -->
77
+ <link rel="preload" href="https://fonts.googleapis.com/css2?family=Sora:wght@400;500;600;700;800&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'">
78
+ <noscript><link href="https://fonts.googleapis.com/css2?family=Sora:wght@400;500;600;700;800&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"></noscript>
79
+
80
+ {% seo %}
81
+ {% feed_meta %}
82
+
83
+ <!-- Structured Data (JSON-LD) -->
84
+ {% include structured-data-website.html %}
85
+ {% include structured-data-person.html %}
86
+ {% include structured-data-article.html %}
87
+ {% include structured-data-breadcrumb.html %}
88
+ </head>
@@ -0,0 +1,21 @@
1
+ {% assign t = site.data.i18n[site.lang] %}
2
+ <a href="#main-content" class="skip-to-content">{{ t.nav.skip_to_content }}</a>
3
+
4
+ <nav class="nav" role="navigation" aria-label="{{ t.nav.main_navigation }}">
5
+ <div class="nav-container">
6
+ <a href="{{ '/' | relative_url }}" class="nav-logo" aria-label="{{ site.author.name }} - {{ t.nav.home }}">
7
+ {% if site.nav_logo.type == 'image' %}
8
+ <img src="{{ site.nav_logo.image | relative_url }}" alt="{{ site.nav_logo.alt | default: site.title }}" class="nav-logo-image">
9
+ {% elsif site.nav_logo.text %}
10
+ {{ site.nav_logo.text }}
11
+ {% else %}
12
+ {{ site.author.name | slice: 0, 2 | upcase }}
13
+ {% endif %}
14
+ </a>
15
+ <div class="nav-links">
16
+ <a href="{{ '/' | relative_url }}" class="nav-link {% if page.url == '/' or page.url == '/index.html' %}active{% endif %}" {% if page.url == '/' or page.url == '/index.html' %}aria-current="page"{% endif %}>{{ t.nav.home }}</a>
17
+ <a href="{{ '/blog' | relative_url }}" class="nav-link {% if page.url contains '/blog' %}active{% endif %}" {% if page.url contains '/blog' %}aria-current="page"{% endif %}>{{ t.nav.blog }}</a>
18
+ <a href="{{ '/contact' | relative_url }}" class="nav-link {% if page.url contains '/contact' %}active{% endif %}" {% if page.url contains '/contact' %}aria-current="page"{% endif %}>{{ t.nav.contacts }}</a>
19
+ </div>
20
+ </div>
21
+ </nav>
@@ -0,0 +1,75 @@
1
+ {% assign maxRelated = 4 %}
2
+
3
+ {% comment %}
4
+ This include finds related posts using:
5
+ 1. Auto-generated related posts (from auto_related_posts.rb plugin) - if available
6
+ 2. Fallback to manual category-based matching
7
+ {% endcomment %}
8
+
9
+ {% assign related_posts = "" | split: "" %}
10
+
11
+ {% comment %} Use auto-generated related posts if available {% endcomment %}
12
+ {% if page.auto_related_posts and page.auto_related_posts.size > 0 %}
13
+ {% assign related_posts = page.auto_related_posts %}
14
+ {% else %}
15
+ {% comment %} Fallback: Find posts with common categories {% endcomment %}
16
+ {% assign minCommonCategories = 1 %}
17
+
18
+ {% for post in site.posts %}
19
+ {% if post.url != page.url %}
20
+ {% assign commonCategories = 0 %}
21
+ {% for category in post.categories %}
22
+ {% if page.categories contains category %}
23
+ {% assign commonCategories = commonCategories | plus: 1 %}
24
+ {% endif %}
25
+ {% endfor %}
26
+
27
+ {% if commonCategories >= minCommonCategories %}
28
+ {% assign related_posts = related_posts | push: post %}
29
+ {% endif %}
30
+ {% endif %}
31
+ {% endfor %}
32
+
33
+ {% comment %} If we don't have enough related posts, add recent ones {% endcomment %}
34
+ {% if related_posts.size < maxRelated %}
35
+ {% for post in site.posts %}
36
+ {% if post.url != page.url %}
37
+ {% unless related_posts contains post %}
38
+ {% assign related_posts = related_posts | push: post %}
39
+ {% endunless %}
40
+ {% endif %}
41
+ {% if related_posts.size >= maxRelated %}
42
+ {% break %}
43
+ {% endif %}
44
+ {% endfor %}
45
+ {% endif %}
46
+ {% endif %}
47
+
48
+ {% if related_posts.size > 0 %}
49
+ {% assign t = site.data.i18n[site.lang] %}
50
+ <aside class="related-posts">
51
+ <h2 class="related-posts-title">{{ t.related.you_may_like }}</h2>
52
+ <div class="related-posts-grid">
53
+ {% for post in related_posts limit:maxRelated %}
54
+ <article class="related-post-card">
55
+ <time class="related-post-date" datetime="{{ post.date | date_to_xmlschema }}">
56
+ {{ post.date | localized_date }}
57
+ </time>
58
+ {% if post.categories %}
59
+ <div class="related-post-categories">
60
+ {% for category in post.categories %}
61
+ <span class="related-post-category">{{ category }}</span>
62
+ {% endfor %}
63
+ </div>
64
+ {% endif %}
65
+ <h3 class="related-post-title">
66
+ <a href="{{ post.url | relative_url }}">{{ post.title }}</a>
67
+ </h3>
68
+ {% if post.subtitle %}
69
+ <p class="related-post-subtitle">{{ post.subtitle }}</p>
70
+ {% endif %}
71
+ </article>
72
+ {% endfor %}
73
+ </div>
74
+ </aside>
75
+ {% endif %}