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 7be49ba73a
commit 7cf2e858a2
192 changed files with 7829 additions and 21756 deletions

106
src/components/Fish.astro Normal file
View file

@ -0,0 +1,106 @@
---
---
<div class="w-full block pointer-events-none relative" style="height: 100px;">
<svg class="fish" id="fish">
<path
id="fish2"
d="m 172.04828,20.913839 c 0.0489,-0.444179 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.475049 -1.4826,-0.932948 -2.2149,-1.401138 -1.6035,-1.028129 -3.29018,-1.969653 -4.89798,-3.079244 -4.67074,-3.24131 -10.22127,-4.404923 -15.76322,-5.1509392 -2.27235,-0.286401 -4.81223,-0.168925 -6.72186,-1.574351 -1.48174,-1.081294 -4.04993,-4.828523 -6.86506,-6.456038 -0.4862,-0.290688 -2.77227,-1.44486897 -2.77227,-1.44486897 0,0 1.30939,3.55000597 1.60951,4.26429497 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.0418502 2.13772,0.8129002 2.26463,1.7827212 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082841 -11.56925,0.884071 -4.3046,-1.38313 -7.37269,-4.129669 -10.46566,-7.2354952 1.43801,6.7252892 5.4382,10.6028562 5.6157,11.4226162 0.18607,0.905509 -0.45961,1.091584 -1.04099,1.682394 -1.28967,1.265655 -6.91566,7.731125 -6.93366,9.781383 1.61379,-0.247815 3.56115,-1.660957 4.9803,-2.485862 1.58035,-0.905509 7.60593,-5.373029 9.29347,-6.065023 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932949 0.0695,0.932949 -0.30784,1.137031 -0.18436,1.527189 0.22638,0.746016 1.44144,1.465449 2.02282,1.985088 1.50918,1.292237 3.21044,2.42841 4.27373,4.156252 1.49203,2.401827 1.55805,4.999163 1.98251,7.677102 0.99469,-0.111473 2.0091,-2.17545 2.55961,-2.992638 0.51278,-0.772598 2.38639,-4.07136 3.09725,-4.275442 0.67227,-0.204082 2.75511,0.958673 3.50284,1.180763 2.85973,0.848057 5.644,1.353976 8.56032,1.353976 3.50799,0.0094 12.726,0.258104 19.55505,-4.800226 0.75545,-0.567658 2.55703,-2.731104 2.55703,-2.731104 0,0 -0.37644,-0.577091 -1.04785,-0.790605 0.89779,-0.584808 1.8659,-1.211633 1.94993,-1.925922 z"
style="fill:#528484;fill-opacity:1"></path>
<path
id="fish3"
d="m 234.99441,42.953992 c 0.0489,-0.44418 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.47505 -1.4826,-0.932949 -2.2149,-1.401138 -1.6035,-1.02813 -3.29018,-1.969653 -4.89798,-3.079245 -4.67074,-3.24131 -10.22127,-4.404923 -15.76322,-5.150939 -2.27235,-0.286401 -4.81223,-0.168925 -6.72186,-1.574351 -1.48174,-1.081294 -4.04993,-4.828523 -6.86506,-6.456038 -0.4862,-0.290688 -2.77227,-1.444869 -2.77227,-1.444869 0,0 1.30939,3.550006 1.60951,4.264295 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.04185 2.13772,0.8129 2.26463,1.782721 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082842 -11.56925,0.884072 -4.3046,-1.383131 -7.37269,-4.12967 -10.46566,-7.235496 1.43801,6.725289 5.4382,10.602857 5.6157,11.422617 0.18607,0.905508 -0.45961,1.091583 -1.04099,1.682394 -1.28967,1.265654 -6.91566,7.731125 -6.93366,9.781382 1.61379,-0.247815 3.56115,-1.660957 4.9803,-2.485862 1.58035,-0.905509 7.60593,-5.373029 9.29347,-6.065023 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932948 0.0695,0.932948 -0.30784,1.137031 -0.18436,1.527188 0.22638,0.746016 1.44144,1.46545 2.02282,1.985088 1.50918,1.292237 3.21044,2.42841 4.27373,4.156252 1.49203,2.401827 1.55805,4.999163 1.98251,7.677102 0.99469,-0.111473 2.0091,-2.17545 2.55961,-2.992638 0.51278,-0.772598 2.38639,-4.071359 3.09725,-4.275442 0.67227,-0.204082 2.75511,0.958673 3.50284,1.180763 2.85973,0.848057 5.644,1.353976 8.56032,1.353976 3.50799,0.0094 12.726,0.258104 19.55505,-4.800226 0.75545,-0.567658 2.55703,-2.731104 2.55703,-2.731104 0,0 -0.37644,-0.57709 -1.04785,-0.790605 0.89779,-0.584808 1.8659,-1.211633 1.94993,-1.925921 z"
style="fill:#528484;fill-opacity:1"></path>
<path
id="fish6"
d="m 200.07076,80.737109 c 0.0489,-0.44418 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.47505 -1.4826,-0.932949 -2.2149,-1.401138 -1.6035,-1.02813 -3.29018,-1.969653 -4.89798,-3.079245 -4.67074,-3.24131 -10.22127,-4.404923 -15.76322,-5.150939 -2.27235,-0.286401 -4.81223,-0.168925 -6.72186,-1.574351 -1.48174,-1.081294 -4.04993,-4.828523 -6.86506,-6.456038 -0.4862,-0.290688 -2.77227,-1.444869 -2.77227,-1.444869 0,0 1.30939,3.550006 1.60951,4.264295 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.04185 2.13772,0.8129 2.26463,1.782721 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082842 -11.56925,0.884072 -4.3046,-1.383131 -7.37269,-4.12967 -10.46566,-7.235496 1.43801,6.725289 5.4382,10.602857 5.6157,11.422617 0.18607,0.905508 -0.45961,1.091583 -1.04099,1.682394 -1.28967,1.265654 -6.91566,7.731125 -6.93366,9.781382 1.61379,-0.247815 3.56115,-1.660957 4.9803,-2.485862 1.58035,-0.905509 7.60593,-5.373029 9.29347,-6.065023 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932948 0.0695,0.932948 -0.30784,1.137031 -0.18436,1.527188 0.22638,0.746016 1.44144,1.46545 2.02282,1.985088 1.50918,1.292237 3.21044,2.42841 4.27373,4.156252 1.49203,2.401827 1.55805,4.999163 1.98251,7.677102 0.99469,-0.111473 2.0091,-2.17545 2.55961,-2.992638 0.51278,-0.772598 2.38639,-4.071359 3.09725,-4.275442 0.67227,-0.204082 2.75511,0.958673 3.50284,1.180763 2.85973,0.848057 5.644,1.353976 8.56032,1.353976 3.50799,0.0094 12.726,0.258104 19.55505,-4.800226 0.75545,-0.567658 2.55703,-2.731104 2.55703,-2.731104 0,0 -0.37644,-0.57709 -1.04785,-0.790605 0.89779,-0.584808 1.8659,-1.211633 1.94993,-1.925921 z"
style="fill:#528484;fill-opacity:1"></path>
<path
id="fish4"
d="m 77.275623,89.018799 c 0.0489,-0.44418 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.47505 -1.4826,-0.932949 -2.2149,-1.401138 -1.6035,-1.02813 -3.29018,-1.969653 -4.89798,-3.079245 -4.67074,-3.24131 -10.22127,-4.404923 -15.76322,-5.150939 -2.272347,-0.286401 -4.812227,-0.168925 -6.721857,-1.574351 -1.48174,-1.081294 -4.04993,-4.828523 -6.86506,-6.456038 -0.4862,-0.290688 -2.77227,-1.444869 -2.77227,-1.444869 0,0 1.30939,3.550006 1.60951,4.264295 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.04185 2.13772,0.8129 2.26463,1.782721 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082842 -11.56925,0.884072 -4.3046,-1.383131 -7.37269,-4.12967 -10.46566,-7.235496 1.43801,6.725289 5.4382,10.602857 5.6157,11.422617 0.18607,0.905508 -0.45961,1.091583 -1.04099,1.682394 -1.28967,1.265654 -6.9156603,7.731122 -6.9336603,9.781382 1.6137903,-0.24782 3.5611503,-1.66096 4.9803003,-2.48586 1.58035,-0.90551 7.60593,-5.37303 9.29347,-6.065025 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932948 0.0695,0.932948 -0.30784,1.137031 -0.18436,1.527183 0.22638,0.74602 1.44144,1.46546 2.02282,1.98509 1.50918,1.29224 3.21044,2.42841 4.27373,4.15625 1.49203,2.40183 1.55805,4.999171 1.98251,7.677111 0.99469,-0.11148 2.0091,-2.17545 2.55961,-2.99264 0.51278,-0.7726 2.38639,-4.071361 3.09725,-4.275441 0.67227,-0.20408 2.75511,0.95867 3.50284,1.18076 2.85973,0.84806 5.644,1.35398 8.560317,1.35398 3.50799,0.009 12.726,0.2581 19.55505,-4.80023 0.75545,-0.56766 2.55703,-2.7311 2.55703,-2.7311 0,0 -0.37644,-0.57709 -1.04785,-0.79061 0.89779,-0.58481 1.8659,-1.211632 1.94993,-1.92592 z"
style="fill:#528484;fill-opacity:1"></path>
<path
id="fish5"
d="m 127.65312,60.900973 c 0.0489,-0.44418 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.47505 -1.4826,-0.932949 -2.2149,-1.401138 -1.6035,-1.02813 -3.29018,-1.969653 -4.89799,-3.079245 -4.67074,-3.24131 -10.22127,-4.404923 -15.76322,-5.150939 -2.27235,-0.286401 -4.812228,-0.168925 -6.721858,-1.574351 -1.48174,-1.081294 -4.04993,-4.828523 -6.86506,-6.456038 -0.4862,-0.290688 -2.77227,-1.444869 -2.77227,-1.444869 0,0 1.30939,3.550006 1.60951,4.264295 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.04185 2.13772,0.8129 2.26463,1.782721 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082842 -11.56925,0.884072 -4.3046,-1.383131 -7.37269,-4.12967 -10.46566,-7.235496 1.43801,6.725289 5.4382,10.602857 5.6157,11.422617 0.18607,0.905508 -0.45961,1.091583 -1.04099,1.682394 -1.28967,1.265654 -6.91566,7.731125 -6.93366,9.781382 1.61379,-0.247815 3.56115,-1.660957 4.9803,-2.485862 1.58035,-0.905509 7.60593,-5.373029 9.29347,-6.065023 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932948 0.0695,0.932948 -0.30784,1.137031 -0.18436,1.527188 0.22638,0.746016 1.44144,1.46545 2.02282,1.985088 1.50918,1.292237 3.21044,2.42841 4.27373,4.156252 1.49203,2.401827 1.55805,4.999163 1.98251,7.677102 0.99469,-0.111473 2.0091,-2.17545 2.55961,-2.992638 0.51278,-0.772598 2.38639,-4.071359 3.09725,-4.275442 0.67227,-0.204082 2.75511,0.958673 3.50284,1.180763 2.85973,0.848057 5.643998,1.353976 8.560318,1.353976 3.50799,0.0094 12.726,0.258104 19.55506,-4.800226 0.75545,-0.567658 2.55703,-2.731104 2.55703,-2.731104 0,0 -0.37644,-0.57709 -1.04785,-0.790605 0.89779,-0.584808 1.8659,-1.211633 1.94993,-1.925921 z"
style="fill:#528484;fill-opacity:1"></path>
<path
id="fish1"
d="m 68.19699,20.522295 c 0.0489,-0.44418 -0.2178,-0.896934 -1.01784,-1.415715 -0.72801,-0.47505 -1.4826,-0.932949 -2.2149,-1.401138 -1.6035,-1.02813 -3.29018,-1.969653 -4.89798,-3.079245 C 55.39553,11.384887 49.845,10.221274 44.30305,9.4752582 42.0307,9.1888572 39.49082,9.3063332 37.58119,7.900907 36.09945,6.819613 33.53126,3.072384 30.71613,1.444869 30.22993,1.154181 27.94386,0 27.94386,0 c 0,0 1.30939,3.550006 1.60951,4.264295 0.69542,1.644664 -0.38158,3.063809 -0.83262,4.642447 -0.29069,1.0418502 2.13772,0.8129002 2.26463,1.782721 0.18179,1.432007 -4.15197,1.936211 -6.59152,2.417263 -3.65634,0.715146 -7.91635,2.082842 -11.56925,0.884072 C 8.52001,12.607667 5.45192,9.8611282 2.35895,6.755302 3.79696,13.480591 7.79715,17.358159 7.97465,18.177919 8.16072,19.083427 7.51504,19.269502 6.93366,19.860313 5.64399,21.125967 0.018,27.591438 0,29.641695 1.61379,29.39388 3.56115,27.980738 4.9803,27.155833 c 1.58035,-0.905509 7.60593,-5.373029 9.29347,-6.065023 0.38587,-0.160351 5.0549,-1.531476 5.09434,-0.932948 0.0695,0.932948 -0.30784,1.137031 -0.18436,1.527188 0.22638,0.746016 1.44144,1.46545 2.02282,1.985088 1.50918,1.292237 3.21044,2.42841 4.27373,4.156252 1.49203,2.401827 1.55805,4.999163 1.98251,7.677102 0.99469,-0.111473 2.0091,-2.17545 2.55961,-2.992638 0.51278,-0.772598 2.38639,-4.071359 3.09725,-4.275442 0.67227,-0.204082 2.75511,0.958673 3.50284,1.180763 2.85973,0.848057 5.644,1.353976 8.56032,1.353976 3.50799,0.0094 12.726,0.258104 19.55505,-4.800226 0.75545,-0.567658 2.55703,-2.731104 2.55703,-2.731104 0,0 -0.37644,-0.57709 -1.04785,-0.790605 0.89779,-0.584808 1.8659,-1.211633 1.94993,-1.925921 z"
style="fill:#528484;fill-opacity:1"></path>
</svg>
</div>
<style>
svg#fish {
overflow: visible;
}
@keyframes swim {
0% {
left: -235px;
}
70% {
left: calc(100% - 235px);
width: 235px;
}
100% {
left: calc(100%);
width: 0;
}
}
.fish {
width: 235px;
height: 104px;
left: -235px;
position: absolute;
opacity: 0.3;
animation: swim 20s infinite linear;
filter: drop-shadow(0 2px 8px rgba(46, 189, 233, 0.15));
}
svg #fish1,
svg #fish2,
svg #fish3,
svg #fish4,
svg #fish5,
svg #fish6 {
fill: #2ebde9;
animation: bounce 2s infinite;
}
svg #fish2 {
animation-delay: 0.5s;
}
svg #fish3 {
animation-delay: 0.2s;
}
svg #fish4 {
animation-delay: 0.4s;
}
svg #fish5 {
animation-delay: 0.1s;
}
svg #fish6 {
animation-delay: 0.3s;
}
@keyframes bounce {
0%,
50%,
100% {
transform: translateY(0);
}
25% {
transform: translateY(-5px);
}
75% {
transform: translateY(-3px);
}
}
</style>

124
src/components/Footer.astro Normal file
View file

@ -0,0 +1,124 @@
---
---
<div class="w-full bg-secondary py-2 px-4">
<div class="max-w-6xl mx-auto flex justify-between flex-col-reverse sm:flex-row gap-4 sm:items-end items-center">
<div class="text-center sm:text-left text-gray-600 flex flex-col items-center sm:items-start">
<div class="flex flex-wrap items-center gap-3 text-sm">
<span class="font-medium text-gray-800">Lorenzo Iovino</span>
<span class="text-gray-400">•</span>
<a
href="/rss.xml"
class="hover:text-primary-600 transition-colors duration-200 inline-flex items-center gap-1"
title="RSS Feed"
>
RSS
</a>
<span class="text-gray-400">•</span>
<a
href="/sitemap-index.xml"
class="hover:text-primary-600 transition-colors duration-200"
title="Sitemap">Sitemap</a
>
<span class="text-gray-400">•</span>
<a
href="https://www.iubenda.com/privacy-policy/98687046"
class="hover:text-primary-600 transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe"
title="Privacy Policy">Privacy Policy</a
>
<script is:inline type="text/javascript">
(function (w, d) {
var loader = function () {
var s = d.createElement("script"),
tag = d.getElementsByTagName("script")[0];
s.src = "https://cdn.iubenda.com/iubenda.js";
tag.parentNode.insertBefore(s, tag);
};
if (w.addEventListener) {
w.addEventListener("load", loader, false);
} else if (w.attachEvent) {
w.attachEvent("onload", loader);
} else {
w.onload = loader;
}
})(window, document);
</script>
<span class="text-gray-400">•</span>
<a
href="https://www.iubenda.com/privacy-policy/98687046/cookie-policy"
class="hover:text-primary-600 transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe"
title="Cookie Policy">Cookie Policy</a
>
<script is:inline type="text/javascript">
(function (w, d) {
var loader = function () {
var s = d.createElement("script"),
tag = d.getElementsByTagName("script")[0];
s.src = "https://cdn.iubenda.com/iubenda.js";
tag.parentNode.insertBefore(s, tag);
};
if (w.addEventListener) {
w.addEventListener("load", loader, false);
} else if (w.attachEvent) {
w.attachEvent("onload", loader);
} else {
w.onload = loader;
}
})(window, document);
</script>
</div>
</div>
<div class="text-center sm:text-right text-gray-600 text-sm">
<div class="flex flex-col gap-1">
<div class="flex items-center justify-center sm:justify-end gap-1 flex-wrap">
<span>Made with</span>
<a
href="https://astro.build/"
class="inline-flex items-center hover:text-white transition-all duration-200"
title="Astro"
>
<img
class="h-5 w-5"
src="/astro.svg"
height="20"
width="20"
loading="lazy"
alt="Astro Logo"
/>
</a>
<span>and</span>
<a
href="https://tailwindcss.com/"
class="inline-flex items-center center hover:text-white transition-all duration-200"
title="TailwindCSS"
>
<img
class="h-5 w-5"
src="/tailwind.svg"
height="20"
width="20"
loading="lazy"
alt="Tailwind Logo"
/>
</a>
</div>
<a
href="https://github.com/thisloke/lorenzoiovino.com"
class="hover:text-white transition-colors duration-200 inline-flex items-center justify-center sm:justify-end gap-2 font-medium"
>
<span>Check the source code</span>
<img
src="/github.svg"
class="h-5 w-5"
height="20"
width="20"
loading="lazy"
alt="Github Logo"
/>
</a>
</div>
</div>
</div>
</div>

90
src/components/Hero.astro Normal file
View file

@ -0,0 +1,90 @@
---
---
<div class="w-full">
<div class="relative px-6 lg:px-8">
<div class="mx-auto max-w-5xl">
<div
class="relative overflow-hidden rounded-3xl bg-white shadow-soft-lg hover:shadow-soft-lg transition-shadow duration-300"
>
<div class="relative flex flex-col md:flex-row items-center md:items-end">
<!-- Photo Section -->
<div class="w-full md:w-auto flex-shrink-0 order-2 md:order-none">
<div class="relative overflow-hidden md:rounded-l-3xl flex justify-center md:block">
<img
src="/photos/me.png"
alt="Photo of Lorenzo Iovino"
class="w-48 h-auto md:w-full object-cover object-center"
width="300"
height="300"
/>
<div class="absolute inset-0 to-transparent md:bg-gradient-to-r"></div>
<div class="absolute inset-0 to-transparent md:bg-gradient-to-r"></div>
</div>
</div>
<!-- Content Section -->
<div class="flex-1 p-6 md:p-12 flex flex-col justify-center order-1 md:order-none">
<div class="space-y-4 md:space-y-6">
<!-- Greeting -->
<div class="text-center md:text-left">
<h1 class="mb-3">
Hey, I'm <span class="text-gray-900 font-extrabold">Lorenzo</span>!
</h1>
<div class="h-1 w-20 bg-secondary rounded-full mx-auto md:mx-0"></div>
</div>
<!-- Description -->
<div class="space-y-3 md:space-y-4">
<p class="text-base md:text-lg text-gray-700">
I'm on a quest to uncover life's meaning while diving deep into my passion for
Computer Science as a
<span class="font-semibold text-gray-900 relative inline-block">
Software Engineer
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-secondary"></span>
</span>
</p>
<p class="text-sm md:text-lg text-gray-600">
Here, on my personal website, I share my projects and occasional thoughts.
</p>
</div>
<!-- Social Links -->
<div class="flex gap-3 md:gap-4 pt-2 justify-center md:justify-end">
<a
href="https://www.linkedin.com/in/lorenzoiovino/"
class="group relative p-3 bg-gray-50 hover:bg-secondary/10 rounded-xl transition-all duration-200 transform hover:-translate-y-1"
aria-label="LinkedIn"
>
<img
src="/linkedin.svg"
alt="LinkedIn"
class="h-6 w-6 opacity-70 group-hover:opacity-100 transition-opacity"
width="24"
height="24"
loading="lazy"
/>
</a>
<a
href="https://github.com/thisloke"
class="group relative p-3 bg-gray-50 hover:bg-secondary/10 rounded-xl transition-all duration-200 transform hover:-translate-y-1"
aria-label="GitHub"
>
<img
src="/github.svg"
alt="GitHub"
class="h-6 w-6 opacity-70 group-hover:opacity-100 transition-opacity"
width="24"
height="24"
loading="lazy"
/>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

111
src/components/Navbar.astro Normal file
View file

@ -0,0 +1,111 @@
---
const currentPath = Astro.url.pathname;
---
<nav class="fixed top-0 left-0 right-0 z-50 bg-secondary shadow-sm">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<!-- Logo/Brand -->
<a
href="/"
class="text-xl font-bold text-white hover:text-gray-100 transition-colors duration-200"
>
Lorenzo Iovino
</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8">
<a
href="/"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/" ? "text-white font-semibold" : "text-white/80 hover:text-white"
}`}
>
Home
</a>
<a
href="/bio"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/bio" ? "text-white font-semibold" : "text-white/80 hover:text-white"
}`}
>
Bio
</a>
<a
href="/blog"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/blog" ? "text-white font-semibold" : "text-white/80 hover:text-white"
}`}
>
Blog
</a>
</div>
<!-- Mobile menu button -->
<button
id="mobile-menu-button"
class="md:hidden p-2 rounded-lg text-white hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/50"
aria-label="Toggle menu"
>
<svg
class="h-6 w-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
</div>
<!-- Mobile Navigation -->
<div id="mobile-menu" class="hidden md:hidden bg-secondary">
<div class="px-4 py-3 space-y-3">
<a
href="/"
class={`block px-3 py-2 rounded-lg text-base font-medium transition-colors duration-200 ${
currentPath === "/"
? "bg-white/20 text-white font-semibold"
: "text-white/80 hover:bg-white/10 hover:text-white"
}`}
>
Home
</a>
<a
href="/bio"
class={`block px-3 py-2 rounded-lg text-base font-medium transition-colors duration-200 ${
currentPath === "/bio"
? "bg-white/20 text-white font-semibold"
: "text-white/80 hover:bg-white/10 hover:text-white"
}`}
>
Bio
</a>
<a
href="/blog"
class={`block px-3 py-2 rounded-lg text-base font-medium transition-colors duration-200 ${
currentPath === "/blog"
? "bg-white/20 text-white font-semibold"
: "text-white/80 hover:bg-white/10 hover:text-white"
}`}
>
Blog
</a>
</div>
</div>
</nav>
<script>
const mobileMenuButton = document.getElementById("mobile-menu-button");
const mobileMenu = document.getElementById("mobile-menu");
mobileMenuButton?.addEventListener("click", () => {
mobileMenu?.classList.toggle("hidden");
});
</script>

View file

@ -0,0 +1,41 @@
---
interface Props {
title?: string;
titleColor?: "light" | "dark";
backgroundImageUrl?: string;
backgroundColor?: "light" | "dark";
noHeight?: boolean;
}
const {
title = "",
titleColor = "light",
backgroundImageUrl = "",
backgroundColor = "light",
noHeight = false,
} = Astro.props;
const bgClass = backgroundColor === "light" ? "bg-white" : "bg-secondary";
const titleColorClass = titleColor === "light" ? "text-white" : "text-secondary";
const heightClass = noHeight ? "h-[0px]" : "h-[150px]";
---
<div
class={`bg-center bg-no-repeat ${heightClass} ${bgClass}`}
style={backgroundImageUrl ? `background-image: url(${backgroundImageUrl})` : ""}
>
{
title && (
<h2
class={`mx-24 pt-8 text-6xl drop-shadow-2xl shadow-black text-gray-600 mr-6 font-extrabold ${titleColorClass}`}
>
{title}
</h2>
)
}
</div>
<section
class="max-w-4xl min-h-full py-4 px-6 mx-auto text-gray-700 flex flex-col items-center justify-center"
>
<slot />
</section>