Feature: add avatar with offline support

This commit is contained in:
Pieter Vander Vennet 2025-08-05 23:20:14 +02:00
parent 06aa8a3406
commit f671cd342f
6 changed files with 33 additions and 10 deletions

View file

@ -18,6 +18,7 @@
"allFilteredAway": "No feature in view meets all filters", "allFilteredAway": "No feature in view meets all filters",
"loadingData": "Loading data…", "loadingData": "Loading data…",
"noData": "There are no relevant features in the current view", "noData": "There are no relevant features in the current view",
"noDataOffline": "No data is loaded and you are offline",
"ready": "Done!", "ready": "Done!",
"retrying": "Loading data failed. Trying again in {count} seconds…", "retrying": "Loading data failed. Trying again in {count} seconds…",
"zoomIn": "Zoom in to view or edit the data" "zoomIn": "Zoom in to view or edit the data"
@ -959,4 +960,4 @@
"startsWithQ": "A wikidata identifier starts with Q and is followed by a number" "startsWithQ": "A wikidata identifier starts with Q and is followed by a number"
} }
} }
} }

View file

@ -204,7 +204,7 @@
</div> </div>
</div> </div>
<LoginToggle {state}> <LoginToggle {state} offline>
{#if $recentThemes.length > 2} {#if $recentThemes.length > 2}
<div class="my-4"> <div class="my-4">
<h2> <h2>

20
src/UI/Base/Avatar.svelte Normal file
View file

@ -0,0 +1,20 @@
<script lang="ts">
import type UserDetails from "../../Logic/Osm/OsmConnection"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import UserCircle from "@rgossiaux/svelte-heroicons/solid/UserCircle"
import { IsOnline } from "../../Logic/Web/IsOnline"
/**
* USer icon, if available
*/
export let userdetails: Store<UserDetails>
let loaded = new UIEventSource(false)
let isOnline = IsOnline.isOnline
</script>
{#if !$userdetails.img || !($loaded || $isOnline)}
<UserCircle class="h-14 w-14" color="gray" />
{:else}
<img alt="avatar" src={$userdetails.img} class="h-12 w-12 rounded-full" on:load={() => {loaded.set(true)}} />
{/if}

View file

@ -63,6 +63,7 @@
import OfflineManagement from "./OfflineManagement.svelte" import OfflineManagement from "./OfflineManagement.svelte"
import { GlobeEuropeAfrica } from "@babeard/svelte-heroicons/solid/GlobeEuropeAfrica" import { GlobeEuropeAfrica } from "@babeard/svelte-heroicons/solid/GlobeEuropeAfrica"
import { onDestroy } from "svelte" import { onDestroy } from "svelte"
import Avatar from "../Base/Avatar.svelte"
export let state: { export let state: {
favourites: FavouritesFeatureSource favourites: FavouritesFeatureSource
@ -134,11 +135,7 @@
<LoginToggle {state} offline> <LoginToggle {state} offline>
<LoginButton osmConnection={state.osmConnection} slot="not-logged-in" /> <LoginButton osmConnection={state.osmConnection} slot="not-logged-in" />
<div class="flex items-center gap-x-4 w-full m-2"> <div class="flex items-center gap-x-4 w-full m-2">
{#if $userdetails.img} <Avatar userdetails={state.osmConnection.userDetails} />
<img alt="avatar" src={$userdetails.img} class="h-12 w-12 rounded-full" />
{:else}
<UserCircle class="h-14 w-14" color="gray"/>
{/if}
<div class="flex flex-col w-full gap-y-2"> <div class="flex flex-col w-full gap-y-2">
<b>{$userdetails?.name ?? '<Username>'}</b> <b>{$userdetails?.name ?? '<Username>'}</b>

View file

@ -3,6 +3,7 @@
import Translations from "../i18n/Translations" import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte" import Tr from "../Base/Tr.svelte"
import Loading from "../Base/Loading.svelte" import Loading from "../Base/Loading.svelte"
import { IsOnline } from "../../Logic/Web/IsOnline"
export let state: ThemeViewState export let state: ThemeViewState
/** /**
@ -14,6 +15,7 @@
let dataIsLoading = state.dataIsLoading let dataIsLoading = state.dataIsLoading
let currentState = state.hasDataInView let currentState = state.hasDataInView
let online = IsOnline.isOnline
const t = Translations.t.centerMessage const t = Translations.t.centerMessage
const showingSearch = state.searchState.showSearchDrawer const showingSearch = state.searchState.showSearchDrawer
</script> </script>
@ -34,6 +36,10 @@
<Tr t={Translations.t.centerMessage.loadingData} /> <Tr t={Translations.t.centerMessage.loadingData} />
</Loading> </Loading>
</div> </div>
{:else if $currentState === "no-data" && !$online}
<div class="alert w-fit p-4">
<Tr t={t.noDataOffline} />
</div>
{:else if $currentState === "no-data"} {:else if $currentState === "no-data"}
<div class="alert w-fit p-4"> <div class="alert w-fit p-4">
<Tr t={t.noData} /> <Tr t={t.noData} />

View file

@ -3,6 +3,7 @@
import { fade } from "svelte/transition" import { fade } from "svelte/transition"
import { OsmConnection } from "../../Logic/Osm/OsmConnection" import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { onDestroy } from "svelte" import { onDestroy } from "svelte"
import Avatar from "../Base/Avatar.svelte"
let open = false let open = false
export let state: { osmConnection: OsmConnection } export let state: { osmConnection: OsmConnection }
@ -28,9 +29,7 @@
> >
{#if $username !== undefined} {#if $username !== undefined}
<div style="width: max-content" class="flex items-center"> <div style="width: max-content" class="flex items-center">
{#if $userdetails.img} <Avatar {userdetails} />
<img src={$userdetails.img} alt="avatar" class="mr-4 h-10 w-10 rounded-full" />
{/if}
<div> <div>
<div>Welcome back</div> <div>Welcome back</div>
<div class="normal-background" style="width: max-content"> <div class="normal-background" style="width: max-content">