Compare commits

..

2 Commits

Author SHA1 Message Date
3de62dba04 ci: fix lychee link checker binary on ARM and handle false positives
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 QA (push) Successful in 3m53s
Build & Deploy / 🏗️ Build (push) Successful in 2m39s
Build & Deploy / 🚀 Deploy (push) Successful in 27s
Build & Deploy / 🧪 Smoke Test (push) Successful in 49s
Build & Deploy / ♿ WCAG (push) Successful in 2m3s
Build & Deploy / 🛡️ Quality Gates (push) Successful in 3m24s
Build & Deploy / ⚡ Lighthouse (push) Successful in 7m2s
Build & Deploy / 🔔 Notify (push) Successful in 8s
2026-02-22 17:34:54 +01:00
fb2354d2cc feat: Add aspect ratio support to imgproxy loader and apply 16:9 aspect ratio to featured images across blog posts and recent posts. 2026-02-22 17:30:30 +01:00
5 changed files with 60 additions and 11 deletions

View File

@@ -76,7 +76,7 @@ export default async function BlogPost({ params }: BlogPostProps) {
<div className="relative w-full h-[70vh] min-h-[500px] overflow-hidden group">
<div className="absolute inset-0 transition-transform duration-[3s] ease-out scale-110 group-hover:scale-100">
<Image
src={post.frontmatter.featuredImage}
src={`${post.frontmatter.featuredImage}?ar=16:9`}
alt={post.frontmatter.title}
fill
priority

View File

@@ -31,7 +31,7 @@ export default function PostNavigation({
{prev.frontmatter.featuredImage ? (
<div
className="absolute inset-0 bg-cover bg-center transition-transform duration-700 group-hover:scale-110"
style={{ backgroundImage: `url(${prev.frontmatter.featuredImage})` }}
style={{ backgroundImage: `url(${prev.frontmatter.featuredImage}?ar=16:9)` }}
/>
) : (
<div className="absolute inset-0 bg-neutral-100" />
@@ -82,7 +82,7 @@ export default function PostNavigation({
{next.frontmatter.featuredImage ? (
<div
className="absolute inset-0 bg-cover bg-center transition-transform duration-700 group-hover:scale-110"
style={{ backgroundImage: `url(${next.frontmatter.featuredImage})` }}
style={{ backgroundImage: `url(${next.frontmatter.featuredImage}?ar=16:9)` }}
/>
) : (
<div className="absolute inset-0 bg-neutral-100" />

View File

@@ -43,7 +43,7 @@ export default async function RecentPosts({ locale }: RecentPostsProps) {
{post.frontmatter.featuredImage && (
<div className="relative h-64 overflow-hidden">
<Image
src={post.frontmatter.featuredImage}
src={`${post.frontmatter.featuredImage}?ar=16:9`}
alt={post.frontmatter.title}
fill
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"

View File

@@ -23,17 +23,37 @@ export default function imgproxyLoader({
return src;
}
// Check if src contains custom gravity query parameter
// Check if src contains custom gravity or aspect ratio query parameters
let gravity = 'sm'; // Use smart gravity (content-aware) by default
let cleanSrc = src;
let calculatedHeight = 0;
let resizingType: 'fit' | 'fill' = 'fit';
try {
// Dummy base needed for relative URLs
const url = new URL(src, 'http://localhost');
const customGravity = url.searchParams.get('gravity');
const aspectRatio = url.searchParams.get('ar'); // e.g. "16:9"
if (customGravity) {
gravity = customGravity;
url.searchParams.delete('gravity');
}
if (aspectRatio) {
const parts = aspectRatio.split(':');
if (parts.length === 2) {
const arW = parseFloat(parts[0]);
const arH = parseFloat(parts[1]);
if (!isNaN(arW) && !isNaN(arH) && arW > 0) {
calculatedHeight = Math.round(width * (arH / arW));
resizingType = 'fill'; // Must use fill to allow imgproxy to crop
}
}
url.searchParams.delete('ar');
}
if (customGravity || aspectRatio) {
cleanSrc = src.startsWith('http') ? url.href : url.pathname + url.search;
}
} catch (e) {
@@ -41,10 +61,11 @@ export default function imgproxyLoader({
}
// We use the width provided by Next.js for responsive images
// Height is set to 0 to maintain aspect ratio
// Height is calculated from aspect ratio if provided, otherwise 0 to maintain aspect ratio
return getImgproxyUrl(cleanSrc, {
width,
resizing_type: 'fit',
height: calculatedHeight,
resizing_type: resizingType,
gravity,
});
}

View File

@@ -4,7 +4,33 @@ set -e
# Auto-provision Lychee Rust Binary if missing
if [ ! -f ./lychee ]; then
echo "📥 Downloading Lychee Link Checker (v0.15.1)..."
curl -sSLo lychee.tar.gz https://github.com/lycheeverse/lychee/releases/download/v0.15.1/lychee-v0.15.1-x86_64-unknown-linux-gnu.tar.gz
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
VERSION="lychee-v0.23.0"
if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then
ARCH_MAPPED="x86_64"
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
ARCH_MAPPED="aarch64"
else
echo "❌ Unsupported architecture: $ARCH"
exit 1
fi
if [ "$OS" = "darwin" ]; then
TARGET="arm64-macos"
elif [ "$OS" = "linux" ]; then
TARGET="${ARCH_MAPPED}-unknown-linux-gnu"
else
echo "❌ Unsupported OS: $OS"
exit 1
fi
DOWNLOAD_URL="https://github.com/lycheeverse/lychee/releases/download/${VERSION}/lychee-${TARGET}.tar.gz"
echo "Downloading from $DOWNLOAD_URL"
curl -sSLo lychee.tar.gz "$DOWNLOAD_URL"
tar -xzf lychee.tar.gz lychee
rm lychee.tar.gz
chmod +x ./lychee
@@ -19,8 +45,10 @@ echo "🚀 Starting Deep Link Assessment (Lychee)..."
--exclude "127.0.0.1" \
--exclude "mintel\.me" \
--exclude "example\.com" \
--exclude-mail \
--accept 200,204,401,403 \
"./content/**/*.mdx" "./content/**/*.md" "./app/**/*.tsx" "./components/**/*.tsx"
--exclude "linkedin\.com" \
--exclude "fonts\." \
--base-url "http://127.0.0.1" \
--accept 200,204,308,401,403,999 \
"./data/**/*.mdx" "./data/**/*.md" "./app/**/*.tsx" "./components/**/*.tsx"
echo "✅ All project source links are alive and healthy!"