From d2d1e7d362c7cd8c91d6e82acbdbd8a121fdf16a Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Fri, 31 Jul 2026 15:33:15 +0000 Subject: [PATCH] web/settings: reserve layout with skeletons instead of a load spinner Renders each settings tab's structure immediately and swaps same-size skeleton placeholders for the real controls while data loads, so a hard refresh doesn't flash a spinner or shift the bounding box. Adds a shared Skeleton component. --- web/src/lib/components/ui/Skeleton.svelte | 12 ++++++++++++ web/src/lib/components/settings/tabs/KeysTab.svelte | 22 ++++++++++++++++------ web/src/lib/components/settings/tabs/NotificationsTab.svelte | 43 ++++++++++++++++++++++--------------------- web/src/lib/components/settings/tabs/SitesTab.svelte | 15 +++++++++++---- 4 file(s) changed, 61 insertion(s)(+), 31 deletion(s)(-) diff --git a/web/src/lib/components/ui/Skeleton.svelte b/web/src/lib/components/ui/Skeleton.svelte new file mode 100644 --- /dev/null +++ b/web/src/lib/components/ui/Skeleton.svelte @@ -0,0 +1,12 @@ + + + diff --git a/web/src/lib/components/settings/tabs/KeysTab.svelte b/web/src/lib/components/settings/tabs/KeysTab.svelte --- a/web/src/lib/components/settings/tabs/KeysTab.svelte +++ b/web/src/lib/components/settings/tabs/KeysTab.svelte @@ -8,7 +8,7 @@ type PublicKeyRecord } from "$lib/api/settings"; import Button from "$lib/components/ui/Button.svelte"; - import Spinner from "$lib/components/ui/Spinner.svelte"; + import Skeleton from "$lib/components/ui/Skeleton.svelte"; import ErrorAlert from "$lib/components/ui/Error.svelte"; import SettingsEmpty from "../SettingsEmpty.svelte"; import TimeAgo from "$lib/components/ui/TimeAgo.svelte"; @@ -91,11 +91,21 @@ {#if loaded.loading} -
- Loading… -
+ + + {#each [0, 1] as row (row)} +
+
+ +
+ + +
+
+ +
+ {/each} +
{:else if loaded.data?.keys.length === 0} {:else if loaded.data} diff --git a/web/src/lib/components/settings/tabs/NotificationsTab.svelte b/web/src/lib/components/settings/tabs/NotificationsTab.svelte --- a/web/src/lib/components/settings/tabs/NotificationsTab.svelte +++ b/web/src/lib/components/settings/tabs/NotificationsTab.svelte @@ -11,7 +11,7 @@ } from "$lib/api/notifications"; import Button from "$lib/components/ui/Button.svelte"; import Toggle from "$lib/components/ui/Toggle.svelte"; - import Spinner from "$lib/components/ui/Spinner.svelte"; + import Skeleton from "$lib/components/ui/Skeleton.svelte"; import ErrorAlert from "$lib/components/ui/Error.svelte"; import SettingsHeader from "../SettingsHeader.svelte"; import SettingsList from "../SettingsList.svelte"; @@ -158,24 +158,25 @@ -{#if loaded.loading} -
- Loading… -
-{:else} - - {#each prefs as pref (pref.key)} - {@const Glyph = pref.icon} -
-
- - - {pref.description} -
- + + + {#each prefs as pref (pref.key)} + {@const Glyph = pref.icon} +
+
+ + + {pref.description}
- {/each} - -{/if} + {#if loaded.loading} + + {:else} + + {/if} +
+ {/each} +
diff --git a/web/src/lib/components/settings/tabs/SitesTab.svelte b/web/src/lib/components/settings/tabs/SitesTab.svelte --- a/web/src/lib/components/settings/tabs/SitesTab.svelte +++ b/web/src/lib/components/settings/tabs/SitesTab.svelte @@ -7,8 +7,8 @@ import Button from "$lib/components/ui/Button.svelte"; import Input from "$lib/components/ui/Input.svelte"; import Tag from "$lib/components/ui/Tag.svelte"; - import Spinner from "$lib/components/ui/Spinner.svelte"; import ErrorAlert from "$lib/components/ui/Error.svelte"; + import Skeleton from "$lib/components/ui/Skeleton.svelte"; import SettingsEmpty from "../SettingsEmpty.svelte"; import SettingsHeader from "../SettingsHeader.svelte"; import SettingsToolbar from "../SettingsToolbar.svelte"; @@ -99,9 +99,16 @@ {/if} {#if loaded.loading} -
- Loading… -
+ + +
+
+ + +
+ +
+
{:else if loaded.data} -- tangled.sh