feat!: add ability to set light and dark mode logo

This commit is contained in:
Elias Schneider
2024-10-03 11:27:31 +02:00
parent 9e94a436cc
commit be45eed125
14 changed files with 146 additions and 55 deletions

View File

@@ -97,16 +97,4 @@
font-weight: 700;
src: url('/fonts/PlayfairDisplay-Bold.woff') format('woff');
}
}
@layer components {
.application-images-grid {
@apply flex flex-wrap justify-between gap-x-5 gap-y-8;
}
@media (max-width: 1127px) {
.application-images-grid {
justify-content: flex-start;
@apply gap-x-20;
}
}
}
}

View File

@@ -1 +1,10 @@
<img class={$$restProps.class} src="/api/application-configuration/logo" alt="Logo" />
<script lang="ts">
import { mode } from 'mode-watcher';
import type { HTMLAttributes } from 'svelte/elements';
let { ...props }: HTMLAttributes<HTMLImageElement> = $props();
const isDarkMode = $derived($mode === 'dark');
</script>
<img {...props} src="/api/application-configuration/logo?light={!isDarkMode}" alt="Logo" />

View File

@@ -1,7 +1,4 @@
import type {
AllAppConfig,
AppConfigRawResponse
} from '$lib/types/application-configuration';
import type { AllAppConfig, AppConfigRawResponse } from '$lib/types/application-configuration';
import APIService from './api-service';
export default class AppConfigService extends APIService {
@@ -33,11 +30,13 @@ export default class AppConfigService extends APIService {
await this.api.put(`/application-configuration/favicon`, formData);
}
async updateLogo(logo: File) {
async updateLogo(logo: File, light = true) {
const formData = new FormData();
formData.append('file', logo!);
await this.api.put(`/application-configuration/logo`, formData);
await this.api.put(`/application-configuration/logo`, formData, {
params: { light }
});
}
async updateBackgroundImage(backgroundImage: File) {

View File

@@ -28,17 +28,19 @@
}
async function updateImages(
logo: File | null,
logoLight: File | null,
logoDark: File | null,
backgroundImage: File | null,
favicon: File | null
) {
const faviconPromise = favicon ? appConfigService.updateFavicon(favicon) : Promise.resolve();
const logoPromise = logo ? appConfigService.updateLogo(logo) : Promise.resolve();
const lightLogoPromise = logoLight ? appConfigService.updateLogo(logoLight, true) : Promise.resolve();
const darkLogoPromise = logoDark ? appConfigService.updateLogo(logoDark, false) : Promise.resolve();
const backgroundImagePromise = backgroundImage
? appConfigService.updateBackgroundImage(backgroundImage)
: Promise.resolve();
await Promise.all([logoPromise, backgroundImagePromise, faviconPromise])
await Promise.all([lightLogoPromise, darkLogoPromise, backgroundImagePromise, faviconPromise])
.then(() => toast.success('Images updated successfully'))
.catch(axiosErrorToast);
}

View File

@@ -11,6 +11,7 @@
image = $bindable(),
imageURL,
accept = 'image/png, image/jpeg, image/svg+xml',
forceColorScheme,
...restProps
}: HTMLAttributes<HTMLDivElement> & {
id: string;
@@ -18,6 +19,7 @@
label: string;
image: File | null;
imageURL: string;
forceColorScheme?: 'light' | 'dark';
accept?: string;
} = $props();
@@ -37,10 +39,16 @@
}
</script>
<div {...restProps}>
<Label for={id}>{label}</Label>
<div class="flex flex-col items-start md:flex-row md:items-center" {...restProps}>
<Label class="w-52" for={id}>{label}</Label>
<FileInput {id} variant="secondary" {accept} onchange={onImageChange}>
<div class="bg-muted group relative flex items-center rounded">
<div
class="{forceColorScheme === 'light'
? 'bg-[#F1F1F5]'
: forceColorScheme === 'dark'
? 'bg-[#27272A]'
: 'bg-muted'} group relative flex items-center rounded"
>
<img
class={cn(
'h-full w-full rounded object-cover p-3 transition-opacity duration-200 group-hover:opacity-10',

View File

@@ -5,15 +5,21 @@
let {
callback
}: {
callback: (logo: File | null, backgroundImage: File | null, favicon: File | null) => void;
callback: (
logoLight: File | null,
logoDark: File | null,
backgroundImage: File | null,
favicon: File | null
) => void;
} = $props();
let logo = $state<File | null>(null);
let logoLight = $state<File | null>(null);
let logoDark = $state<File | null>(null);
let backgroundImage = $state<File | null>(null);
let favicon = $state<File | null>(null);
</script>
<div class="application-images-grid">
<div class="flex flex-col gap-8">
<ApplicationImage
id="favicon"
imageClass="h-14 w-14 p-2"
@@ -23,15 +29,23 @@
accept="image/x-icon"
/>
<ApplicationImage
id="logo"
id="logo-light"
imageClass="h-32 w-32"
label="Logo"
bind:image={logo}
imageURL="/api/application-configuration/logo"
label="Light Mode Logo"
bind:image={logoLight}
imageURL="/api/application-configuration/logo?light=true"
forceColorScheme="light"
/>
<ApplicationImage
id="logo-dark"
imageClass="h-32 w-32"
label="Dark Mode Logo"
bind:image={logoDark}
imageURL="/api/application-configuration/logo?light=false"
forceColorScheme="dark"
/>
<ApplicationImage
id="background-image"
class="basis-full lg:basis-auto"
imageClass="h-[350px] max-w-[500px]"
label="Background Image"
bind:image={backgroundImage}
@@ -39,5 +53,7 @@
/>
</div>
<div class="flex justify-end">
<Button class="mt-5" onclick={() => callback(logo, backgroundImage, favicon)}>Save</Button>
<Button class="mt-5" onclick={() => callback(logoLight, logoDark, backgroundImage, favicon)}
>Save</Button
>
</div>

View File

@@ -52,7 +52,8 @@ test('Update application images', async ({ page }) => {
await page.goto('/settings/admin/application-configuration');
await page.getByLabel('Favicon').setInputFiles('tests/assets/w3-schools-favicon.ico');
await page.getByLabel('Logo').setInputFiles('tests/assets/pingvin-share-logo.png');
await page.getByLabel('Light Mode Logo').setInputFiles('tests/assets/pingvin-share-logo.png');
await page.getByLabel('Dark Mode Logo').setInputFiles('tests/assets/nextcloud-logo.png');
await page.getByLabel('Background Image').setInputFiles('tests/assets/clouds.jpg');
await page.getByRole('button', { name: 'Save' }).nth(1).click();
@@ -62,9 +63,11 @@ test('Update application images', async ({ page }) => {
.get('/api/application-configuration/favicon')
.then((res) => expect.soft(res.status()).toBe(200));
await page.request
.get('/api/application-configuration/logo')
.get('/api/application-configuration/logo?light=true')
.then((res) => expect.soft(res.status()).toBe(200));
await page.request
.get('/api/application-configuration/logo?light=false')
.then((res) => expect.soft(res.status()).toBe(200));
await page.request
.get('/api/application-configuration/background-image')
.then((res) => expect.soft(res.status()).toBe(200));