Fix HEIC/HEIF image loading in Docker and improve Timeline layout

- Rewrote Dockerfile to compile libvips with HEIF support from source
- Set sharp failOn: 'none' to handle minor image metadata warnings
- Improved timeline thumbnails: increased max-h, added object-[center_15%] to prevent cutting off heads, and added subtle hover effects
- Reverted horizontal timeline spacing to restore the original gap
- Polished timeline card padding and font sizes for a more premium look
This commit is contained in:
denshooter
2026-02-22 01:22:34 +01:00
parent 49d8798e11
commit 0facc29a97
3 changed files with 82 additions and 50 deletions
+2 -2
View File
@@ -55,7 +55,7 @@ export async function GET(
contentType = 'image/jpeg'
} else {
try {
const converted = await sharp(fs.readFileSync(filePath)).jpeg({ quality: 90 }).toBuffer()
const converted = await sharp(fs.readFileSync(filePath), { failOn: 'none' }).jpeg({ quality: 90 }).toBuffer()
fs.writeFileSync(jpegPath, converted)
fileToSendPath = jpegPath
ext = '.jpg'
@@ -83,7 +83,7 @@ export async function GET(
fileToSendPath = resizedPath
} else {
try {
let transformer = sharp(fs.readFileSync(fileToSendPath))
let transformer = sharp(fs.readFileSync(fileToSendPath), { failOn: 'none' })
.resize(targetWidth, null, { withoutEnlargement: true })
if (ext === '.jpg' || ext === '.jpeg') {
+15 -14
View File
@@ -75,16 +75,16 @@ export default function TimelineSection({ entries }: TimelineSectionProps) {
transition={{ duration: 0.6, delay: 0.1 }}
className={`relative flex items-start ${
isLeft
? 'pl-10 sm:pl-0 sm:pr-[50%]'
: 'pl-10 sm:pl-[50%]'
? 'pl-10 sm:pl-0 sm:pr-[52%]'
: 'pl-10 sm:pl-[52%]'
}`}
>
{/* Content Card */}
<motion.button
onClick={() => setSelectedEntry(entry)}
whileHover={{ scale: 1.02, y: -2 }}
whileTap={{ scale: 0.98 }}
className={`group cursor-pointer text-left w-full bg-white/80 backdrop-blur-sm rounded-xl shadow-md border border-warm-border p-4 sm:p-5 hover:shadow-lg transition-all ${
whileHover={{ scale: 1.01, y: -1 }}
whileTap={{ scale: 0.99 }}
className={`group cursor-pointer text-left w-full bg-white/80 backdrop-blur-sm rounded-xl shadow-md border border-warm-border p-3.5 sm:p-4.5 hover:shadow-lg transition-all ${
isLeft ? 'sm:mr-auto' : 'sm:ml-auto'
} ${isSpecial ? 'ring-2 ring-warm-gold/30' : ''}`}
style={{ minWidth: 0 }}
@@ -93,24 +93,25 @@ export default function TimelineSection({ entries }: TimelineSectionProps) {
{photos.length > 0 && (
<div className={`grid gap-2 mb-3 ${photos.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}`}>
{photos.slice(0, 2).map((filename, i) => (
<img
key={i}
src={`/api/files/${filename.trim()}?w=600`}
alt=""
className="w-full max-h-60 object-cover rounded-lg"
loading="lazy"
/>
<div key={i} className="overflow-hidden rounded-lg">
<img
src={`/api/files/${filename.trim()}?w=600`}
alt=""
className="w-full max-h-64 object-cover object-[center_15%] group-hover:scale-105 transition-transform duration-700"
loading="lazy"
/>
</div>
))}
</div>
)}
{/* Date */}
<div className={`font-cormorant mb-1 ${isSpecial ? 'text-3xl text-warm-gold' : 'text-2xl text-warm-gold'}`}>
<div className={`font-cormorant leading-none mb-1.5 ${isSpecial ? 'text-3xl text-warm-gold' : 'text-2xl text-warm-gold'}`}>
{formatDate(entry.year, entry.month, entry.day)}
</div>
{/* Title */}
<h3 className={`font-cormorant italic mb-1 group-hover:text-warm-gold transition-colors ${isSpecial ? 'text-xl text-warm-brown font-medium' : 'text-lg text-warm-brown'}`}>
<h3 className={`font-cormorant italic mb-1.5 group-hover:text-warm-gold transition-colors ${isSpecial ? 'text-xl text-warm-brown font-medium' : 'text-lg text-warm-brown'}`}>
{entry.title}
</h3>