From aa0677090b785e106392def5bc6d6bf8f8580ac0 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Thu, 19 Jun 2025 01:59:23 +0100 Subject: [PATCH] feat: enhance photo loading with color placeholders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use dominant color as placeholder background while images load - Add aspect ratio support for proper image dimensions - Improve loading state with smoother transitions - Remove shimmer animation in favor of solid color placeholders 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/lib/components/PhotoItem.svelte | 60 +++++++++++++---------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/lib/components/PhotoItem.svelte b/src/lib/components/PhotoItem.svelte index 87b9624..811b3ec 100644 --- a/src/lib/components/PhotoItem.svelte +++ b/src/lib/components/PhotoItem.svelte @@ -37,6 +37,16 @@ const photo = $derived(isAlbum(item) ? item.coverPhoto : item) const isAlbumItem = $derived(isAlbum(item)) + const placeholderStyle = $derived( + photo.dominantColor + ? `background: ${photo.dominantColor}` + : '' + ) + const aspectRatioStyle = $derived( + photo.aspectRatio + ? `aspect-ratio: ${photo.aspectRatio}` + : '' + )
@@ -46,7 +56,7 @@
-
+
{photo.alt} - {#if !imageLoaded} -
- {/if} +
@@ -68,7 +76,7 @@
{:else} -
+
{photo.alt} - {#if !imageLoaded} -
- {/if} +
{/if} @@ -129,6 +135,8 @@ border-radius: $corner-radius; opacity: 0; transition: opacity 0.4s ease; + position: relative; + z-index: 2; &.loaded { opacity: 1; @@ -177,6 +185,8 @@ border-radius: $corner-radius; opacity: 0; transition: opacity 0.4s ease; + position: relative; + z-index: 2; &.loaded { opacity: 1; @@ -232,34 +242,18 @@ left: 0; right: 0; bottom: 0; - background: linear-gradient(135deg, #f0f0f0 0%, #e0e0e0 50%, #f0f0f0 100%); - background-size: 200% 200%; - animation: shimmer 1.5s ease-in-out infinite; + background: #f0f0f0; // Lighter default grey border-radius: $corner-radius; + opacity: 1; + transition: opacity 0.4s ease; + z-index: 1; + overflow: hidden; - &::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 40px; - height: 40px; - background: rgba(0, 0, 0, 0.1); - border-radius: 50%; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='1.5'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'/%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'/%3E%3Cpolyline points='21,15 16,10 5,21'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center; - background-size: 24px 24px; + + &.loaded { + opacity: 0; + pointer-events: none; } } - @keyframes shimmer { - 0% { - background-position: 200% 0; - } - 100% { - background-position: -200% 0; - } - }