feat: implement automatic image optimization with Astro Assets

- Configure content collections to use image() helper for type-safe image references
- Replace all <img> tags with <Image> component from astro:assets
- Migrate images from /public to /src/assets for automatic optimization
- Update blog posts to use relative paths in frontmatter (../../assets/photos/)
- Remove unused images and duplicates from /public folder
- Update Footer component to use optimized SVG icons
- Clean up manifest.json to use favicon.ico instead of deleted photos

Performance improvements:
- remote.jpg: 1.8MB → 128KB (93% reduction)
- me.png: 71KB → 12KB (83% reduction)
- Automatic WebP conversion
- Tree-shaking: only used images are optimized

/public folder reduced from 2.3MB to 32KB (only essential files)
Build output: 2.2MB with fully optimized images ready for S3 deployment
This commit is contained in:
Lorenzo Iovino 2026-01-08 17:40:19 +01:00
parent da03ed9e6f
commit 289dc9ef00
47 changed files with 632 additions and 419 deletions

2
src/assets/astro.svg Normal file
View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><title>file_type_astro</title><path d="M5.9,18.847a7.507,7.507,0,0,0-.572,2.624,3.265,3.265,0,0,0,.551,1.553,7.427,7.427,0,0,0,2.093,1.681L13.1,28.119A7.332,7.332,0,0,0,15.2,29.287a3.239,3.239,0,0,0,1.5,0,7.381,7.381,0,0,0,2.117-1.16L24,24.711a7.512,7.512,0,0,0,2.117-1.688,3.241,3.241,0,0,0,.55-1.563,7.515,7.515,0,0,0-.587-2.643L21.547,4.551a3.973,3.973,0,0,0-.54-1.3,1.733,1.733,0,0,0-.7-.51,3.972,3.972,0,0,0-1.4-.122H13.005a3.932,3.932,0,0,0-1.4.125,1.713,1.713,0,0,0-.7.512,3.94,3.94,0,0,0-.535,1.3L5.9,18.848Zm13.24-13.2a3.329,3.329,0,0,1,.441,1.093l3.892,12.784a16.168,16.168,0,0,0-4.653-1.573L16.291,9.391a.331.331,0,0,0-.513-.169.323.323,0,0,0-.119.169l-2.5,8.557a16.14,16.14,0,0,0-4.674,1.579L12.393,6.743a3.281,3.281,0,0,1,.442-1.094,1.458,1.458,0,0,1,.582-.43,3.31,3.31,0,0,1,1.175-.1h2.793a3.314,3.314,0,0,1,1.176.1,1.454,1.454,0,0,1,.583.432ZM16.127,21.06a5.551,5.551,0,0,0,3.4-.923,2.8,2.8,0,0,1-.207,2.182A3.938,3.938,0,0,1,17.773,23.8c-.674.428-1.254.8-1.254,1.787a2.079,2.079,0,0,0,.209.914,2.49,2.49,0,0,1-1.535-2.3v-.061c0-.683,0-1.524-.962-1.524a1.028,1.028,0,0,0-.391.077,1.021,1.021,0,0,0-.552.551,1.03,1.03,0,0,0-.079.391,3.769,3.769,0,0,1-.988-2.644,4.206,4.206,0,0,1,.175-1.248c.4.757,1.92,1.32,3.731,1.32Z" style="fill:#ff5d01;fill-rule:evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/assets/cat.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 KiB

BIN
src/assets/cloud.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

19
src/assets/github.svg Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>github [#142]</title>
<desc>Created with Sketch.</desc>
<defs>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Dribbble-Light-Preview" transform="translate(-140.000000, -7559.000000)" fill="#000000">
<g id="icons" transform="translate(56.000000, 160.000000)">
<path d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399" id="github-[#142]">
</path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/assets/green.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

7
src/assets/linkedin.svg Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.5 8C7.32843 8 8 7.32843 8 6.5C8 5.67157 7.32843 5 6.5 5C5.67157 5 5 5.67157 5 6.5C5 7.32843 5.67157 8 6.5 8Z" fill="#0F0F0F"/>
<path d="M5 10C5 9.44772 5.44772 9 6 9H7C7.55228 9 8 9.44771 8 10V18C8 18.5523 7.55228 19 7 19H6C5.44772 19 5 18.5523 5 18V10Z" fill="#0F0F0F"/>
<path d="M11 19H12C12.5523 19 13 18.5523 13 18V13.5C13 12 16 11 16 13V18.0004C16 18.5527 16.4477 19 17 19H18C18.5523 19 19 18.5523 19 18V12C19 10 17.5 9 15.5 9C13.5 9 13 10.5 13 10.5V10C13 9.44771 12.5523 9 12 9H11C10.4477 9 10 9.44772 10 10V18C10 18.5523 10.4477 19 11 19Z" fill="#0F0F0F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 1C21.6569 1 23 2.34315 23 4V20C23 21.6569 21.6569 23 20 23H4C2.34315 23 1 21.6569 1 20V4C1 2.34315 2.34315 1 4 1H20ZM20 3C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3H20Z" fill="#0F0F0F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
src/assets/photos/dogs.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
src/assets/photos/me-cc.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
src/assets/photos/me.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

BIN
src/assets/photos/pokemon.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
src/assets/photos/wine.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
src/assets/plane.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

1
src/assets/tailwind.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 54 33"><g clip-path="url(#prefix__clip0)"><path fill="#ffffff" fill-rule="evenodd" d="M27 0c-7.2 0-11.7 3.6-13.5 10.8 2.7-3.6 5.85-4.95 9.45-4.05 2.054.513 3.522 2.004 5.147 3.653C30.744 13.09 33.808 16.2 40.5 16.2c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C36.756 3.11 33.692 0 27 0zM13.5 16.2C6.3 16.2 1.8 19.8 0 27c2.7-3.6 5.85-4.95 9.45-4.05 2.054.514 3.522 2.004 5.147 3.653C17.244 29.29 20.308 32.4 27 32.4c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C23.256 19.31 20.192 16.2 13.5 16.2z" clip-rule="evenodd"/></g><defs><clipPath id="prefix__clip0"><path fill="#fff" d="M0 0h54v32.4H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 772 B

View file

@ -1,5 +1,8 @@
---
import { Image } from "astro:assets";
import astroIcon from "../assets/astro.svg";
import tailwindIcon from "../assets/tailwind.svg";
import githubIcon from "../assets/github.svg";
---
<div class="w-full bg-secondary py-2 px-4">
@ -79,11 +82,11 @@
class="inline-flex items-center hover:text-white transition-all duration-200"
title="Astro"
>
<img
<Image
class="h-5 w-5"
src="/astro.svg"
height="20"
width="20"
src={astroIcon}
width={20}
height={20}
loading="lazy"
alt="Astro Logo"
/>
@ -94,11 +97,11 @@
class="inline-flex items-center center hover:text-white transition-all duration-200"
title="TailwindCSS"
>
<img
<Image
class="h-5 w-5"
src="/tailwind.svg"
height="20"
width="20"
src={tailwindIcon}
width={20}
height={20}
loading="lazy"
alt="Tailwind Logo"
/>
@ -109,11 +112,11 @@
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"
<Image
src={githubIcon}
class="h-5 w-5"
height="20"
width="20"
width={20}
height={20}
loading="lazy"
alt="Github Logo"
/>

View file

@ -1,5 +1,8 @@
---
import { Image } from "astro:assets";
import mePhoto from "../assets/photos/me.png";
import linkedinIcon from "../assets/linkedin.svg";
import githubIcon from "../assets/github.svg";
---
<div class="w-full">
@ -12,12 +15,14 @@
<!-- 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"
<Image
src={mePhoto}
alt="Photo of Lorenzo Iovino"
class="w-48 h-auto md:w-full object-cover object-center"
width="300"
height="300"
width={300}
height={300}
quality={90}
format="webp"
/>
<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>
@ -57,12 +62,12 @@
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"
<Image
src={linkedinIcon}
alt="LinkedIn"
class="h-6 w-6 opacity-70 group-hover:opacity-100 transition-opacity"
width="24"
height="24"
width={24}
height={24}
loading="lazy"
/>
</a>
@ -71,12 +76,12 @@
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"
<Image
src={githubIcon}
alt="GitHub"
class="h-6 w-6 opacity-70 group-hover:opacity-100 transition-opacity"
width="24"
height="24"
width={24}
height={24}
loading="lazy"
/>
</a>

View file

@ -3,6 +3,21 @@ title: "My Story"
description: "A journey through code, curiosity, and creativity"
---
import { Image } from 'astro:assets';
import meBaby from '../../assets/photos/me-baby.jpg';
import pokemon from '../../assets/photos/pokemon.jpg';
import meGuitar from '../../assets/photos/me-guitar-17.jpg';
import meCC from '../../assets/photos/me-cc.jpg';
import goliardia from '../../assets/photos/goliardia.jpg';
import meMoverio from '../../assets/photos/me-moverio.jpg';
import gameJam from '../../assets/photos/game-jam.jpg';
import valenciaTuria from '../../assets/photos/valencia-turia.jpg';
import remote from '../../assets/photos/remote.jpg';
import dogs from '../../assets/photos/dogs.jpg';
import wine from '../../assets/photos/wine.jpg';
import modica from '../../assets/photos/modica.jpg';
import meAmanda from '../../assets/photos/me-amanda.jpg';
## Hello world!
Hi! Im Lorenzo Iovino.
@ -16,8 +31,8 @@ This page is a small recap of my story. Nothing special, just me.
## Childhood Nostalgia
<div class="float-right img-medium">
<img src="/photos/me-baby.jpg" alt="Super young software developer with an Apple II" class="float-right img-medium" />
<em class="text-sm block mt-2">Super young software developer with an Apple II</em>
<Image src={meBaby} alt="Super young geek with an Apple II" class="float-right img-medium" width={400} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">Super young software geek with an Apple II</em>
</div>
My first “wow” moment with computers was very early. I was around 4 years old and I was playing Prince of Persia on an Apple II.
@ -29,7 +44,7 @@ I grew up in Ispica, in the south of Sicily. My days were simple: school, videog
Ispica is slow, warm, and beautiful. When I was a kid I didnt see it that way. I wanted to escape. I was dreaming about big cities, more people, more things happening, more opportunities.
<div class="float-left img-medium">
<img src="/photos/pokemon.jpg" alt="Pokemon Yellow and Game Boy Advance" class="float-left img-medium" />
<Image src={pokemon} alt="Pokemon Yellow and Game Boy Advance" class="float-left img-medium" width={400} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">Pokemon Yellow and Game Boy Advance</em>
</div>
@ -38,7 +53,7 @@ Then came Pokemon, Nintendo consoles, and long afternoons with friends. And at s
When I was 15 I discovered rock music and it hit me hard. I bought a guitar and I started learning (very badly at the beginning) but I loved it.
<div class="float-right img-medium">
<img src="/photos/me-guitar-17.jpg" alt="My dream guitar Fender stratocaster" class="float-right img-medium" />
<Image src={meGuitar} alt="My dream guitar Fender stratocaster" class="float-right img-medium" width={400} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">My dream guitar "Fender stratocaster"</em>
</div>
@ -51,7 +66,7 @@ At 17 I also discovered Magic: The Gathering. It became another obsession for a
I studied Computer Science at the University of Pisa. It was not a straight path.
<div class="float-right img-medium">
<img src="/photos/me-cc.jpg" alt="Me burning out studying" class="float-right img-medium" />
<Image src={meCC} alt="Me burning out studying" class="float-right img-medium" width={400} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">Me burning out studying Computability and Complexity exam</em>
</div>
@ -64,7 +79,7 @@ It took me 12 years to finish my Bachelor. Not proud of the timeline, but Im
Moving to Pisa was not only about studying. It was also my first real “life outside Sicily” experience, and I needed that.
<div class="float-left img-medium">
<img src="/photos/goliardia.jpg" alt="My student hat goliardo" class="float-left img-medium" />
<Image src={goliardia} alt="My student hat goliardo" class="float-left img-medium" width={400} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">My student hat (that's not a hat) "goliardo"</em>
</div>
@ -75,7 +90,7 @@ That period also started my love for traveling. Seeing different cultures in rea
## Embarking on Hackathon Adventures
<div class="float-right img-small">
<img src="/photos/me-moverio.jpg" alt="Me wearing moverio smart glasses" class="float-right img-small" />
<Image src={meMoverio} alt="Me wearing moverio smart glasses" class="float-right img-small" width={300} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">Me wearing moverio smart glasses</em>
</div>
@ -88,7 +103,7 @@ It was made for Epson Moverio Smartglass: the idea was to let people “place”
That experience made me addicted to hackathons. After that I joined other events like Hackaton Toscana (mobility) and also some game jams. Every time you learn something new, and you also learn a lot about teamwork under pressure.
<div class="w-full">
<img src="/photos/game-jam.jpg" alt="Me and the team presenting the game" class="img-hero" />
<Image src={gameJam} alt="Me and the team presenting the game" class="img-hero" width={1200} height={630} quality={80} format="webp" />
<em class="text-sm block mt-2">Me and the team presenting the game developed</em>
</div>
@ -97,7 +112,7 @@ That experience made me addicted to hackathons. After that I joined other events
## Erasmus Project in Valencia
<div class="float-right img-large">
<img src="/photos/valencia-turia.jpg" alt="Beautiful sunny day in Valencia" class="float-right img-large" />
<Image src={valenciaTuria} alt="Beautiful sunny day in Valencia" class="float-right img-large" width={600} height={400} quality={80} format="webp" />
<em class="text-sm block mt-2">Beautiful sunny day in Valencia</em>
</div>
@ -116,7 +131,7 @@ At some point I decided to go back to Sicily.
Not as a “I give up” move. More like: I want a different balance.
<div class="float-left img-medium">
<img src="/photos/remote.jpg" alt="Working remote watching the sea" class="float-left img-medium" />
<Image src={remote} alt="Working remote watching the sea" class="float-left img-medium" width={400} height={300} quality={80} format="webp" />
<em class="text-sm block mt-2">Working remote watching the sea</em>
</div>
@ -127,7 +142,7 @@ I work remote, and Sicily is perfect for that. Life is slower. Sometimes its
Time here feels different. You can actually breathe. You can have “nothing special” days, and those days can still feel good.
<div class="w-full">
<img src="/photos/dogs.jpg" alt="My wineyard" class="img-hero" />
<Image src={dogs} alt="My wineyard" class="img-hero" width={1200} height={630} quality={80} format="webp" />
<em class="text-sm block mt-2">My wineyard</em>
</div>
@ -136,7 +151,7 @@ Family is a big part of my life here. And I also started a side project with my
That project became [www.netum.it](https://netum.it/). Its small (1 hectare), limited bottles, but its something we built together and I love it.
<div class="float-right img-small">
<img src="/photos/wine.jpg" alt="The wine produced Zia Lina" class="float-right img-small" />
<Image src={wine} alt="The wine produced Zia Lina" class="float-right img-small" width={300} height={300} quality={85} format="webp" />
<em class="text-sm block mt-2">The wine produced "Zia Lina"</em>
</div>
@ -147,7 +162,7 @@ And yes: food. Sicily is crazy for food. Its not even a “food culture”, i
For me, living here is a reminder: success is not only about projects and code. Its also about how you live your days.
<div class="w-full">
<img src="/photos/modica.jpg" alt="Modica view from my house" class="img-hero" />
<Image src={modica} alt="Modica view from my house" class="img-hero" width={1200} height={630} quality={80} format="webp" />
<em class="text-sm block mt-2">Modica view from my house</em>
</div>
@ -158,6 +173,6 @@ Today Im a husband (to my wife Amanda) and a dad (to our little Leonardo).
Life changed a lot, in a good way. I still love technology, I still build things, but family gives a different meaning to everything.
<div class="w-full">
<img src="/photos/me-amanda.jpg" alt="Me and my wife Amanda" class="img-hero" />
<Image src={meAmanda} alt="Me and my wife Amanda" class="img-hero" width={1200} height={630} quality={85} format="webp" />
<em class="text-sm block mt-2">Me and my wife Amanda</em>
</div>

View file

@ -2,7 +2,7 @@
title: "Welcome to My Blog!"
description: "First commit"
pubDate: 2024-01-15
heroImage: "/photos/remote.jpg"
heroImage: "../../assets/photos/remote.jpg"
tags: ["personal", "welcome"]
---

View file

@ -2,12 +2,12 @@ import { defineCollection, z } from "astro:content";
const blog = defineCollection({
type: "content",
schema: z.object({
schema: ({ image }) => z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
heroImage: z.string().optional(),
heroImage: image().optional(),
author: z.string().default("Lorenzo Iovino"),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),

View file

@ -12,7 +12,7 @@ interface Props {
const {
title,
description = "Lorenzo Iovino - Software Developer based in Sicily. Passionate about technology, remote work, and life balance.",
description = "Lorenzo Iovino - Software Engineer based in Sicily. Passionate about technology, remote work, and life balance.",
canonicalUrl,
image = "/photos/me.png",
type = "website",
@ -21,7 +21,7 @@ const {
tags = [],
} = Astro.props;
const siteUrl = "https://lorenzoiovino.com";
const siteUrl = "https://www.lorenzoiovino.com";
const fullImageUrl = image.startsWith("http") ? image : `${siteUrl}${image}`;
const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;

View file

@ -1,10 +1,13 @@
---
import type { CollectionEntry } from "astro:content";
import { getEntry } from "astro:content";
import { Image } from "astro:assets";
import Footer from "../components/Footer.astro";
import Navbar from "../components/Navbar.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
import "../styles/prose.css";
import linkedinIcon from "../assets/linkedin.svg";
import githubIcon from "../assets/github.svg";
type BioEntry = CollectionEntry<"bio">;
@ -20,7 +23,6 @@ const { Content } = await bioEntry.render();
<BaseLayout
title="Lorenzo Iovino >> Bio"
description="Biography and life story of Lorenzo Iovino"
canonicalUrl="https://www.lorenzoiovino.com/bio"
>
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
@ -56,12 +58,12 @@ const { Content } = await bioEntry.render();
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"
>
<img
src="/linkedin.svg"
<Image
src={linkedinIcon}
alt="LinkedIn"
class="h-6 w-6 mr-3 opacity-80"
width="24"
height="24"
width={24}
height={24}
/>
LinkedIn
</a>
@ -71,12 +73,12 @@ const { Content } = await bioEntry.render();
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"
>
<img
src="/github.svg"
<Image
src={githubIcon}
alt="GitHub"
class="h-6 w-6 mr-3 opacity-80"
width="24"
height="24"
width={24}
height={24}
/>
GitHub
</a>

View file

@ -1,6 +1,7 @@
---
import type { CollectionEntry } from "astro:content";
import { getCollection } from "astro:content";
import { Image } from "astro:assets";
import Footer from "../components/Footer.astro";
import Navbar from "../components/Navbar.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
@ -33,7 +34,6 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
<BaseLayout
title="Lorenzo Iovino >> Blog"
description="Blog posts and articles by Lorenzo Iovino"
canonicalUrl="https://www.lorenzoiovino.com/blog"
>
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
@ -115,10 +115,14 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
{post.data.heroImage && (
<a href={`/blog/${post.slug}`} class="block">
<div class="relative h-64 overflow-hidden">
<img
<Image
src={post.data.heroImage}
alt={post.data.title}
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
width={1200}
height={630}
quality={80}
format="webp"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
</div>

View file

@ -1,6 +1,7 @@
---
import type { CollectionEntry } from "astro:content";
import { getCollection } from "astro:content";
import { Image } from "astro:assets";
import BaseLayout from "../../layouts/BaseLayout.astro";
import Navbar from "../../components/Navbar.astro";
import Footer from "../../components/Footer.astro";
@ -18,13 +19,15 @@ export async function getStaticPaths() {
const { entry }: { entry: BlogPost } = Astro.props;
const { Content } = await entry.render();
// Extract image src for meta tags (Open Graph expects a URL string)
const heroImageSrc = entry.data.heroImage?.src || "/photos/me.png";
---
<BaseLayout
title={`${entry.data.title} | Lorenzo Iovino`}
description={entry.data.description}
canonicalUrl={`https://www.lorenzoiovino.com/blog/${entry.slug}`}
image={entry.data.heroImage || "/photos/me.png"}
image={heroImageSrc}
type="article"
publishedTime={entry.data.pubDate}
modifiedTime={entry.data.updatedDate}
@ -69,10 +72,14 @@ const { Content } = await entry.render();
entry.data.heroImage && (
<div class="mb-8 md:mb-12 -mx-4 sm:mx-0">
<div class="relative h-64 sm:h-80 md:h-96 overflow-hidden sm:rounded-2xl shadow-xl">
<img
<Image
src={entry.data.heroImage}
alt={entry.data.title}
class="w-full h-full object-cover"
width={1200}
height={630}
quality={80}
format="webp"
/>
</div>
</div>
@ -91,6 +98,8 @@ const { Content } = await entry.render();
src="/photos/me.png"
alt="Lorenzo Iovino"
class="w-20 h-20 rounded-full object-cover"
width="80"
height="80"
/>
<div>
<h3 class="text-lg md:text-xl font-bold text-gray-900 mb-2">Lorenzo Iovino</h3>

View file

@ -1,6 +1,7 @@
---
import type { CollectionEntry } from "astro:content";
import { getCollection } from "astro:content";
import { Image } from "astro:assets";
import Footer from "../../../components/Footer.astro";
import Navbar from "../../../components/Navbar.astro";
import BaseLayout from "../../../layouts/BaseLayout.astro";
@ -38,7 +39,6 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
<BaseLayout
title={`${displayTag} Posts | Lorenzo Iovino Blog`}
description={`Browse all blog posts about ${displayTag}. ${posts.length} article${posts.length !== 1 ? "s" : ""} found.`}
canonicalUrl={`https://www.lorenzoiovino.com/blog/tag/${tag}`}
>
<Navbar />
<div class="min-h-screen pt-16 bg-secondary">
@ -92,10 +92,14 @@ const displayTag: string = tag.charAt(0).toUpperCase() + tag.slice(1);
{post.data.heroImage && (
<a href={`/blog/${post.slug}`} class="block">
<div class="relative h-64 overflow-hidden">
<img
<Image
src={post.data.heroImage}
alt={post.data.title}
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
width={1200}
height={630}
quality={80}
format="webp"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
</div>

View file

@ -7,9 +7,8 @@ import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout
title="Lorenzo Iovino >> Home"
description="Lorenzo Iovino - Software Developer"
canonicalUrl="https://www.lorenzoiovino.com"
title="Lorenzo Iovino >> Homepage "
description="Lorenzo Iovino - Software Engineer"
>
<Navbar />
<div class="bg-secondary min-h-screen flex flex-col relative pt-16">