feat: add animated logo as default logo

This commit is contained in:
Elias Schneider
2026-08-08 20:50:37 +02:00
parent 987d1a8b59
commit 0c9a03e519
16 changed files with 367 additions and 87 deletions
@@ -37,7 +37,7 @@
? 'translate-x-[108px]'
: ''}"
>
<Logo class="size-10" />
<Logo class="size-10" animate={false} />
</div>
<ConnectArrow
@@ -36,8 +36,8 @@
}
async function updateImages(
logoLight: File | undefined,
logoDark: File | undefined,
logoLight: File | null | undefined,
logoDark: File | null | undefined,
logoEmail: File | undefined,
defaultProfilePicture: File | null | undefined,
backgroundImage: File | null | undefined,
@@ -45,13 +45,19 @@
) {
const faviconPromise = favicon ? appConfigService.updateFavicon(favicon) : Promise.resolve();
const lightLogoPromise = logoLight
? appConfigService.updateLogo(logoLight, true)
: Promise.resolve();
const lightLogoPromise =
logoLight === null
? appConfigService.deleteLogo(true)
: logoLight
? appConfigService.updateLogo(logoLight, true)
: Promise.resolve();
const darkLogoPromise = logoDark
? appConfigService.updateLogo(logoDark, false)
: Promise.resolve();
const darkLogoPromise =
logoDark === null
? appConfigService.deleteLogo(false)
: logoDark
? appConfigService.updateLogo(logoDark, false)
: Promise.resolve();
const emailLogoPromise = logoEmail
? appConfigService.updateEmailLogo(logoEmail)
@@ -2,8 +2,10 @@
import FileInput from '$lib/components/form/file-input.svelte';
import { Button } from '$lib/components/ui/button';
import * as Field from '$lib/components/ui/field';
import { m } from '$lib/paraglide/messages';
import { cn } from '$lib/utils/style';
import { LucideImageOff, LucideUpload, LucideX } from '@lucide/svelte';
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
let {
@@ -12,6 +14,7 @@
label,
image = $bindable(),
imageURL,
fallback,
accept = 'image/png, image/jpeg, image/svg+xml, image/gif, image/webp, image/avif, image/heic',
forceColorScheme,
isResetable = false,
@@ -23,6 +26,7 @@
label: string;
image: File | null | undefined;
imageURL: string;
fallback?: Snippet;
forceColorScheme?: 'light' | 'dark';
accept?: string;
isResetable?: boolean;
@@ -70,7 +74,11 @@
imageClass
)}
>
<LucideImageOff class="text-muted-foreground" />
{#if fallback}
{@render fallback()}
{:else}
<LucideImageOff class="text-muted-foreground" />
{/if}
</div>
{:else}
<img
@@ -97,6 +105,7 @@
{#if isResetable && isImageSet}
<Button
size="icon"
aria-label={`${m.reset_to_default()} ${label}`}
onclick={(e) => {
e.stopPropagation();
onReset();
@@ -1,4 +1,5 @@
<script lang="ts">
import Logo from '$lib/components/logo.svelte';
import Button from '$lib/components/ui/button/button.svelte';
import { m } from '$lib/paraglide/messages';
import {
@@ -13,8 +14,8 @@
callback
}: {
callback: (
logoLight: File | undefined,
logoDark: File | undefined,
logoLight: File | null | undefined,
logoDark: File | null | undefined,
logoEmail: File | undefined,
defaultProfilePicture: File | null | undefined,
backgroundImage: File | null | undefined,
@@ -22,8 +23,8 @@
) => void;
} = $props();
let logoLight = $state<File | undefined>();
let logoDark = $state<File | undefined>();
let logoLight = $state<File | null | undefined>();
let logoDark = $state<File | null | undefined>();
let logoEmail = $state<File | undefined>();
let defaultProfilePicture = $state<File | null | undefined>();
let backgroundImage = $state<File | null | undefined>();
@@ -31,8 +32,18 @@
let defaultProfilePictureSet = $state(true);
let backgroundImageSet = $state(true);
let logoLightSet = $state(true);
let logoDarkSet = $state(true);
</script>
{#snippet lightLogoFallback()}
<Logo defaultOnly colorScheme="light" class="size-full" />
{/snippet}
{#snippet darkLogoFallback()}
<Logo defaultOnly colorScheme="dark" class="size-full" />
{/snippet}
<div class="flex flex-col gap-8">
<ApplicationImage
id="favicon"
@@ -48,7 +59,10 @@
label={m.light_mode_logo()}
bind:image={logoLight}
imageURL={cachedApplicationLogo.getUrl(true)}
fallback={lightLogoFallback}
forceColorScheme="light"
isResetable
bind:isImageSet={logoLightSet}
/>
<ApplicationImage
id="logo-dark"
@@ -56,7 +70,10 @@
label={m.dark_mode_logo()}
bind:image={logoDark}
imageURL={cachedApplicationLogo.getUrl(false)}
fallback={darkLogoFallback}
forceColorScheme="dark"
isResetable
bind:isImageSet={logoDarkSet}
/>
<ApplicationImage
id="logo-email"
@@ -1,6 +1,7 @@
<script lang="ts">
import { goto } from '$app/navigation';
import ImageBox from '$lib/components/image-box.svelte';
import Logo from '$lib/components/logo.svelte';
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
@@ -8,7 +9,7 @@
import { m } from '$lib/paraglide/messages';
import userStore from '$lib/stores/user-store';
import type { AccessibleOidcClient, OidcClientMetaData } from '$lib/types/oidc.type';
import { cachedApplicationLogo, cachedOidcClientLogo } from '$lib/utils/cached-image-util';
import { cachedOidcClientLogo } from '$lib/utils/cached-image-util';
import { encodeClientIdParam } from '$lib/utils/client-id-util';
import {
LucideBan,
@@ -38,13 +39,17 @@
<Card.Content class=" p-0">
<div class="flex gap-3">
<div class="aspect-square h-[56px]">
<ImageBox
class="size-14"
src={client.hasLogo
? cachedOidcClientLogo.getUrl(client.id, isLightMode)
: cachedApplicationLogo.getUrl(isLightMode)}
alt={m.name_logo({ name: client.name })}
/>
{#if client.hasLogo}
<ImageBox
class="size-14"
src={cachedOidcClientLogo.getUrl(client.id, isLightMode)}
alt={m.name_logo({ name: client.name })}
/>
{:else}
<div class="bg-muted flex size-14 items-center justify-center rounded-2xl p-3">
<Logo class="size-full" alt={m.name_logo({ name: client.name })} animate={false} />
</div>
{/if}
</div>
<div class="flex w-full justify-between gap-3">
<div class="h-20">