feat: implement dark mode with theme toggle

- Add dark mode support across all components and pages
- Implement theme toggle button in navbar (desktop and mobile)
- Fix desktop theme toggle icon visibility issue
- Add dark mode color variants to all text, backgrounds and components
- Update Tailwind config to enable class-based dark mode
- Add dark mode support to prose styles for blog content
- Persist theme preference in localStorage
- Update all pages (index, bio, blog) with dark mode colors
- Optimize images (me.png and me-baby.jpg)
This commit is contained in:
Lorenzo Iovino 2026-01-09 16:20:24 +01:00
parent 7caf02fb36
commit df04844ca2
16 changed files with 392 additions and 203 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

View file

@ -5,29 +5,31 @@ import tailwindIcon from "../assets/tailwind.svg";
import githubIcon from "../assets/github.svg";
---
<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-800 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-800">•</span>
<div class="w-full bg-secondary dark:bg-gray-800 py-8 px-4 transition-colors duration-200">
<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-800 dark:text-gray-200 flex flex-col items-center sm:items-start"
>
<div class="flex flex-wrap items-center gap-1 md:gap-3 text-xs">
<a
href="/rss.xml"
class="transition-colors duration-200 inline-flex items-center gap-1"
class="transition-colors duration-200 inline-flex items-center gap-1 hover:text-gray-600 dark:hover:text-gray-300"
title="RSS Feed"
>
RSS
</a>
<span class="text-gray-800">•</span>
<span class="text-gray-800 dark:text-gray-400">•</span>
<a
href="/sitemap-index.xml"
class="transition-colors duration-200"
class="transition-colors duration-200 hover:text-gray-600 dark:hover:text-gray-300"
title="Sitemap">Sitemap</a
>
<span class="text-gray-800">•</span>
<span class="text-gray-800 dark:text-gray-400">•</span>
<a
href="https://www.iubenda.com/privacy-policy/98687046"
class="transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe"
class="transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe hover:text-gray-600 dark:hover:text-gray-300"
title="Privacy Policy">Privacy Policy</a
>
<script is:inline type="text/javascript">
@ -47,11 +49,11 @@ import githubIcon from "../assets/github.svg";
}
})(window, document);
</script>
<span class="text-gray-800">•</span>
<span class="text-gray-800 dark:text-gray-400">•</span>
<a
href="https://www.iubenda.com/privacy-policy/98687046/cookie-policy"
class="transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe"
class="transition-colors duration-200 iubenda-white iubenda-noiframe iubenda-embed iubenda-noiframe hover:text-gray-600 dark:hover:text-gray-300"
title="Cookie Policy">Cookie Policy</a
>
<script is:inline type="text/javascript">
@ -73,53 +75,14 @@ import githubIcon from "../assets/github.svg";
</script>
</div>
</div>
<div class="text-center sm:text-right text-gray-800 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 transition-all duration-200"
aria-label="Astro"
>
<Image
class="h-5 w-5"
src={astroIcon}
width={20}
height={20}
loading="lazy"
alt=""
/>
</a>
<span>and</span>
<a
href="https://tailwindcss.com/"
class="inline-flex items-center center transition-all duration-200"
aria-label="TailwindCSS"
>
<Image
class="h-5 w-5"
src={tailwindIcon}
width={20}
height={20}
loading="lazy"
alt=""
/>
</a>
</div>
<div class="text-center sm:text-right text-gray-800 dark:text-gray-200 text-xs">
<div class="flex flex-col">
<a
href="https://github.com/thisloke/lorenzoiovino.com"
class="transition-colors duration-200 inline-flex items-center justify-center sm:justify-end gap-2 font-medium"
class="transition-colors duration-200 inline-flex items-center justify-center sm:justify-end gap-2 font-medium hover:text-gray-600 dark:hover:text-gray-300"
>
<span>Check the source code</span>
<Image
src={githubIcon}
class="h-5 w-5"
width={20}
height={20}
loading="lazy"
alt=""
/>
<Image src={githubIcon} class="h-5 w-5" width={20} height={20} loading="lazy" alt="" />
</a>
</div>
</div>

View file

@ -9,7 +9,7 @@ import githubIcon from "../assets/github.svg";
<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"
class="relative overflow-hidden rounded-3xl bg-white dark:bg-gray-800 shadow-soft-lg hover:shadow-soft-lg transition-all duration-300"
>
<div class="relative flex flex-col md:flex-row items-center md:items-end">
<!-- Photo Section -->
@ -36,23 +36,29 @@ import githubIcon from "../assets/github.svg";
<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 class="mb-3 text-gray-900 dark:text-gray-100">
Hey, I'm <span class="text-gray-900 dark:text-gray-100 font-extrabold"
>Lorenzo</span
>!
</h1>
<div class="h-1 w-20 bg-secondary rounded-full mx-auto md:mx-0"></div>
<div class="h-1 w-20 bg-secondary dark:bg-primary 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">
<p class="text-base md:text-lg text-gray-700 dark:text-gray-300">
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">
<span
class="font-semibold text-gray-900 dark:text-gray-100 relative inline-block"
>
Software Engineer
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-secondary"></span>
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-secondary dark:bg-primary"
></span>
</span>
</p>
<p class="text-sm md:text-lg text-gray-600">
<p class="text-sm md:text-lg text-gray-600 dark:text-gray-400">
Here, on my personal website, I share my projects and occasional thoughts.
</p>
</div>
@ -61,7 +67,7 @@ import githubIcon from "../assets/github.svg";
<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"
class="group relative p-3 bg-gray-50 dark:bg-gray-700 hover:bg-secondary/10 dark:hover:bg-primary/10 rounded-xl transition-all duration-200 transform hover:-translate-y-1"
aria-label="LinkedIn"
>
<Image
@ -75,7 +81,7 @@ import githubIcon from "../assets/github.svg";
</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"
class="group relative p-3 bg-gray-50 dark:bg-gray-700 hover:bg-secondary/10 dark:hover:bg-primary/10 rounded-xl transition-all duration-200 transform hover:-translate-y-1"
aria-label="GitHub"
>
<Image

View file

@ -2,23 +2,55 @@
const currentPath = Astro.url.pathname;
---
<nav class="fixed top-0 left-0 right-0 z-50 bg-secondary shadow-sm">
<nav
class="fixed top-0 left-0 right-0 z-50 bg-secondary dark:bg-gray-800 shadow-sm transition-colors duration-200"
>
<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-gray-800 hover:text-gray-200 transition-colors duration-200"
class="text-xl font-bold text-gray-800 dark:text-gray-100 hover:text-gray-600 dark:hover:text-gray-300 transition-colors duration-200"
>
Lorenzo Iovino
</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8">
<!-- Dark Mode Toggle -->
<button
id="theme-toggle"
class="p-2 rounded-lg text-gray-800 dark:text-gray-200 hover:bg-white/20 dark:hover:bg-white/10 transition-colors duration-200"
aria-label="Toggle dark mode"
>
<svg
id="theme-toggle-dark-icon"
class="theme-toggle-dark-icon w-5 h-5 hidden"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
</svg>
<svg
id="theme-toggle-light-icon"
class="theme-toggle-light-icon w-5 h-5 hidden"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
fill-rule="evenodd"
clip-rule="evenodd"></path>
</svg>
</button>
<a
href="/"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/" ? "text-gray-800 font-semibold" : "text-gray-800/80 hover:text-gray-800"
currentPath === "/"
? "text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Home
@ -26,7 +58,9 @@ const currentPath = Astro.url.pathname;
<a
href="/bio"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/bio" ? "text-gray-800 font-semibold" : "text-gray-800/80 hover:text-gray-800"
currentPath === "/bio"
? "text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Bio
@ -34,17 +68,48 @@ const currentPath = Astro.url.pathname;
<a
href="/blog"
class={`text-sm font-medium transition-colors duration-200 ${
currentPath === "/blog" ? "text-gray-800 font-semibold" : "text-gray-800/80 hover:text-gray-800"
currentPath === "/blog"
? "text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Blog
</a>
</div>
<!-- Mobile controls (theme toggle + menu button) -->
<div class="md:hidden flex items-center space-x-2">
<!-- Dark Mode Toggle (Mobile) -->
<button
id="theme-toggle-mobile"
class="p-2 rounded-lg text-gray-800 dark:text-gray-200 hover:bg-white/20 dark:hover:bg-white/10 transition-colors duration-200"
aria-label="Toggle dark mode"
>
<svg
class="theme-toggle-dark-icon w-5 h-5 hidden"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
</svg>
<svg
class="theme-toggle-light-icon w-5 h-5 hidden"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
fill-rule="evenodd"
clip-rule="evenodd"></path>
</svg>
</button>
<!-- Mobile menu button -->
<button
id="mobile-menu-button"
class="md:hidden p-2 rounded-lg text-gray-800 hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/50"
class="p-2 rounded-lg text-gray-800 dark:text-gray-200 hover:bg-white/10 dark:hover:bg-white/5 focus:outline-none focus:ring-2 focus:ring-white/50"
aria-label="Toggle menu"
>
<svg
@ -63,16 +128,20 @@ const currentPath = Astro.url.pathname;
</button>
</div>
</div>
</div>
<!-- Mobile Navigation -->
<div id="mobile-menu" class="hidden md:hidden bg-secondary">
<div
id="mobile-menu"
class="hidden md:hidden bg-secondary dark:bg-gray-800 transition-colors duration-200"
>
<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-gray-800 font-semibold"
: "text-gray-800/80 hover:bg-white/10 hover:text-gray-800"
? "bg-white/20 dark:bg-white/10 text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Home
@ -81,8 +150,8 @@ const currentPath = Astro.url.pathname;
href="/bio"
class={`block px-3 py-2 rounded-lg text-base font-medium transition-colors duration-200 ${
currentPath === "/bio"
? "bg-white/20 text-gray-800 font-semibold"
: "text-gray-800/80 hover:bg-white/10 hover:text-gray-800"
? "bg-white/20 dark:bg-white/10 text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Bio
@ -91,8 +160,8 @@ const currentPath = Astro.url.pathname;
href="/blog"
class={`block px-3 py-2 rounded-lg text-base font-medium transition-colors duration-200 ${
currentPath === "/blog"
? "bg-white/20 text-gray-800 font-semibold"
: "text-gray-800/80 hover:bg-white/10 hover:text-gray-800"
? "bg-white/20 dark:bg-white/10 text-gray-800 dark:text-gray-100 font-semibold"
: "text-gray-800/80 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5 hover:text-gray-800 dark:hover:text-gray-100"
}`}
>
Blog
@ -102,10 +171,51 @@ const currentPath = Astro.url.pathname;
</nav>
<script>
// Mobile menu toggle
const mobileMenuButton = document.getElementById("mobile-menu-button");
const mobileMenu = document.getElementById("mobile-menu");
mobileMenuButton?.addEventListener("click", () => {
mobileMenu?.classList.toggle("hidden");
});
// Theme toggle functionality
const themeToggleBtns = [
document.getElementById("theme-toggle"),
document.getElementById("theme-toggle-mobile"),
];
const themeToggleDarkIcons = document.querySelectorAll(".theme-toggle-dark-icon");
const themeToggleLightIcons = document.querySelectorAll(".theme-toggle-light-icon");
// Check for saved theme preference or default to 'light' mode
const currentTheme = localStorage.getItem("theme") || "light";
// Set initial theme and icons
if (currentTheme === "dark") {
document.documentElement.classList.add("dark");
themeToggleLightIcons.forEach((icon) => icon.classList.remove("hidden"));
themeToggleDarkIcons.forEach((icon) => icon.classList.add("hidden"));
} else {
document.documentElement.classList.remove("dark");
themeToggleDarkIcons.forEach((icon) => icon.classList.remove("hidden"));
themeToggleLightIcons.forEach((icon) => icon.classList.add("hidden"));
}
// Toggle theme on button clicks
themeToggleBtns.forEach((btn) => {
btn?.addEventListener("click", () => {
document.documentElement.classList.toggle("dark");
// Swap icons
themeToggleDarkIcons.forEach((icon) => icon.classList.toggle("hidden"));
themeToggleLightIcons.forEach((icon) => icon.classList.toggle("hidden"));
// Save theme preference
if (document.documentElement.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
} else {
localStorage.setItem("theme", "light");
}
});
});
</script>

View file

@ -15,19 +15,21 @@ const {
noHeight = false,
} = Astro.props;
const bgClass = backgroundColor === "light" ? "bg-white" : "bg-secondary";
const titleColorClass = titleColor === "light" ? "text-white" : "text-secondary-700";
const bgClass =
backgroundColor === "light" ? "bg-white dark:bg-gray-800" : "bg-secondary dark:bg-gray-900";
const titleColorClass =
titleColor === "light" ? "text-white dark:text-gray-100" : "text-gray-600 dark:text-gray-300";
const heightClass = noHeight ? "h-[0px]" : "h-[150px]";
---
<div
class={`bg-center bg-no-repeat ${heightClass} ${bgClass}`}
class={`bg-center bg-no-repeat ${heightClass} ${bgClass} transition-colors duration-200`}
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}`}
class={`mx-24 pt-8 text-6xl drop-shadow-2xl shadow-black mr-6 font-extrabold ${titleColorClass}`}
>
{title}
</h2>
@ -35,7 +37,7 @@ const heightClass = noHeight ? "h-[0px]" : "h-[150px]";
}
</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"
class="max-w-4xl min-h-full py-4 px-6 mx-auto text-gray-700 dark:text-gray-300 flex flex-col items-center justify-center transition-colors duration-200"
>
<slot />
</section>

View file

@ -1,7 +1,7 @@
---
title: "Welcome to My Blog!"
description: "First commit"
pubDate: 2024-01-15
pubDate: 2026-01-08
heroImage: "../../assets/photos/remote.jpg"
tags: ["personal", "welcome"]
---
@ -9,7 +9,7 @@ tags: ["personal", "welcome"]
Hi, Im Lorenzo.
Ive been thinking about writing for a long time, and I finally decided to publish this blog.
Not to be “a creator” or something like that just to keep track of what I learn and share it with whoever finds it useful.
Not to be “a creator” or something like that, just to keep track of what I learn and share it with whoever finds it useful.
## What you will find here

View file

@ -27,7 +27,9 @@ const {
const siteUrl = "https://lorenzoiovino.com";
const defaultImage = mePhoto.src;
const fullImageUrl = image
? (image.startsWith("http") ? image : `${siteUrl}${image}`)
? image.startsWith("http")
? image
: `${siteUrl}${image}`
: `${siteUrl}${defaultImage}`;
const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;
---
@ -171,12 +173,16 @@ const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;
<style>
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-style: normal;
font-weight: 400 800;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
src: url(https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2)
format("woff2");
unicode-range:
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
U+FFFD;
}
</style>
@ -184,7 +190,7 @@ const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;
<link rel="manifest" href="/manifest.json" />
<title>{title}</title>
</head>
<body class="bg-secondary min-h-screen">
<body class="bg-white dark:bg-gray-900 min-h-screen transition-colors duration-200">
<slot />
</body>
</html>

View file

@ -20,33 +20,34 @@ if (!bioEntry) {
const { Content } = await bioEntry.render();
---
<BaseLayout
title="Lorenzo Iovino >> Bio"
description="Biography and life story of Lorenzo Iovino"
>
<BaseLayout title="Lorenzo Iovino >> Bio" description="Biography and life story of Lorenzo Iovino">
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
<div class="min-h-screen pt-16 bg-secondary dark:bg-gray-900 transition-colors duration-200">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-20">
<div class="mb-16 text-center">
<h1 class="text-gray-800 mb-4">{bioEntry.data.title}</h1>
<p class="text-xl text-gray-700 max-w-2xl mx-auto">
<h1 class="text-gray-800 dark:text-gray-100 mb-4">{bioEntry.data.title}</h1>
<p class="text-xl text-gray-700 dark:text-gray-300 max-w-2xl mx-auto">
{bioEntry.data.description}
</p>
<div class="h-1 w-20 bg-gray-600 rounded-full mx-auto mt-6"></div>
<div class="h-1 w-20 bg-gray-600 dark:bg-primary rounded-full mx-auto mt-6"></div>
</div>
<div class="bg-white rounded-2xl shadow-soft-lg p-8 md:p-12 lg:p-16">
<div
class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg p-8 md:p-12 lg:p-16 transition-colors duration-200"
>
<div class="prose prose-xl max-w-none">
<Content />
</div>
</div>
<div
class="mt-16 bg-gradient-to-br from-white to-gray-50 rounded-2xl shadow-soft-lg p-10 md:p-14 lg:p-16 text-center border border-gray-100"
class="mt-16 bg-gradient-to-br from-white to-gray-50 dark:from-gray-800 dark:to-gray-700 rounded-2xl shadow-soft-lg p-10 md:p-14 lg:p-16 text-center border border-gray-100 dark:border-gray-600 transition-colors duration-200"
>
<h3 class="text-3xl md:text-4xl font-bold text-gray-900 mb-6">Let's Connect!</h3>
<h3 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-6">
Let's Connect!
</h3>
<p
class="text-gray-700 text-xl md:text-2xl leading-relaxed mb-10 max-w-3xl mx-auto font-light"
class="text-gray-700 dark:text-gray-300 text-xl md:text-2xl leading-relaxed mb-10 max-w-3xl mx-auto font-light"
>
I'm always excited to connect with fellow developers, discuss interesting projects, or
just have a chat about technology and life. Feel free to reach out!
@ -56,7 +57,7 @@ const { Content } = await bioEntry.render();
href="https://www.linkedin.com/in/lorenzoiovino/"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-10 py-5 bg-white hover:bg-gray-50 text-gray-700 font-semibold text-lg rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl border-2 border-gray-200 hover:border-gray-300 transform hover:-translate-y-1 hover:scale-105"
class="inline-flex items-center px-10 py-5 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-200 font-semibold text-lg rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl border-2 border-gray-200 dark:border-gray-600 hover:border-gray-300 dark:hover:border-gray-500 transform hover:-translate-y-1 hover:scale-105"
>
<Image
src={linkedinIcon}
@ -71,15 +72,9 @@ const { Content } = await bioEntry.render();
href="https://github.com/thisloke"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-10 py-5 bg-white hover:bg-gray-50 text-gray-700 font-semibold text-lg rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl border-2 border-gray-200 hover:border-gray-300 transform hover:-translate-y-1 hover:scale-105"
class="inline-flex items-center px-10 py-5 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-200 font-semibold text-lg rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl border-2 border-gray-200 dark:border-gray-600 hover:border-gray-300 dark:hover:border-gray-500 transform hover:-translate-y-1 hover:scale-105"
>
<Image
src={githubIcon}
alt=""
class="h-6 w-6 mr-3 opacity-80"
width={24}
height={24}
/>
<Image src={githubIcon} alt="" class="h-6 w-6 mr-3 opacity-80" width={24} height={24} />
GitHub
</a>
</div>

View file

@ -21,7 +21,7 @@ const allTags: Record<string, number> = sortedPosts.reduce(
});
return acc;
},
{} as Record<string, number>,
{} as Record<string, number>
);
const sortedTags: TagCount[] = Object.entries(allTags)
@ -31,31 +31,30 @@ const sortedTags: TagCount[] = Object.entries(allTags)
const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
---
<BaseLayout
title="Lorenzo Iovino >> Blog"
description="Blog posts and articles by Lorenzo Iovino"
>
<BaseLayout title="Lorenzo Iovino >> Blog" description="Blog posts and articles by Lorenzo Iovino">
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
<div class="min-h-screen pt-16 bg-secondary dark:bg-gray-900 transition-colors duration-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-20">
<div class="mb-16 text-center">
<h1 class="text-gray-800 mb-4">Blog</h1>
<p class="text-xl text-gray-800/90 max-w-2xl mx-auto">
<h1 class="text-gray-800 dark:text-gray-100 mb-4">Blog</h1>
<p class="text-xl text-gray-800/90 dark:text-gray-300 max-w-2xl mx-auto">
Thoughts, experiences, and insights about software engineering, technology, and life
</p>
<div class="h-1 w-20 bg-gray-800 rounded-full mx-auto mt-6"></div>
<div class="h-1 w-20 bg-gray-800 dark:bg-primary rounded-full mx-auto mt-6"></div>
</div>
<div class="mb-12">
<div class="bg-white rounded-2xl shadow-soft-lg overflow-hidden">
<div
class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden transition-colors duration-200"
>
<button
id="toggle-tags"
class="w-full p-6 flex items-center justify-between hover:bg-gray-50 transition-colors duration-200"
class="w-full p-6 flex items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-200"
>
<div class="flex items-center gap-3">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-secondary-700"
class="h-6 w-6 text-secondary-700 dark:text-primary"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -67,12 +66,12 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
></path>
</svg>
<h2 class="text-xl font-bold text-gray-900">Filter by Topic</h2>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Filter by Topic</h2>
</div>
<svg
id="chevron-icon"
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-gray-400 transition-transform duration-200"
class="h-6 w-6 text-gray-400 dark:text-gray-500 transition-transform duration-200"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -88,7 +87,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
<div class="flex flex-wrap gap-2">
<a
href="/blog"
class="inline-block px-4 py-2 bg-secondary text-white rounded-lg font-medium transition-all duration-200 hover:bg-secondary/90"
class="inline-block px-4 py-2 bg-secondary dark:bg-primary text-white dark:text-gray-900 rounded-lg font-medium transition-all duration-200 hover:bg-secondary/90 dark:hover:bg-primary/90"
>
All Posts ({sortedPosts.length})
</a>
@ -96,7 +95,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
sortedTags.map(({ tag, count }: TagCount) => (
<a
href={`/blog/tag/${tag}`}
class="inline-block px-4 py-2 bg-gray-100 text-gray-700 rounded-lg font-medium transition-all duration-200 hover:bg-secondary hover:text-white"
class="inline-block px-4 py-2 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 rounded-lg font-medium transition-all duration-200 hover:bg-secondary hover:text-white dark:hover:bg-primary dark:hover:text-gray-900"
>
{tag} ({count})
</a>
@ -110,7 +109,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
<div id="posts-container" class="space-y-8">
{
initialPosts.map((post: BlogPost) => (
<article class="bg-white rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-shadow duration-300">
<article class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-all duration-300">
<div class="block">
{post.data.heroImage && (
<a href={`/blog/${post.slug}`} class="block">
@ -129,7 +128,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
</a>
)}
<div class="p-8">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500 dark:text-gray-400">
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString("en-US", {
year: "numeric",
@ -144,7 +143,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
{post.data.tags.slice(0, 3).map((tag: string) => (
<a
href={`/blog/tag/${tag}`}
class="px-2 py-1 bg-secondary/10 text-gray-800 text-xs rounded-lg font-medium hover:bg-secondary hover:text-white transition-all duration-200"
class="px-2 py-1 bg-secondary/10 dark:bg-primary/20 text-gray-800 dark:text-gray-200 text-xs rounded-lg font-medium hover:bg-secondary hover:text-white dark:hover:bg-primary dark:hover:text-gray-900 transition-all duration-200"
>
{tag}
</a>
@ -154,13 +153,13 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
)}
</div>
<a href={`/blog/${post.slug}`} class="block group">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 mb-3 group-hover:text-secondary-700 transition-colors">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-3 group-hover:text-secondary-700 dark:group-hover:text-primary transition-colors">
{post.data.title}
</h2>
<p class="text-gray-700 text-lg leading-relaxed mb-4">
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4">
{post.data.description}
</p>
<div class="flex items-center text-secondary-800 font-medium">
<div class="flex items-center text-secondary-800 dark:text-primary font-medium">
Read more
<svg
xmlns="http://www.w3.org/2000/svg"
@ -185,14 +184,14 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
<div id="loading" class="hidden text-center py-8">
<div
class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-white border-t-transparent"
class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-gray-800 dark:border-gray-200 border-t-transparent"
>
</div>
<p class="text-white mt-4">Loading more posts...</p>
<p class="text-gray-800 dark:text-gray-200 mt-4">Loading more posts...</p>
</div>
<div id="end-message" class="hidden text-center py-8">
<p class="text-white/80 text-lg">You've reached the end! 🎉</p>
<p class="text-gray-800/80 dark:text-gray-200/80 text-lg">You've reached the end! 🎉</p>
</div>
</div>
</div>
@ -211,7 +210,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
function createPostElement(post) {
const article = document.createElement("article");
article.className =
"bg-white rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-shadow duration-300";
"bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-all duration-300";
const heroImageHTML = post.data.heroImage
? `
@ -237,7 +236,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
.slice(0, 3)
.map(
(tag) =>
`<a href="/blog/tag/${tag}" class="px-2 py-1 bg-secondary/10 text-secondary-700 text-xs rounded-lg font-medium hover:bg-secondary hover:text-white transition-all duration-200">${tag}</a>`
`<a href="/blog/tag/${tag}" class="px-2 py-1 bg-secondary/10 dark:bg-primary/20 text-gray-800 dark:text-gray-200 text-xs rounded-lg font-medium hover:bg-secondary hover:text-white dark:hover:bg-primary dark:hover:text-gray-900 transition-all duration-200">${tag}</a>`
)
.join("")}
</div>
@ -255,20 +254,20 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
<div class="block">
${heroImageHTML}
<div class="p-8">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500 dark:text-gray-400">
<time datetime="${pubDate.toISOString()}">
${formattedDate}
</time>
${tagsHTML}
</div>
<a href="/blog/${post.slug}" class="block group">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 mb-3 group-hover:text-secondary-700 transition-colors">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-3 group-hover:text-secondary-700 dark:group-hover:text-primary transition-colors">
${post.data.title}
</h2>
<p class="text-gray-700 text-lg leading-relaxed mb-4">
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4">
${post.data.description}
</p>
<div class="flex items-center text-secondary font-medium">
<div class="flex items-center text-secondary dark:text-primary font-medium">
Read more
<svg
xmlns="http://www.w3.org/2000/svg"

View file

@ -35,10 +35,13 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
tags={entry.data.tags}
>
<Navbar />
<div class="min-h-screen pt-16 bg-gray-50">
<div class="min-h-screen pt-16 bg-gray-50 dark:bg-gray-900 transition-colors duration-200">
<article class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8 md:py-12">
<header class="mb-8 md:mb-12">
<time datetime={entry.data.pubDate.toISOString()} class="block mb-3 text-sm text-gray-600">
<time
datetime={entry.data.pubDate.toISOString()}
class="block mb-3 text-sm text-gray-600 dark:text-gray-400"
>
{
entry.data.pubDate.toLocaleDateString("en-US", {
year: "numeric",
@ -53,7 +56,7 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
{entry.data.tags.map((tag: string) => (
<a
href={`/blog/tag/${tag}`}
class="px-3 py-1.5 bg-gray-100 text-gray-700 text-xs rounded-lg font-medium hover:bg-gray-900 hover:text-white transition-all duration-200"
class="px-3 py-1.5 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 text-xs rounded-lg font-medium hover:bg-gray-900 hover:text-white dark:hover:bg-primary dark:hover:text-gray-900 transition-all duration-200"
>
{tag}
</a>
@ -61,10 +64,12 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
</div>
)
}
<h1 class="text-gray-900 mb-4 text-3xl md:text-4xl lg:text-5xl font-bold leading-tight">
<h1
class="text-gray-900 dark:text-gray-100 mb-4 text-3xl md:text-4xl lg:text-5xl font-bold leading-tight"
>
{entry.data.title}
</h1>
<p class="text-lg md:text-xl text-gray-600 leading-relaxed mb-6">
<p class="text-lg md:text-xl text-gray-600 dark:text-gray-400 leading-relaxed mb-6">
{entry.data.description}
</p>
</header>
@ -87,13 +92,17 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
)
}
<div class="bg-white rounded-xl md:rounded-2xl shadow-xl p-6 sm:p-8 md:p-12 lg:p-16">
<div
class="bg-white dark:bg-gray-800 rounded-xl md:rounded-2xl shadow-xl p-6 sm:p-8 md:p-12 lg:p-16 transition-colors duration-200"
>
<div class="prose prose-xl max-w-none">
<Content />
</div>
</div>
<div class="mt-8 md:mt-12 bg-white rounded-xl md:rounded-2xl shadow-lg p-6 sm:p-8">
<div
class="mt-8 md:mt-12 bg-white dark:bg-gray-800 rounded-xl md:rounded-2xl shadow-lg p-6 sm:p-8 transition-colors duration-200"
>
<div class="flex items-start gap-6">
<Image
src={mePhoto}
@ -105,8 +114,10 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
format="webp"
/>
<div>
<h3 class="text-lg md:text-xl font-bold text-gray-900 mb-2">Lorenzo Iovino</h3>
<p class="text-sm md:text-base text-gray-700 mb-4">
<h3 class="text-lg md:text-xl font-bold text-gray-900 dark:text-gray-100 mb-2">
Lorenzo Iovino
</h3>
<p class="text-sm md:text-base text-gray-700 dark:text-gray-300 mb-4">
Software Engineer based in Sicily, passionate about technology, remote work, and life
balance. When not coding, you'll find me working on my vineyard or exploring the
beautiful Sicilian countryside.
@ -116,7 +127,7 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
href="https://www.linkedin.com/in/lorenzoiovino/"
target="_blank"
rel="noopener noreferrer"
class="text-gray-600 hover:text-gray-900 transition-colors"
class="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors"
aria-label="Visit Lorenzo Iovino's LinkedIn profile"
>
<svg class="w-5 h-5 md:w-6 md:h-6" fill="currentColor" viewBox="0 0 24 24">
@ -129,7 +140,7 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
href="https://github.com/thisloke"
target="_blank"
rel="noopener noreferrer"
class="text-gray-600 hover:text-gray-900 transition-colors"
class="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors"
aria-label="Visit Lorenzo Iovino's GitHub profile"
>
<svg class="w-5 h-5 md:w-6 md:h-6" fill="currentColor" viewBox="0 0 24 24">
@ -146,7 +157,7 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
<div class="mt-8 md:mt-12 text-center">
<a
href="/blog"
class="inline-flex items-center px-5 py-2.5 md:px-6 md:py-3 bg-white hover:bg-gray-50 text-gray-900 font-medium rounded-lg md:rounded-xl transition-all duration-200 shadow-md hover:shadow-lg border border-gray-200"
class="inline-flex items-center px-5 py-2.5 md:px-6 md:py-3 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100 font-medium rounded-lg md:rounded-xl transition-all duration-200 shadow-md hover:shadow-lg border border-gray-200 dark:border-gray-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"

View file

@ -41,12 +41,12 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
description={`Browse all blog posts about ${displayTag}. ${posts.length} article${posts.length !== 1 ? "s" : ""} found.`}
>
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
<div class="min-h-screen pt-16 bg-secondary dark:bg-gray-900 transition-colors duration-200">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-20">
<div class="mb-16 text-center">
<a
href="/blog"
class="inline-flex items-center text-white/80 hover:text-white transition-colors mb-6"
class="inline-flex items-center text-gray-800/80 dark:text-gray-200/80 hover:text-gray-800 dark:hover:text-gray-200 transition-colors mb-6"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -64,7 +64,7 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
<div class="flex items-center justify-center gap-3 mb-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-white"
class="h-8 w-8 text-gray-800 dark:text-gray-200"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -76,18 +76,18 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
></path>
</svg>
<h1 class="text-white mb-0">{displayTag}</h1>
<h1 class="text-gray-800 dark:text-gray-100 mb-0">{displayTag}</h1>
</div>
<p class="text-xl text-white/90 max-w-2xl mx-auto">
<p class="text-xl text-gray-800/90 dark:text-gray-300 max-w-2xl mx-auto">
{posts.length} article{posts.length !== 1 ? "s" : ""} about {displayTag.toLowerCase()}
</p>
<div class="h-1 w-20 bg-white rounded-full mx-auto mt-6"></div>
<div class="h-1 w-20 bg-gray-800 dark:bg-primary rounded-full mx-auto mt-6"></div>
</div>
<div class="space-y-8">
{
posts.map((post: BlogPost) => (
<article class="bg-white rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-shadow duration-300">
<article class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-all duration-300">
<div class="block">
{post.data.heroImage && (
<a href={`/blog/${post.slug}`} class="block">
@ -106,7 +106,7 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
</a>
)}
<div class="p-8">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500">
<div class="flex items-center gap-3 mb-4 text-sm text-gray-500 dark:text-gray-400">
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString("en-US", {
year: "numeric",
@ -135,13 +135,13 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
)}
</div>
<a href={`/blog/${post.slug}`} class="block group">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 mb-3 group-hover:text-secondary-700 transition-colors">
<h2 class="text-2xl md:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-3 group-hover:text-secondary-700 dark:group-hover:text-primary transition-colors">
{post.data.title}
</h2>
<p class="text-gray-700 text-lg leading-relaxed mb-4">
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4">
{post.data.description}
</p>
<div class="flex items-center text-secondary-700 font-medium">
<div class="flex items-center text-secondary-700 dark:text-primary font-medium">
Read more
<svg
xmlns="http://www.w3.org/2000/svg"
@ -166,10 +166,10 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
{
posts.length === 0 && (
<div class="bg-white rounded-2xl shadow-soft-lg p-12 text-center">
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg p-12 text-center transition-colors duration-200">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-16 w-16 mx-auto text-gray-300 mb-4"
class="h-16 w-16 mx-auto text-gray-300 dark:text-gray-600 mb-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -181,7 +181,7 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<p class="text-gray-600 text-lg">No posts found with this tag.</p>
<p class="text-gray-600 dark:text-gray-400 text-lg">No posts found with this tag.</p>
</div>
)
}

View file

@ -6,19 +6,18 @@ import Navbar from "../components/Navbar.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout
title="Lorenzo Iovino >> Homepage "
description="Lorenzo Iovino - Software Engineer"
>
<BaseLayout title="Lorenzo Iovino >> Homepage " description="Lorenzo Iovino - Software Engineer">
<Navbar />
<div class="bg-secondary min-h-screen flex flex-col relative pt-16">
<div
class="bg-secondary dark:bg-gray-900 min-h-screen flex flex-col relative pt-16 transition-colors duration-200"
>
<div class="flex-grow flex items-center justify-center relative z-10 py-12">
<Hero />
</div>
<div class="relative">
<div
class="absolute bottom-0 left-0 right-0 pointer-events-none z-20"
style="height: 100px; margin-bottom: 0;"
style="height: 110px; margin-bottom: 0;"
>
<Fish />
</div>

View file

@ -12,8 +12,11 @@
/* Typography base */
body {
@apply font-sans text-base text-gray-900;
font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
@apply font-sans text-base text-gray-900 dark:text-gray-100;
font-feature-settings:
"kern" 1,
"liga" 1,
"calt" 1;
}
/* Headings ottimizzati */
@ -23,8 +26,12 @@
h4,
h5,
h6 {
@apply font-bold;
font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "ss01" 1;
@apply font-bold text-gray-900 dark:text-gray-100;
font-feature-settings:
"kern" 1,
"liga" 1,
"calt" 1,
"ss01" 1;
}
h1 {
@ -50,7 +57,11 @@
/* Link ottimizzati */
a {
@apply transition-colors duration-200;
@apply transition-colors duration-200 text-gray-800 dark:text-gray-200;
}
a:hover {
@apply text-gray-600 dark:text-gray-400;
}
/* Strong e emphasis */

View file

@ -4,6 +4,10 @@
line-height: 1.875 !important;
}
.dark .prose {
color: #d1d5db !important;
}
.prose h2 {
font-size: 2.25rem !important;
font-weight: 700 !important;
@ -16,11 +20,14 @@
padding-bottom: 1rem !important;
}
.dark .prose h2 {
color: #f3f4f6 !important;
}
.prose > h2:first-child {
margin-top: 0 !important;
}
.prose h2::after {
content: "";
position: absolute;
@ -32,6 +39,10 @@
border-radius: 2px;
}
.dark .prose h2::after {
background: linear-gradient(90deg, #f9bc2e 0%, #fbd46c 100%);
}
@media (min-width: 768px) {
.prose h2 {
font-size: 3rem !important;
@ -48,6 +59,10 @@
letter-spacing: -0.01em !important;
}
.dark .prose h3 {
color: #f3f4f6 !important;
}
@media (min-width: 768px) {
.prose h3 {
font-size: 1.875rem !important;
@ -63,6 +78,10 @@
line-height: 1.4 !important;
}
.dark .prose h4 {
color: #f3f4f6 !important;
}
@media (min-width: 768px) {
.prose h4 {
font-size: 1.5rem !important;
@ -76,6 +95,10 @@
font-weight: 400 !important;
}
.dark .prose p {
color: #d1d5db !important;
}
@media (min-width: 768px) {
.prose p {
font-size: 1.1rem !important;
@ -83,8 +106,7 @@
}
.prose > p:first-of-type {
margin-top: 1.6rem
margin-top: 1.6rem;
}
@media (min-width: 768px) {
@ -102,21 +124,38 @@
transition: all 0.2s ease !important;
}
.dark .prose a {
color: #d1d5db !important;
}
.prose a:hover {
color: #111827 !important;
text-decoration-color: #111827 !important;
}
.dark .prose a:hover {
color: #f3f4f6 !important;
text-decoration-color: #f9bc2e !important;
}
.prose strong {
font-weight: 700 !important;
color: #111827 !important;
}
.dark .prose strong {
color: #f3f4f6 !important;
}
.prose em {
font-style: italic !important;
color: #4b5563 !important;
}
.dark .prose em {
color: #9ca3af !important;
}
.prose ul,
.prose ol {
margin-top: 2rem !important;
@ -140,6 +179,10 @@
margin-bottom: 0.75rem !important;
}
.dark .prose li {
color: #d1d5db !important;
}
@media (min-width: 768px) {
.prose li {
font-size: 1.1rem !important;
@ -151,6 +194,10 @@
font-weight: 600 !important;
}
.dark .prose li::marker {
color: #9ca3af !important;
}
.prose blockquote {
border-left: 4px solid #6b7280 !important;
background-color: #f9fafb !important;
@ -163,6 +210,12 @@
line-height: 1.6 !important;
}
.dark .prose blockquote {
border-left-color: #9ca3af !important;
background-color: #374151 !important;
color: #d1d5db !important;
}
.prose code {
background-color: #f3f4f6 !important;
color: #374151 !important;
@ -170,8 +223,14 @@
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;
font-family:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
monospace !important;
}
.dark .prose code {
background-color: #374151 !important;
color: #f3f4f6 !important;
}
.prose pre {
@ -197,6 +256,10 @@
border-width: 2px !important;
}
.dark .prose hr {
border-color: #4b5563 !important;
}
.prose img {
border-radius: 1rem !important;
margin-top: 2.5rem !important;
@ -237,6 +300,10 @@
border-bottom: 2px solid #e5e7eb !important;
}
.dark .prose thead {
border-bottom-color: #4b5563 !important;
}
.prose th {
padding: 0.75rem 1rem !important;
text-align: left !important;
@ -244,16 +311,29 @@
color: #111827 !important;
}
.dark .prose th {
color: #f3f4f6 !important;
}
.prose td {
padding: 0.75rem 1rem !important;
border-bottom: 1px solid #e5e7eb !important;
color: #374151 !important;
}
.dark .prose td {
border-bottom-color: #4b5563 !important;
color: #d1d5db !important;
}
.prose tbody tr:hover {
background-color: #f9fafb !important;
}
.dark .prose tbody tr:hover {
background-color: #374151 !important;
}
/* Image Utility Classes */
/* Float classes */
@ -363,6 +443,12 @@
word-wrap: break-word !important;
}
.dark .prose div.float-left em,
.dark .prose div.float-right em,
.dark .prose div.w-full em {
color: #9ca3af !important;
}
@media (min-width: 768px) {
.prose div.float-right em {
margin-left: 2rem !important;

View file

@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
darkMode: 'class',
theme: {
colors: {
white: "#ffffff",