WIP: My personal website
0

Configure Feed

Select the types of activity you want to include in your feed.

lazyload with skeleton

+98 -24
+5 -6
src/lib/components/BookHistory.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import type { CurrentlyReading, FinishedBook } from '$lib/types'; 4 5 5 6 let { ··· 27 28 <div class="card mx-auto mt-10 max-w-xl bg-base-100 shadow-sm"> 28 29 <div class="card-body flex-row items-start gap-5"> 29 30 {#if currentlyReading.cover} 30 - <img 31 - class="h-40 w-28 flex-none rounded-md object-cover shadow-sm" 31 + <LazyLoadingImg 32 + class="h-40 w-28 flex-none rounded-md shadow-sm" 32 33 src={currentlyReading.cover} 33 34 alt={currentlyReading.title} 34 - loading="lazy" 35 35 /> 36 36 {/if} 37 37 <div class="flex flex-col"> ··· 64 64 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 65 65 <div class="card-body flex-row items-start gap-4"> 66 66 {#if book.cover} 67 - <img 68 - class="h-32 w-22 flex-none rounded-md object-cover shadow-sm" 67 + <LazyLoadingImg 68 + class="h-32 w-22 flex-none rounded-md shadow-sm" 69 69 src={book.cover} 70 70 alt={book.title} 71 - loading="lazy" 72 71 /> 73 72 {/if} 74 73 <div class="flex min-w-0 flex-col">
+5 -6
src/lib/components/FreeTime.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import type { CurrentlyReading, NowPlaying } from '$lib/types'; 4 5 5 6 let { ··· 25 26 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 26 27 <div class="card-body flex-row items-start gap-5"> 27 28 {#if currentlyReading.cover} 28 - <img 29 - class="h-40 w-28 flex-none rounded-md object-cover shadow-sm" 29 + <LazyLoadingImg 30 + class="h-40 w-28 flex-none rounded-md shadow-sm" 30 31 src={currentlyReading.cover} 31 32 alt={currentlyReading.title} 32 - loading="lazy" 33 33 /> 34 34 {/if} 35 35 <div class="flex flex-col"> ··· 58 58 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 59 59 <div class="card-body flex-row items-start gap-5"> 60 60 {#if nowPlaying.coverArt && !coverArtFailed} 61 - <img 62 - class="h-32 w-32 flex-none rounded-md object-cover shadow-sm" 61 + <LazyLoadingImg 62 + class="h-32 w-32 flex-none rounded-md shadow-sm" 63 63 src={nowPlaying.coverArt} 64 64 alt={nowPlaying.releaseName ?? nowPlaying.trackName} 65 65 onerror={() => (coverArtFailed = true)} 66 - loading="lazy" 67 66 /> 68 67 {:else} 69 68 <div
+3 -1
src/lib/components/Hero.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import me from '$lib/assets/me.webp'; 4 5 import mePumpkin from '$lib/assets/me_pumpkin.webp'; 5 6 import GitHubButton from './buttons/GitHubButton.svelte'; ··· 8 9 9 10 <div id="home" class="hero flex justify-center py-10" use:reveal> 10 11 <div class="hero-content flex-col lg:flex-row-reverse"> 11 - <img 12 + <LazyLoadingImg 12 13 src={me} 13 14 alt="" 14 15 class="max-w-xs rounded-t-[14rem] rounded-b-box shadow-2xl outline outline-base-content/5 md:max-w-md" 16 + imgClass="block w-full" 15 17 /> 16 18 <div class="text-center lg:text-start"> 17 19 <!-- <span class="badge badge-outline badge-lg">Award winning digital agency</span> -->
+53
src/lib/components/LazyLoadingImg.svelte
··· 1 + <script lang="ts"> 2 + import type { HTMLImgAttributes } from 'svelte/elements'; 3 + import type { Attachment } from 'svelte/attachments'; 4 + 5 + let { 6 + src, 7 + alt, 8 + class: className = '', 9 + imgClass = 'h-full w-full object-cover', 10 + onload, 11 + onerror, 12 + ...rest 13 + }: { 14 + src: string; 15 + alt: string; 16 + /** Classes for the wrapper box (sizing, rounding, ring, shadow, flex-none, etc.) */ 17 + class?: string; 18 + /** Classes for the inner <img> (object-fit, padding). Defaults to fill+cover. */ 19 + imgClass?: string; 20 + onload?: (e: Event) => void; 21 + onerror?: (e: Event) => void; 22 + } & HTMLImgAttributes = $props(); 23 + 24 + let loaded = $state(false); 25 + 26 + // After SSR/hydration a cached image can already be complete before our 27 + // onload handler is attached, so reconcile once on mount. 28 + const reconcileCached: Attachment<HTMLImageElement> = (node) => { 29 + if (node.complete && node.naturalWidth > 0) loaded = true; 30 + }; 31 + </script> 32 + 33 + <div class={['relative overflow-hidden', className]}> 34 + {#if !loaded} 35 + <div class="absolute inset-0 skeleton"></div> 36 + {/if} 37 + <img 38 + {@attach reconcileCached} 39 + {src} 40 + {alt} 41 + class={imgClass} 42 + loading="lazy" 43 + {...rest} 44 + onload={(e) => { 45 + loaded = true; 46 + onload?.(e); 47 + }} 48 + onerror={(e) => { 49 + loaded = true; 50 + onerror?.(e); 51 + }} 52 + /> 53 + </div>
+3 -3
src/lib/components/MusicHistory.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import type { RecentPlay } from '$lib/types'; 4 5 5 6 let { recentPlays }: { recentPlays: RecentPlay[] } = $props(); ··· 50 51 class="card flex-row items-center gap-4 bg-base-100 p-3 shadow-sm transition duration-300 hover:-translate-y-0.5" 51 52 > 52 53 {#if play.coverArt && !coverFailed[i]} 53 - <img 54 - class="h-16 w-16 flex-none rounded-md object-cover shadow-sm" 54 + <LazyLoadingImg 55 + class="h-16 w-16 flex-none rounded-md shadow-sm" 55 56 src={play.coverArt} 56 57 alt={play.releaseName ?? play.trackName} 57 58 onerror={() => (coverFailed[i] = true)} 58 - loading="lazy" 59 59 /> 60 60 {:else} 61 61 <div
+15 -2
src/lib/components/NavBar.svelte
··· 1 1 <script lang="ts"> 2 2 import PumpkinHead from '$lib/assets/pumpkin_head.png'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 4 + import { page } from '$app/stores'; // 1. Import the page store 3 5 4 6 type NavItem = { 5 7 name: string; ··· 44 46 currentHeadSize = headSizes[(index + 1) % headSizes.length]; 45 47 }; 46 48 47 - let active = $state(navigation[0].href); 49 + let active = $derived.by(() => { 50 + // if ($page.url.pathname; 51 + const path = `${$page.url.pathname}${$page.url.hash}`; 52 + let test = path === '/' || path === '' ? '/#home' : path; 53 + console.log(test); 54 + return test; 55 + }); 48 56 49 57 function onActivate(href: string | undefined) { 50 58 if (href) active = href; ··· 194 202 onclick={increaseHeadSize} 195 203 class={['rounded-full', 'cursor-pointer', currentHeadSize]} 196 204 > 197 - <img alt="A cartoon Jack-o'-lantern " src={PumpkinHead} /> 205 + <LazyLoadingImg 206 + class="w-full" 207 + imgClass="block w-full" 208 + alt="A cartoon Jack-o'-lantern " 209 + src={PumpkinHead} 210 + /> 198 211 </button> 199 212 </div> 200 213 <!-- <ThemeToggle /> -->
+2 -1
src/lib/components/OpenSourceProjects.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import moover from '$lib/assets/projects/moover.webp'; 4 5 import npmx from '$lib/assets/projects/npmx.png'; 5 6 import gatekeeper from '$lib/assets/projects/gatekeeper.jpg'; ··· 92 93 {#each visibleProjects as item (item.name)} 93 94 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 94 95 <figure> 95 - <img class="h-48 w-full object-cover" src={item.image} alt={item.name} loading="lazy" /> 96 + <LazyLoadingImg class="h-48 w-full" src={item.image} alt={item.name} /> 96 97 </figure> 97 98 <div class="card-body"> 98 99 <h2 class="card-title font-urbanist text-2xl font-black">{item.name}</h2>
+7 -1
src/lib/components/Services.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 4 5 const services = [ 5 6 { ··· 53 54 <div class="card max-w-2xl shadow-sm transition duration-300 hover:-translate-y-1"> 54 55 <div class="card-body"> 55 56 <div class="h-16 w-16 rounded-full bg-gradient-to-t from-base-300/20 to-base-content/10"> 56 - <img class="p-4" src={item.icon} alt={item.name} loading="lazy" /> 57 + <LazyLoadingImg 58 + class="h-full w-full rounded-full" 59 + imgClass="h-full w-full object-contain p-4" 60 + src={item.icon} 61 + alt={item.name} 62 + /> 57 63 </div> 58 64 <h2 class="card-title font-urbanist text-3xl font-black">{item.name}</h2> 59 65 <p class="text-md font-urbanist font-medium opacity-60">{item.description}</p>
+3 -3
src/lib/components/Sponsors.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import type { Sponsor } from '$lib/types'; 4 5 5 6 let { sponsors }: { sponsors: Sponsor[] } = $props(); ··· 22 23 rel="noopener noreferrer" 23 24 title={sponsor.name} 24 25 > 25 - <img 26 - class="h-16 w-16 rounded-full object-cover ring-2 ring-base-content/10 group-hover:ring-primary md:h-20 md:w-20" 26 + <LazyLoadingImg 27 + class="h-16 w-16 rounded-full ring-2 ring-base-content/10 group-hover:ring-primary md:h-20 md:w-20" 27 28 src={sponsor.avatarUrl} 28 29 alt={sponsor.name} 29 - loading="lazy" 30 30 /> 31 31 <span class="max-w-20 truncate text-center font-urbanist text-sm font-medium opacity-60"> 32 32 {sponsor.name}
+2 -1
src/lib/components/Writing.svelte
··· 1 1 <script lang="ts"> 2 2 import { reveal } from '$lib/actions/reveal'; 3 + import LazyLoadingImg from './LazyLoadingImg.svelte'; 3 4 import type { Publication } from '$lib/types'; 4 5 5 6 let { publications }: { publications: Publication[] } = $props(); ··· 24 25 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 25 26 {#if item.image} 26 27 <figure> 27 - <img class="h-48 w-full object-cover" src={item.image} alt={item.name} loading="lazy" /> 28 + <LazyLoadingImg class="h-48 w-full" src={item.image} alt={item.name} /> 28 29 </figure> 29 30 {/if} 30 31 <div class="card-body">