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:
@@ -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') {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user