featmigrate from Angular to Astro static site

BREAKING CHANGE: Complete rewrite from Angular SPA to Astro

- Replace Angular 18 with Astro 5.16.7 + Tailwind CSS
- Convert all Angular components to Astro components
- Add content collections for blog with markdown support
- Setup S3 deployment with CloudFront invalidation
- Add RSS feed and sitemap generation
- Configure Prettier and Biome for code formatting
- Switch from npm to pnpm
- Remove Amplify backend (now fully static)
- Improve SEO and performance with static generation
This commit is contained in:
Lorenzo Iovino 2026-01-08 16:46:17 +01:00
parent cda19e8624
commit 69d5850f5b
191 changed files with 7821 additions and 21755 deletions

77
src/styles/global.css Normal file
View file

@ -0,0 +1,77 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
/* Ottimizzazione rendering font */
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
/* Typography base */
body {
@apply font-sans text-base text-gray-900;
font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
}
/* Headings ottimizzati */
h1,
h2,
h3,
h4,
h5,
h6 {
@apply font-bold;
font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "ss01" 1;
}
h1 {
@apply text-4xl md:text-5xl lg:text-6xl;
}
h2 {
@apply text-3xl md:text-4xl lg:text-5xl;
}
h3 {
@apply text-2xl md:text-3xl;
}
h4 {
@apply text-xl md:text-2xl;
}
/* Paragrafi ottimizzati */
p {
@apply leading-relaxed;
}
/* Link ottimizzati */
a {
@apply transition-colors duration-200;
}
/* Strong e emphasis */
strong,
b {
@apply font-semibold;
}
em,
i {
@apply italic;
}
}
@layer utilities {
/* Utility classes custom per typography */
.text-balance {
text-wrap: balance;
}
.text-pretty {
text-wrap: pretty;
}
}

395
src/styles/prose.css Normal file
View file

@ -0,0 +1,395 @@
.prose {
color: #1f2937 !important;
font-size: 1.125rem !important;
line-height: 1.875 !important;
}
.prose h2 {
font-size: 2.25rem !important;
font-weight: 700 !important;
color: #111827 !important;
margin-top: 3rem !important;
margin-bottom: 2rem !important;
line-height: 1.2 !important;
letter-spacing: -0.02em !important;
position: relative;
padding-bottom: 1rem !important;
}
.prose > h2:first-child {
margin-top: 0 !important;
}
.prose h2::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 3px;
background: linear-gradient(90deg, #374151 0%, #6b7280 100%);
border-radius: 2px;
}
@media (min-width: 768px) {
.prose h2 {
font-size: 3rem !important;
}
}
.prose h3 {
font-size: 1.5rem !important;
font-weight: 700 !important;
color: #111827 !important;
margin-top: 3rem !important;
margin-bottom: 1.5rem !important;
line-height: 1.3 !important;
letter-spacing: -0.01em !important;
}
@media (min-width: 768px) {
.prose h3 {
font-size: 1.875rem !important;
}
}
.prose h4 {
font-size: 1.25rem !important;
font-weight: 700 !important;
color: #111827 !important;
margin-top: 2rem !important;
margin-bottom: 1rem !important;
line-height: 1.4 !important;
}
@media (min-width: 768px) {
.prose h4 {
font-size: 1.5rem !important;
}
}
.prose p {
font-size: 1.125rem !important;
color: #374151 !important;
line-height: 1.6 !important;
font-weight: 400 !important;
}
@media (min-width: 768px) {
.prose p {
font-size: 1.1rem !important;
}
}
.prose > p:first-of-type {
margin-top: 1.6rem
}
@media (min-width: 768px) {
.prose > p:first-of-type {
margin-top: 1.2rem !important;
}
}
.prose a {
color: #374151 !important;
font-weight: 600 !important;
text-decoration: underline !important;
text-decoration-thickness: 2px !important;
text-underline-offset: 4px !important;
transition: all 0.2s ease !important;
}
.prose a:hover {
color: #111827 !important;
text-decoration-color: #111827 !important;
}
.prose strong {
font-weight: 700 !important;
color: #111827 !important;
}
.prose em {
font-style: italic !important;
color: #4b5563 !important;
}
.prose ul,
.prose ol {
margin-top: 2rem !important;
margin-bottom: 2rem !important;
margin-left: 2rem !important;
}
.prose ul {
list-style-type: disc !important;
}
.prose ol {
list-style-type: decimal !important;
}
.prose li {
font-size: 1.125rem !important;
color: #374151 !important;
padding-left: 0.5rem !important;
line-height: 1.1 !important;
margin-bottom: 0.75rem !important;
}
@media (min-width: 768px) {
.prose li {
font-size: 1.1rem !important;
}
}
.prose li::marker {
color: #6b7280 !important;
font-weight: 600 !important;
}
.prose blockquote {
border-left: 4px solid #6b7280 !important;
background-color: #f9fafb !important;
padding: 1.5rem 1.5rem 1.5rem 2rem !important;
margin: 2.5rem 0 !important;
font-style: italic !important;
color: #4b5563 !important;
border-radius: 0 0.75rem 0.75rem 0 !important;
font-size: 1.125rem !important;
line-height: 1.6 !important;
}
.prose code {
background-color: #f3f4f6 !important;
color: #374151 !important;
padding: 0.25rem 0.75rem !important;
border-radius: 0.375rem !important;
font-size: 1rem !important;
font-weight: 600 !important;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace !important;
}
.prose pre {
background-color: #111827 !important;
color: #f3f4f6 !important;
padding: 1.5rem !important;
border-radius: 0.75rem !important;
overflow-x: auto !important;
margin: 2rem 0 !important;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3) !important;
}
.prose pre code {
background-color: transparent !important;
color: #f3f4f6 !important;
padding: 0 !important;
}
.prose hr {
margin-top: 4rem !important;
margin-bottom: 4rem !important;
border-color: #e5e7eb !important;
border-width: 2px !important;
}
.prose img {
border-radius: 1rem !important;
margin-top: 2.5rem !important;
margin-bottom: 2.5rem !important;
margin-left: auto !important;
margin-right: auto !important;
max-width: 100% !important;
width: 100% !important;
height: auto !important;
transition: transform 0.3s ease !important;
box-shadow: 0 20px 60px -15px rgba(0, 0, 0, 0.3) !important;
}
.prose img:hover {
transform: scale(1.02) !important;
}
.prose::after {
content: "";
display: table;
clear: both;
}
.prose h2 + p,
.prose h3 + p,
.prose h4 + p {
margin-top: 0 !important;
}
.prose table {
width: 100% !important;
margin-top: 2rem !important;
margin-bottom: 2rem !important;
border-collapse: collapse !important;
}
.prose thead {
border-bottom: 2px solid #e5e7eb !important;
}
.prose th {
padding: 0.75rem 1rem !important;
text-align: left !important;
font-weight: 600 !important;
color: #111827 !important;
}
.prose td {
padding: 0.75rem 1rem !important;
border-bottom: 1px solid #e5e7eb !important;
color: #374151 !important;
}
.prose tbody tr:hover {
background-color: #f9fafb !important;
}
/* Image Utility Classes */
/* Float classes */
.prose img.float-left {
float: left !important;
margin-right: 2rem !important;
margin-bottom: 1.5rem !important;
margin-left: 0 !important;
shape-outside: margin-box;
shape-margin: 1rem;
}
.prose img.float-right {
float: right !important;
margin-left: 2rem !important;
margin-bottom: 1.5rem !important;
margin-right: 0 !important;
shape-outside: margin-box;
shape-margin: 1rem;
}
.prose img.float-none {
float: none !important;
margin-left: auto !important;
margin-right: auto !important;
}
/* Size classes */
.prose img.img-small {
width: 16rem !important;
max-width: 100% !important;
}
.prose img.img-medium {
width: 24rem !important;
max-width: 100% !important;
}
.prose img.img-large {
width: 32rem !important;
max-width: 100% !important;
}
.prose img.img-full {
width: 100% !important;
}
/* Hero image - full width with fixed height */
.prose img.img-hero {
width: 100% !important;
height: 24rem !important;
object-fit: cover !important;
margin-top: 3rem !important;
margin-bottom: 3rem !important;
}
@media (min-width: 640px) {
.prose img.img-hero {
height: 28rem !important;
}
}
@media (min-width: 768px) {
.prose img.img-hero {
height: 32rem !important;
}
}
/* Rounded variations */
.prose img.rounded-full {
border-radius: 9999px !important;
}
.prose img.rounded-lg {
border-radius: 0.5rem !important;
}
/* Mobile: remove float on small screens */
@media (max-width: 767px) {
.prose img.float-left,
.prose img.float-right {
float: none !important;
margin-left: auto !important;
margin-right: auto !important;
margin-bottom: 2rem !important;
width: 100% !important;
}
.prose img.img-small,
.prose img.img-medium,
.prose img.img-large {
width: 100% !important;
}
}
/* Caption styles */
.prose div.float-left em,
.prose div.float-right em,
.prose div.w-full em {
display: block !important;
margin-top: 0.5rem !important;
font-size: 0.875rem !important;
color: #6b7280 !important;
font-style: italic !important;
line-height: 1.4 !important;
max-width: 100% !important;
word-wrap: break-word !important;
}
@media (min-width: 768px) {
.prose div.float-right em {
margin-left: 2rem !important;
}
.prose div.float-left em {
margin-right: 2rem !important;
}
}
.prose div.float-left,
.prose div.float-right {
margin-bottom: 1.5rem !important;
max-width: fit-content !important;
}
.prose div.w-full {
margin-top: 2.5rem !important;
margin-bottom: 2.5rem !important;
width: 100% !important;
}
/* Remove default image margins when inside caption divs */
.prose div.float-left img,
.prose div.float-right img,
.prose div.w-full img {
margin-top: 0 !important;
margin-bottom: 0 !important;
display: block !important;
}