diff --git a/src/lib/components/AtMentions.svelte b/src/lib/components/AtMentions.svelte
index a73389d..cb96068 100644
--- a/src/lib/components/AtMentions.svelte
+++ b/src/lib/components/AtMentions.svelte
@@ -1,5 +1,6 @@
@@ -32,5 +36,7 @@
data-aturi={aturi || undefined}
variant={variant}
>
+ {:else if !failed}
+
{/if}
diff --git a/src/lib/components/LoadingSkeleton.svelte b/src/lib/components/LoadingSkeleton.svelte
index ab4de92..33fd291 100644
--- a/src/lib/components/LoadingSkeleton.svelte
+++ b/src/lib/components/LoadingSkeleton.svelte
@@ -7,17 +7,24 @@
*/
interface Props {
count?: number;
+ label?: string;
}
- let { count = 1 }: Props = $props();
+ let { count = 1, label = "Loading content" }: Props = $props();
-{#each Array(count) as _}
-
-{/each}
+
+ {#each Array(count) as _}
+
+ {/each}
+
diff --git a/src/lib/components/leaflet/LeafletEmbed.svelte b/src/lib/components/leaflet/LeafletEmbed.svelte
index 808e874..1f80754 100644
--- a/src/lib/components/leaflet/LeafletEmbed.svelte
+++ b/src/lib/components/leaflet/LeafletEmbed.svelte
@@ -4,6 +4,8 @@
* Supports explicit height or an aspect-ratio based sizing with
* a 16:9 fallback for unmeasured embeds.
*/
+ import LoadingSkeleton from "$lib/components/LoadingSkeleton.svelte";
+
let { url, height, aspectRatio }: {
url: string;
height?: number;
@@ -15,9 +17,15 @@
? `${aspectRatio.width} / ${aspectRatio.height}`
: "16 / 9"
);
+ let loaded = $state(false);
-
+
+ {#if !loaded}
+
+
+
+ {/if}
diff --git a/src/lib/styles/leaflet-blocks.css b/src/lib/styles/leaflet-blocks.css
index f92a366..5e552ea 100644
--- a/src/lib/styles/leaflet-blocks.css
+++ b/src/lib/styles/leaflet-blocks.css
@@ -252,6 +252,7 @@
/* ── Embeds ─────────────────────────────────────────────────── */
.leaflet-embed {
+ position: relative;
margin: var(--space-md) 0;
border-radius: var(--radius-md);
overflow: hidden;
@@ -259,10 +260,21 @@
}
.leaflet-embed iframe {
+ display: block;
width: 100%;
border: none;
}
+ .leaflet-embed-loading {
+ position: absolute;
+ inset: 0;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ padding: var(--space-md);
+ background: var(--surface-raised);
+ }
+
/* ── Website card ───────────────────────────────────────────── */
.leaflet-website-card {
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 544be50..dfce9c2 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -20,20 +20,32 @@
let githubUsername = $state('ewanc26');
let publications = $state
(null);
let links = $state(null);
+ let homeLoading = $state(true);
let pinnedProjects = $derived(githubProjects ? githubProjects.slice(0, 6) : []);
onMount(async () => {
- // Fetch remaining data in parallel
- fetch('/api/home').then(r => r.json()).then(d => {
- kibunStatus = d.kibunStatus;
- musicStatus = d.musicStatus;
- posts = d.posts;
- githubProjects = d.githubProjects;
- githubUsername = d.githubUsername;
- publications = d.publications;
- links = d.links;
- }).catch(e => console.error("Failed to load home data", e));
+ try {
+ const response = await fetch('/api/home');
+ if (!response.ok) throw new Error(`Home API returned ${response.status}`);
+
+ const d = await response.json();
+ kibunStatus = d.kibunStatus;
+ musicStatus = d.musicStatus;
+ posts = d.posts;
+ githubProjects = d.githubProjects;
+ githubUsername = d.githubUsername ?? githubUsername;
+ publications = d.publications;
+ links = d.links;
+ } catch (e) {
+ console.error("Failed to load home data", e);
+ posts = [];
+ githubProjects = [];
+ publications = [];
+ links = { cards: [] };
+ } finally {
+ homeLoading = false;
+ }
});
function getBlogUrl(post: any) {
@@ -64,7 +76,11 @@
- {#if kibunStatus !== null || musicStatus !== null}
+ {#if homeLoading}
+
+
+
+ {:else if kibunStatus !== null || musicStatus !== null}
{#if kibunStatus}
@@ -92,13 +108,13 @@
{/if}
-
+
{#if posts === null}
-
+
{:else if Array.isArray(posts) && posts.length > 0}
{#each posts.filter(p => p.publicationRkey === PUBLIC_LEAFLET_BLOG_PUBLICATION).slice(0, 5) as post, i}
@@ -123,13 +139,13 @@
-
+
Projects
Pinned on GitHub
{#if githubProjects === null}
-
+
{:else if githubProjects && githubProjects.length > 0}
{#each pinnedProjects as project}
@@ -175,13 +191,13 @@
-
+
Publications
Longer-running collections
{#if publications === null}
-
+
{:else if publications && publications.length > 0}
{#each publications.filter((p: any) => p.rkey !== PUBLIC_LEAFLET_BLOG_PUBLICATION) as pub}
@@ -202,13 +218,13 @@
-
+
Elsewhere
Other places to find me
{#if links === null}
-
+
{:else if links && links.cards && links.cards.length > 0}
{#each links.cards.slice(0, 8) as link}
diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte
index 3577696..1e8b7e4 100644
--- a/src/routes/about/+page.svelte
+++ b/src/routes/about/+page.svelte
@@ -76,7 +76,7 @@
{profile.pronouns}
{/if}
{#await data.lazy.sifaProfile}
-
+
{:then sifaProfile}
{#if sifaProfile}
{sifaProfile.headline}
@@ -93,7 +93,7 @@
Skills
{#await data.lazy.sifaSkills}
-
+
{:then sifaSkills}
{#if sifaSkills && sifaSkills.length > 0}
{#each groupSkillsByCategory(sifaSkills) as [category, skills]}
@@ -119,7 +119,7 @@
Education
{#await data.lazy.sifaEducation}
-
+
{:then sifaEducation}
{#if sifaEducation && sifaEducation.length > 0}
@@ -148,7 +148,7 @@
Projects
{#await data.lazy.githubProjects}
-
+
{:then githubProjects}
{#if githubProjects && githubProjects.length > 0}